xref: /petsc/src/sys/classes/draw/utils/bars.c (revision ee12ae39415b2e672d944cdca066227dadbf8b14)
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 https://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 .seealso: PetscDrawLGCreate(), PetscDrawLG, PetscDrawSPCreate(), PetscDrawSP, PetscDrawHGCreate(), PetscDrawHG, PetscDrawBarDestroy(), PetscDrawBarSetData(),
51           PetscDrawBar, PetscDrawBarDraw(), PetscDrawBarSave(), PetscDrawBarSetColor(), PetscDrawBarSort(), PetscDrawBarSetLimits(), PetscDrawBarGetAxis(), PetscDrawAxis,
52           PetscDrawBarGetDraw(), PetscDrawBarSetFromOptions()
53 @*/
54 PetscErrorCode  PetscDrawBarCreate(PetscDraw draw,PetscDrawBar *bar)
55 {
56   PetscDrawBar   h;
57   PetscErrorCode ierr;
58 
59   PetscFunctionBegin;
60   PetscValidHeaderSpecific(draw,PETSC_DRAW_CLASSID,1);
61   PetscValidPointer(bar,2);
62 
63   ierr = PetscHeaderCreate(h,PETSC_DRAWBAR_CLASSID,"DrawBar","Bar Graph","Draw",PetscObjectComm((PetscObject)draw),PetscDrawBarDestroy,NULL);CHKERRQ(ierr);
64   ierr = PetscLogObjectParent((PetscObject)draw,(PetscObject)h);CHKERRQ(ierr);
65 
66   ierr = PetscObjectReference((PetscObject)draw);CHKERRQ(ierr);
67   h->win = draw;
68 
69   h->view        = NULL;
70   h->destroy     = NULL;
71   h->color       = PETSC_DRAW_GREEN;
72   h->ymin        = 0.;  /* if user has not set these then they are determined from the data */
73   h->ymax        = 0.;
74   h->numBins     = 0;
75 
76   ierr = PetscDrawAxisCreate(draw,&h->axis);CHKERRQ(ierr);
77   h->axis->xticks = NULL;
78 
79   *bar = h;
80   PetscFunctionReturn(0);
81 }
82 
83 /*@C
84    PetscDrawBarSetData
85 
86    Logically Collective on PetscDrawBar
87 
88    Input Parameter:
89 +  bar - The bar graph context.
90 .  bins  - number of items
91 .  values - values of each item
92 -  labels - optional label for each bar, NULL terminated array of strings
93 
94    Level: intermediate
95 
96    Notes:
97     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 = PetscArraycpy(bar->values,data,bins);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);CHKERRMPI(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 .seealso:  PetscDrawBarCreate(), PetscDrawBarGetDraw(), PetscDrawSetSave(), PetscDrawSave(), PetscDrawBarSetData()
264 @*/
265 PetscErrorCode  PetscDrawBarSave(PetscDrawBar bar)
266 {
267   PetscErrorCode ierr;
268 
269   PetscFunctionBegin;
270   PetscValidHeaderSpecific(bar,PETSC_DRAWBAR_CLASSID,1);
271   ierr = PetscDrawSave(bar->win);CHKERRQ(ierr);
272   PetscFunctionReturn(0);
273 }
274 
275 /*@
276   PetscDrawBarSetColor - Sets the color the bars will be drawn with.
277 
278   Logically Collective on PetscDrawBar
279 
280   Input Parameters:
281 + bar - The bar graph context
282 - color - one of the colors defined in petscdraw.h or PETSC_DRAW_ROTATE to make each bar a
283           different color
284 
285   Level: intermediate
286 
287 .seealso: PetscDrawBarCreate(), PetscDrawBar, PetscDrawBarSetData(), PetscDrawBarDraw(), PetscDrawBarGetAxis()
288 
289 @*/
290 PetscErrorCode  PetscDrawBarSetColor(PetscDrawBar bar, int color)
291 {
292   PetscFunctionBegin;
293   PetscValidHeaderSpecific(bar, PETSC_DRAWBAR_CLASSID,1);
294   bar->color = color;
295   PetscFunctionReturn(0);
296 }
297 
298 /*@
299   PetscDrawBarSort - Sorts the values before drawing the bar chart
300 
301   Logically Collective on PetscDrawBar
302 
303   Input Parameters:
304 + bar - The bar graph context
305 . sort - PETSC_TRUE to sort the values
306 - tolerance - discard values less than tolerance
307 
308   Level: intermediate
309 
310 .seealso: PetscDrawBarCreate(), PetscDrawBar, PetscDrawBarSetData(), PetscDrawBarSetColor(), PetscDrawBarDraw(), PetscDrawBarGetAxis()
311 @*/
312 PetscErrorCode  PetscDrawBarSort(PetscDrawBar bar, PetscBool sort, PetscReal tolerance)
313 {
314   PetscFunctionBegin;
315   PetscValidHeaderSpecific(bar,PETSC_DRAWBAR_CLASSID,1);
316   bar->sort          = sort;
317   bar->sorttolerance = tolerance;
318   PetscFunctionReturn(0);
319 }
320 
321 /*@
322   PetscDrawBarSetLimits - Sets the axis limits for a bar graph. If more
323   points are added after this call, the limits will be adjusted to
324   include those additional points.
325 
326   Logically Collective on PetscDrawBar
327 
328   Input Parameters:
329 + bar - The bar graph context
330 - y_min,y_max - The limits
331 
332   Level: intermediate
333 
334 .seealso: PetscDrawBarCreate(), PetscDrawBar, PetscDrawBarGetAxis(), PetscDrawBarSetData(), PetscDrawBarDraw()
335 @*/
336 PetscErrorCode  PetscDrawBarSetLimits(PetscDrawBar bar, PetscReal y_min, PetscReal y_max)
337 {
338   PetscFunctionBegin;
339   PetscValidHeaderSpecific(bar,PETSC_DRAWBAR_CLASSID,1);
340   bar->ymin = y_min;
341   bar->ymax = y_max;
342   PetscFunctionReturn(0);
343 }
344 
345 /*@C
346   PetscDrawBarGetAxis - Gets the axis context associated with a bar graph.
347   This is useful if one wants to change some axis property, such as
348   labels, color, etc. The axis context should not be destroyed by the
349   application code.
350 
351   Not Collective, PetscDrawAxis is parallel if PetscDrawBar is parallel
352 
353   Input Parameter:
354 . bar - The bar graph context
355 
356   Output Parameter:
357 . axis - The axis context
358 
359   Level: intermediate
360 
361 .seealso: PetscDrawBarCreate(), PetscDrawBar, PetscDrawAxis, PetscDrawAxisCreate()
362 @*/
363 PetscErrorCode  PetscDrawBarGetAxis(PetscDrawBar bar,PetscDrawAxis *axis)
364 {
365   PetscFunctionBegin;
366   PetscValidHeaderSpecific(bar,PETSC_DRAWBAR_CLASSID,1);
367   PetscValidPointer(axis,2);
368   *axis = bar->axis;
369   PetscFunctionReturn(0);
370 }
371 
372 /*@C
373   PetscDrawBarGetDraw - Gets the draw context associated with a bar graph.
374 
375   Not Collective, PetscDraw is parallel if PetscDrawBar is parallel
376 
377   Input Parameter:
378 . bar - The bar graph context
379 
380   Output Parameter:
381 . draw  - The draw context
382 
383   Level: intermediate
384 
385 .seealso: PetscDrawBarCreate(), PetscDrawBar, PetscDrawBarDraw(), PetscDraw
386 @*/
387 PetscErrorCode  PetscDrawBarGetDraw(PetscDrawBar bar,PetscDraw *draw)
388 {
389   PetscFunctionBegin;
390   PetscValidHeaderSpecific(bar,PETSC_DRAWBAR_CLASSID,1);
391   PetscValidPointer(draw,2);
392   *draw = bar->win;
393   PetscFunctionReturn(0);
394 }
395 
396 /*@
397     PetscDrawBarSetFromOptions - Sets options related to the PetscDrawBar
398 
399     Collective over PetscDrawBar
400 
401     Options Database:
402 .  -bar_sort - sort the entries before drawing the bar graph
403 
404     Level: intermediate
405 
406 
407 .seealso:  PetscDrawBarDestroy(), PetscDrawBarCreate(), PetscDrawBarSort()
408 @*/
409 PetscErrorCode  PetscDrawBarSetFromOptions(PetscDrawBar bar)
410 {
411   PetscErrorCode ierr;
412   PetscBool      set;
413 
414   PetscFunctionBegin;
415   PetscValidHeaderSpecific(bar,PETSC_DRAWBAR_CLASSID,1);
416 
417   ierr = PetscOptionsHasName(((PetscObject)bar)->options,((PetscObject)bar)->prefix,"-bar_sort",&set);CHKERRQ(ierr);
418   if (set) {
419     PetscReal tol = bar->sorttolerance;
420     ierr = PetscOptionsGetReal(((PetscObject)bar)->options,((PetscObject)bar)->prefix,"-bar_sort",&tol,NULL);CHKERRQ(ierr);
421     ierr = PetscDrawBarSort(bar,PETSC_TRUE,tol);CHKERRQ(ierr);
422   }
423   PetscFunctionReturn(0);
424 }
425