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