xref: /petsc/src/sys/classes/draw/utils/bars.c (revision 5b6bfdb9644f185dbf5e5a09b808ec241507e1e7)
1 
2 /*
3   Contains the data structure for plotting a bargraph in a window with an axis.
4 */
5 #include <petscdraw.h>                       /*I "petscdraw.h" I*/
6 #include <petsc/private/petscimpl.h>         /*I "petscsys.h" I*/
7 #include <petscviewer.h>                     /*I "petscviewer.h" I*/
8 #include <../src/sys/classes/draw/utils/axisimpl.h>   /* so we can directly modify axis xticks */
9 
10 PetscClassId PETSC_DRAWBAR_CLASSID = 0;
11 
12 struct _p_PetscDrawBar {
13   PETSCHEADER(int);
14   PetscErrorCode (*destroy)(PetscDrawSP);
15   PetscErrorCode (*view)(PetscDrawSP,PetscViewer);
16   PetscDraw      win;
17   PetscDrawAxis  axis;
18   PetscReal      ymin,ymax;
19   int            numBins;
20   PetscReal      *values;
21   int            color;
22   char           **labels;
23   PetscBool      sort;
24   PetscReal      sorttolerance;
25 };
26 
27 #define CHUNKSIZE 100
28 
29 /*@C
30    PetscDrawBarCreate - Creates a bar graph data structure.
31 
32    Collective over PetscDraw
33 
34    Input Parameters:
35 .  draw  - The window where the graph will be made
36 
37    Output Parameters:
38 .  bar - The bar graph context
39 
40    Notes: Call PetscDrawBarSetData() to provide the bins to be plotted and then PetscDrawBarDraw() to display the new plot
41 
42   The difference between a bar chart, PetscDrawBar, and a histogram, PetscDrawHG, is explained here http://stattrek.com/statistics/charts/histogram.aspx?Tutorial=AP
43 
44    The MPI communicator that owns the PetscDraw owns this PetscDrawBar, but the calls to set options and add data are ignored on all processes except the
45    zeroth MPI process in the communicator. All MPI processes in the communicator must call PetscDrawBarDraw() to display the updated graph.
46 
47    Level: intermediate
48 
49    Concepts: bar graph^creating
50 
51 .seealso: PetscDrawLGCreate(), PetscDrawLG, PetscDrawSPCreate(), PetscDrawSP, PetscDrawHGCreate(), PetscDrawHG, PetscDrawBarDestroy(), PetscDrawBarSetData(),
52           PetscDrawBar, PetscDrawBarDraw(), PetscDrawBarSave(), PetscDrawBarSetColor(), PetscDrawBarSort(), PetscDrawBarSetLimits(), PetscDrawBarGetAxis(), PetscDrawAxis,
53           PetscDrawBarGetDraw(), PetscDrawBarSetFromOptions()
54 @*/
55 PetscErrorCode  PetscDrawBarCreate(PetscDraw draw,PetscDrawBar *bar)
56 {
57   PetscDrawBar   h;
58   PetscErrorCode ierr;
59 
60   PetscFunctionBegin;
61   PetscValidHeaderSpecific(draw,PETSC_DRAW_CLASSID,1);
62   PetscValidPointer(bar,2);
63 
64   ierr = PetscHeaderCreate(h,PETSC_DRAWBAR_CLASSID,"DrawBar","Bar Graph","Draw",PetscObjectComm((PetscObject)draw),PetscDrawBarDestroy,NULL);CHKERRQ(ierr);
65   ierr = PetscLogObjectParent((PetscObject)draw,(PetscObject)h);CHKERRQ(ierr);
66 
67   ierr = PetscObjectReference((PetscObject)draw);CHKERRQ(ierr);
68   h->win = draw;
69 
70   h->view        = NULL;
71   h->destroy     = NULL;
72   h->color       = PETSC_DRAW_GREEN;
73   h->ymin        = 0.;  /* if user has not set these then they are determined from the data */
74   h->ymax        = 0.;
75   h->numBins     = 0;
76 
77   ierr = PetscDrawAxisCreate(draw,&h->axis);CHKERRQ(ierr);
78   h->axis->xticks = NULL;
79 
80   *bar = h;
81   PetscFunctionReturn(0);
82 }
83 
84 /*@C
85    PetscDrawBarSetData
86 
87    Logically Collective on PetscDrawBar
88 
89    Input Parameter:
90 +  bar - The bar graph context.
91 .  bins  - number of items
92 .  values - values of each item
93 -  labels - optional label for each bar, NULL terminated array of strings
94 
95    Level: intermediate
96 
97    Notes: Call PetscDrawBarDraw() after this call to display the new plot
98 
99 .seealso: PetscDrawBarCreate(), PetscDrawBar, PetscDrawBarDraw()
100 
101 @*/
102 PetscErrorCode  PetscDrawBarSetData(PetscDrawBar bar,PetscInt bins,const PetscReal data[],const char *const *labels)
103 {
104   PetscErrorCode ierr;
105 
106   PetscFunctionBegin;
107   PetscValidHeaderSpecific(bar,PETSC_DRAWBAR_CLASSID,1);
108 
109   if (bar->numBins != bins) {
110     ierr = PetscFree(bar->values);CHKERRQ(ierr);
111     ierr = PetscMalloc1(bins, &bar->values);CHKERRQ(ierr);
112     bar->numBins = bins;
113   }
114   ierr = PetscMemcpy(bar->values,data,bins*sizeof(PetscReal));CHKERRQ(ierr);
115   bar->numBins = bins;
116   if (labels) {
117     ierr = PetscStrArrayallocpy(labels,&bar->labels);CHKERRQ(ierr);
118   }
119   PetscFunctionReturn(0);
120 }
121 
122 /*@C
123   PetscDrawBarDestroy - Frees all space taken up by bar graph data structure.
124 
125   Collective over PetscDrawBar
126 
127   Input Parameter:
128 . bar - The bar graph context
129 
130   Level: intermediate
131 
132 .seealso:  PetscDrawBarCreate()
133 @*/
134 PetscErrorCode  PetscDrawBarDestroy(PetscDrawBar *bar)
135 {
136   PetscErrorCode ierr;
137 
138   PetscFunctionBegin;
139   if (!*bar) PetscFunctionReturn(0);
140   PetscValidHeaderSpecific(*bar,PETSC_DRAWBAR_CLASSID,1);
141   if (--((PetscObject)(*bar))->refct > 0) PetscFunctionReturn(0);
142 
143   ierr = PetscFree((*bar)->values);CHKERRQ(ierr);
144   ierr = PetscStrArrayDestroy(&(*bar)->labels);CHKERRQ(ierr);
145   ierr = PetscDrawAxisDestroy(&(*bar)->axis);CHKERRQ(ierr);
146   ierr = PetscDrawDestroy(&(*bar)->win);CHKERRQ(ierr);
147   ierr = PetscHeaderDestroy(bar);CHKERRQ(ierr);
148   PetscFunctionReturn(0);
149 }
150 
151 /*@
152   PetscDrawBarDraw - Redraws a bar graph.
153 
154   Collective on PetscDrawBar
155 
156   Input Parameter:
157 . bar - The bar graph context
158 
159   Level: intermediate
160 
161 .seealso: PetscDrawBar, PetscDrawBarCreate(), PetscDrawBarSetData()
162 
163 @*/
164 PetscErrorCode  PetscDrawBarDraw(PetscDrawBar bar)
165 {
166   PetscDraw      draw;
167   PetscBool      isnull;
168   PetscReal      xmin,xmax,ymin,ymax,*values,binLeft,binRight;
169   PetscInt       numValues,i,bcolor,color,idx,*perm,nplot;
170   PetscMPIInt    rank;
171   PetscErrorCode ierr;
172   char           **labels;
173 
174   PetscFunctionBegin;
175   PetscValidHeaderSpecific(bar,PETSC_DRAWBAR_CLASSID,1);
176   ierr = PetscDrawIsNull(bar->win,&isnull);CHKERRQ(ierr);
177   if (isnull) PetscFunctionReturn(0);
178   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)bar),&rank);CHKERRQ(ierr);
179 
180   if (bar->numBins < 1) PetscFunctionReturn(0);
181 
182   color = bar->color;
183   if (color == PETSC_DRAW_ROTATE) bcolor = PETSC_DRAW_BLACK+1;
184   else bcolor = color;
185 
186   numValues = bar->numBins;
187   values    = bar->values;
188   if (bar->ymin == bar->ymax) {
189     /* user has not set bounds on bars so set them based on the data */
190     ymin = PETSC_MAX_REAL;
191     ymax = PETSC_MIN_REAL;
192     for (i=0; i<numValues; i++) {
193       ymin = PetscMin(ymin,values[i]);
194       ymax = PetscMax(ymax,values[i]);
195     }
196   } else {
197     ymin = bar->ymin;
198     ymax = bar->ymax;
199   }
200   nplot  = numValues;  /* number of points to actually plot; if some are lower than requested tolerance */
201   xmin   = 0.0;
202   xmax   = nplot;
203   labels = bar->labels;
204 
205   if (bar->sort) {
206     ierr = PetscMalloc1(numValues,&perm);CHKERRQ(ierr);
207     for (i=0; i<numValues;i++) perm[i] = i;
208     ierr = PetscSortRealWithPermutation(numValues,values,perm);CHKERRQ(ierr);
209     if (bar->sorttolerance) {
210       for (i=0; i<numValues;i++) {
211         if (values[perm[numValues - i - 1]] < bar->sorttolerance) {
212           nplot = i;
213           break;
214         }
215       }
216     }
217   }
218 
219   draw = bar->win;
220   ierr = PetscDrawCheckResizedWindow(draw);CHKERRQ(ierr);
221   ierr = PetscDrawClear(draw);CHKERRQ(ierr);
222 
223   ierr = PetscDrawAxisSetLimits(bar->axis,xmin,xmax,ymin,ymax);CHKERRQ(ierr);
224   ierr = PetscDrawAxisDraw(bar->axis);CHKERRQ(ierr);
225 
226   ierr = PetscDrawCollectiveBegin(draw);CHKERRQ(ierr);
227   if (!rank) { /* Draw bins */
228     for (i=0; i<nplot; i++) {
229       idx = (bar->sort ? perm[numValues - i - 1] : i);
230       binLeft  = xmin + i;
231       binRight = xmin + i + 1;
232       ierr = PetscDrawRectangle(draw,binLeft,ymin,binRight,values[idx],bcolor,bcolor,bcolor,bcolor);CHKERRQ(ierr);
233       ierr = PetscDrawLine(draw,binLeft,ymin,binLeft,values[idx],PETSC_DRAW_BLACK);CHKERRQ(ierr);
234       ierr = PetscDrawLine(draw,binRight,ymin,binRight,values[idx],PETSC_DRAW_BLACK);CHKERRQ(ierr);
235       ierr = PetscDrawLine(draw,binLeft,values[idx],binRight,values[idx],PETSC_DRAW_BLACK);CHKERRQ(ierr);
236       if (labels) {
237         PetscReal h;
238         ierr = PetscDrawStringGetSize(draw,NULL,&h);CHKERRQ(ierr);
239         ierr = PetscDrawStringCentered(draw,.5*(binLeft+binRight),ymin - 1.5*h,bcolor,labels[idx]);CHKERRQ(ierr);
240       }
241       if (color == PETSC_DRAW_ROTATE) bcolor++;
242       if (bcolor > PETSC_DRAW_BASIC_COLORS-1) bcolor = PETSC_DRAW_BLACK+1;
243     }
244   }
245   ierr = PetscDrawCollectiveEnd(draw);CHKERRQ(ierr);
246   if (bar->sort) {ierr = PetscFree(perm);CHKERRQ(ierr);}
247 
248   ierr = PetscDrawFlush(draw);CHKERRQ(ierr);
249   ierr = PetscDrawPause(draw);CHKERRQ(ierr);
250   PetscFunctionReturn(0);
251 }
252 
253 /*@
254   PetscDrawBarSave - Saves a drawn image
255 
256   Collective on PetscDrawBar
257 
258   Input Parameters:
259 . bar - The bar graph context
260 
261   Level: intermediate
262 
263   Concepts: bar graph^saving
264 
265 .seealso:  PetscDrawBarCreate(), PetscDrawBarGetDraw(), PetscDrawSetSave(), PetscDrawSave(), PetscDrawBarSetData()
266 @*/
267 PetscErrorCode  PetscDrawBarSave(PetscDrawBar bar)
268 {
269   PetscErrorCode ierr;
270 
271   PetscFunctionBegin;
272   PetscValidHeaderSpecific(bar,PETSC_DRAWBAR_CLASSID,1);
273   ierr = PetscDrawSave(bar->win);CHKERRQ(ierr);
274   PetscFunctionReturn(0);
275 }
276 
277 /*@
278   PetscDrawBarSetColor - Sets the color the bars will be drawn with.
279 
280   Logically Collective on PetscDrawBar
281 
282   Input Parameters:
283 + bar - The bar graph context
284 - color - one of the colors defined in petscdraw.h or PETSC_DRAW_ROTATE to make each bar a
285           different color
286 
287   Level: intermediate
288 
289 .seealso: PetscDrawBarCreate(), PetscDrawBar, PetscDrawBarSetData(), PetscDrawBarDraw(), PetscDrawBarGetAxis()
290 
291 @*/
292 PetscErrorCode  PetscDrawBarSetColor(PetscDrawBar bar, int color)
293 {
294   PetscFunctionBegin;
295   PetscValidHeaderSpecific(bar, PETSC_DRAWBAR_CLASSID,1);
296   bar->color = color;
297   PetscFunctionReturn(0);
298 }
299 
300 /*@
301   PetscDrawBarSort - Sorts the values before drawing the bar chart
302 
303   Logically Collective on PetscDrawBar
304 
305   Input Parameters:
306 + bar - The bar graph context
307 . sort - PETSC_TRUE to sort the values
308 . tolerance - discard values less than tolerance
309 
310   Level: intermediate
311 
312   Concepts: bar graph^setting axis
313 
314 .seealso: PetscDrawBarCreate(), PetscDrawBar, PetscDrawBarSetData(), PetscDrawBarSetColor(), PetscDrawBarDraw(), PetscDrawBarGetAxis()
315 @*/
316 PetscErrorCode  PetscDrawBarSort(PetscDrawBar bar, PetscBool sort, PetscReal tolerance)
317 {
318   PetscFunctionBegin;
319   PetscValidHeaderSpecific(bar,PETSC_DRAWBAR_CLASSID,1);
320   bar->sort          = sort;
321   bar->sorttolerance = tolerance;
322   PetscFunctionReturn(0);
323 }
324 
325 /*@
326   PetscDrawBarSetLimits - Sets the axis limits for a bar graph. If more
327   points are added after this call, the limits will be adjusted to
328   include those additional points.
329 
330   Logically Collective on PetscDrawBar
331 
332   Input Parameters:
333 + bar - The bar graph context
334 - y_min,y_max - The limits
335 
336   Level: intermediate
337 
338   Concepts: bar graph^setting axis
339 
340 .seealso: PetscDrawBarCreate(), PetscDrawBar, PetscDrawBarGetAxis(), PetscDrawBarSetData(), PetscDrawBarDraw()
341 @*/
342 PetscErrorCode  PetscDrawBarSetLimits(PetscDrawBar bar, PetscReal y_min, PetscReal y_max)
343 {
344   PetscFunctionBegin;
345   PetscValidHeaderSpecific(bar,PETSC_DRAWBAR_CLASSID,1);
346   bar->ymin = y_min;
347   bar->ymax = y_max;
348   PetscFunctionReturn(0);
349 }
350 
351 /*@C
352   PetscDrawBarGetAxis - Gets the axis context associated with a bar graph.
353   This is useful if one wants to change some axis property, such as
354   labels, color, etc. The axis context should not be destroyed by the
355   application code.
356 
357   Not Collective, PetscDrawAxis is parallel if PetscDrawBar is parallel
358 
359   Input Parameter:
360 . bar - The bar graph context
361 
362   Output Parameter:
363 . axis - The axis context
364 
365   Level: intermediate
366 
367 .seealso: PetscDrawBarCreate(), PetscDrawBar, PetscDrawAxis, PetscDrawAxisCreate()
368 @*/
369 PetscErrorCode  PetscDrawBarGetAxis(PetscDrawBar bar,PetscDrawAxis *axis)
370 {
371   PetscFunctionBegin;
372   PetscValidHeaderSpecific(bar,PETSC_DRAWBAR_CLASSID,1);
373   PetscValidPointer(axis,2);
374   *axis = bar->axis;
375   PetscFunctionReturn(0);
376 }
377 
378 /*@C
379   PetscDrawBarGetDraw - Gets the draw context associated with a bar graph.
380 
381   Not Collective, PetscDraw is parallel if PetscDrawBar is parallel
382 
383   Input Parameter:
384 . bar - The bar graph context
385 
386   Output Parameter:
387 . draw  - The draw context
388 
389   Level: intermediate
390 
391 .seealso: PetscDrawBarCreate(), PetscDrawBar, PetscDrawBarDraw(), PetscDraw
392 @*/
393 PetscErrorCode  PetscDrawBarGetDraw(PetscDrawBar bar,PetscDraw *draw)
394 {
395   PetscFunctionBegin;
396   PetscValidHeaderSpecific(bar,PETSC_DRAWBAR_CLASSID,1);
397   PetscValidPointer(draw,2);
398   *draw = bar->win;
399   PetscFunctionReturn(0);
400 }
401 
402 /*@
403     PetscDrawBarSetFromOptions - Sets options related to the PetscDrawBar
404 
405     Collective over PetscDrawBar
406 
407     Options Database:
408 .  -bar_sort - sort the entries before drawing the bar graph
409 
410     Level: intermediate
411 
412 
413 .seealso:  PetscDrawBarDestroy(), PetscDrawBarCreate(), PetscDrawBarSort()
414 @*/
415 PetscErrorCode  PetscDrawBarSetFromOptions(PetscDrawBar bar)
416 {
417   PetscErrorCode ierr;
418   PetscBool      set;
419 
420   PetscFunctionBegin;
421   PetscValidHeaderSpecific(bar,PETSC_DRAWBAR_CLASSID,1);
422 
423   ierr = PetscOptionsHasName(((PetscObject)bar)->options,((PetscObject)bar)->prefix,"-bar_sort",&set);CHKERRQ(ierr);
424   if (set) {
425     PetscReal tol = bar->sorttolerance;
426     ierr = PetscOptionsGetReal(((PetscObject)bar)->options,((PetscObject)bar)->prefix,"-bar_sort",&tol,NULL);CHKERRQ(ierr);
427     ierr = PetscDrawBarSort(bar,PETSC_TRUE,tol);CHKERRQ(ierr);
428   }
429   PetscFunctionReturn(0);
430 }
431 
432