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