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