xref: /petsc/src/sys/classes/draw/utils/bars.c (revision 356ed81403a8ddb9cbcae868d64486ea275d004c)
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   PetscErrorCode ierr;
150 
151   PetscFunctionBegin;
152   PetscValidHeaderSpecific(bar,PETSC_DRAWBAR_CLASSID,1);
153   PetscCall(PetscDrawIsNull(bar->win,&isnull));
154   if (isnull) PetscFunctionReturn(0);
155   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)bar),&rank));
156 
157   if (bar->numBins < 1) PetscFunctionReturn(0);
158 
159   color = bar->color;
160   if (color == PETSC_DRAW_ROTATE) bcolor = PETSC_DRAW_BLACK+1;
161   else bcolor = color;
162 
163   numValues = bar->numBins;
164   values    = bar->values;
165   if (bar->ymin == bar->ymax) {
166     /* user has not set bounds on bars so set them based on the data */
167     ymin = PETSC_MAX_REAL;
168     ymax = PETSC_MIN_REAL;
169     for (i=0; i<numValues; i++) {
170       ymin = PetscMin(ymin,values[i]);
171       ymax = PetscMax(ymax,values[i]);
172     }
173   } else {
174     ymin = bar->ymin;
175     ymax = bar->ymax;
176   }
177   nplot  = numValues;  /* number of points to actually plot; if some are lower than requested tolerance */
178   xmin   = 0.0;
179   xmax   = nplot;
180   labels = bar->labels;
181 
182   if (bar->sort) {
183     PetscCall(PetscMalloc1(numValues,&perm));
184     for (i=0; i<numValues;i++) perm[i] = i;
185     PetscCall(PetscSortRealWithPermutation(numValues,values,perm));
186     if (bar->sorttolerance) {
187       for (i=0; i<numValues;i++) {
188         if (values[perm[numValues - i - 1]] < bar->sorttolerance) {
189           nplot = i;
190           break;
191         }
192       }
193     }
194   }
195 
196   draw = bar->win;
197   PetscCall(PetscDrawCheckResizedWindow(draw));
198   PetscCall(PetscDrawClear(draw));
199 
200   PetscCall(PetscDrawAxisSetLimits(bar->axis,xmin,xmax,ymin,ymax));
201   PetscCall(PetscDrawAxisDraw(bar->axis));
202 
203   ierr = PetscDrawCollectiveBegin(draw);PetscCall(ierr);
204   if (rank == 0) { /* Draw bins */
205     for (i=0; i<nplot; i++) {
206       idx = (bar->sort ? perm[numValues - i - 1] : i);
207       binLeft  = xmin + i;
208       binRight = xmin + i + 1;
209       PetscCall(PetscDrawRectangle(draw,binLeft,ymin,binRight,values[idx],bcolor,bcolor,bcolor,bcolor));
210       PetscCall(PetscDrawLine(draw,binLeft,ymin,binLeft,values[idx],PETSC_DRAW_BLACK));
211       PetscCall(PetscDrawLine(draw,binRight,ymin,binRight,values[idx],PETSC_DRAW_BLACK));
212       PetscCall(PetscDrawLine(draw,binLeft,values[idx],binRight,values[idx],PETSC_DRAW_BLACK));
213       if (labels) {
214         PetscReal h;
215         PetscCall(PetscDrawStringGetSize(draw,NULL,&h));
216         PetscCall(PetscDrawStringCentered(draw,.5*(binLeft+binRight),ymin - 1.5*h,bcolor,labels[idx]));
217       }
218       if (color == PETSC_DRAW_ROTATE) bcolor++;
219       if (bcolor > PETSC_DRAW_BASIC_COLORS-1) bcolor = PETSC_DRAW_BLACK+1;
220     }
221   }
222   ierr = PetscDrawCollectiveEnd(draw);PetscCall(ierr);
223   if (bar->sort) PetscCall(PetscFree(perm));
224 
225   PetscCall(PetscDrawFlush(draw));
226   PetscCall(PetscDrawPause(draw));
227   PetscFunctionReturn(0);
228 }
229 
230 /*@
231   PetscDrawBarSave - Saves a drawn image
232 
233   Collective on PetscDrawBar
234 
235   Input Parameters:
236 . bar - The bar graph context
237 
238   Level: intermediate
239 
240 .seealso:  PetscDrawBarCreate(), PetscDrawBarGetDraw(), PetscDrawSetSave(), PetscDrawSave(), PetscDrawBarSetData()
241 @*/
242 PetscErrorCode  PetscDrawBarSave(PetscDrawBar bar)
243 {
244   PetscFunctionBegin;
245   PetscValidHeaderSpecific(bar,PETSC_DRAWBAR_CLASSID,1);
246   PetscCall(PetscDrawSave(bar->win));
247   PetscFunctionReturn(0);
248 }
249 
250 /*@
251   PetscDrawBarSetColor - Sets the color the bars will be drawn with.
252 
253   Logically Collective on PetscDrawBar
254 
255   Input Parameters:
256 + bar - The bar graph context
257 - color - one of the colors defined in petscdraw.h or PETSC_DRAW_ROTATE to make each bar a
258           different color
259 
260   Level: intermediate
261 
262 .seealso: PetscDrawBarCreate(), PetscDrawBar, PetscDrawBarSetData(), PetscDrawBarDraw(), PetscDrawBarGetAxis()
263 
264 @*/
265 PetscErrorCode  PetscDrawBarSetColor(PetscDrawBar bar, int color)
266 {
267   PetscFunctionBegin;
268   PetscValidHeaderSpecific(bar, PETSC_DRAWBAR_CLASSID,1);
269   bar->color = color;
270   PetscFunctionReturn(0);
271 }
272 
273 /*@
274   PetscDrawBarSort - Sorts the values before drawing the bar chart
275 
276   Logically Collective on PetscDrawBar
277 
278   Input Parameters:
279 + bar - The bar graph context
280 . sort - PETSC_TRUE to sort the values
281 - tolerance - discard values less than tolerance
282 
283   Level: intermediate
284 
285 .seealso: PetscDrawBarCreate(), PetscDrawBar, PetscDrawBarSetData(), PetscDrawBarSetColor(), PetscDrawBarDraw(), PetscDrawBarGetAxis()
286 @*/
287 PetscErrorCode  PetscDrawBarSort(PetscDrawBar bar, PetscBool sort, PetscReal tolerance)
288 {
289   PetscFunctionBegin;
290   PetscValidHeaderSpecific(bar,PETSC_DRAWBAR_CLASSID,1);
291   bar->sort          = sort;
292   bar->sorttolerance = tolerance;
293   PetscFunctionReturn(0);
294 }
295 
296 /*@
297   PetscDrawBarSetLimits - Sets the axis limits for a bar graph. If more
298   points are added after this call, the limits will be adjusted to
299   include those additional points.
300 
301   Logically Collective on PetscDrawBar
302 
303   Input Parameters:
304 + bar - The bar graph context
305 - y_min,y_max - The limits
306 
307   Level: intermediate
308 
309 .seealso: PetscDrawBarCreate(), PetscDrawBar, PetscDrawBarGetAxis(), PetscDrawBarSetData(), PetscDrawBarDraw()
310 @*/
311 PetscErrorCode  PetscDrawBarSetLimits(PetscDrawBar bar, PetscReal y_min, PetscReal y_max)
312 {
313   PetscFunctionBegin;
314   PetscValidHeaderSpecific(bar,PETSC_DRAWBAR_CLASSID,1);
315   bar->ymin = y_min;
316   bar->ymax = y_max;
317   PetscFunctionReturn(0);
318 }
319 
320 /*@C
321   PetscDrawBarGetAxis - Gets the axis context associated with a bar graph.
322   This is useful if one wants to change some axis property, such as
323   labels, color, etc. The axis context should not be destroyed by the
324   application code.
325 
326   Not Collective, PetscDrawAxis is parallel if PetscDrawBar is parallel
327 
328   Input Parameter:
329 . bar - The bar graph context
330 
331   Output Parameter:
332 . axis - The axis context
333 
334   Level: intermediate
335 
336 .seealso: PetscDrawBarCreate(), PetscDrawBar, PetscDrawAxis, PetscDrawAxisCreate()
337 @*/
338 PetscErrorCode  PetscDrawBarGetAxis(PetscDrawBar bar,PetscDrawAxis *axis)
339 {
340   PetscFunctionBegin;
341   PetscValidHeaderSpecific(bar,PETSC_DRAWBAR_CLASSID,1);
342   PetscValidPointer(axis,2);
343   *axis = bar->axis;
344   PetscFunctionReturn(0);
345 }
346 
347 /*@C
348   PetscDrawBarGetDraw - Gets the draw context associated with a bar graph.
349 
350   Not Collective, PetscDraw is parallel if PetscDrawBar is parallel
351 
352   Input Parameter:
353 . bar - The bar graph context
354 
355   Output Parameter:
356 . draw  - The draw context
357 
358   Level: intermediate
359 
360 .seealso: PetscDrawBarCreate(), PetscDrawBar, PetscDrawBarDraw(), PetscDraw
361 @*/
362 PetscErrorCode  PetscDrawBarGetDraw(PetscDrawBar bar,PetscDraw *draw)
363 {
364   PetscFunctionBegin;
365   PetscValidHeaderSpecific(bar,PETSC_DRAWBAR_CLASSID,1);
366   PetscValidPointer(draw,2);
367   *draw = bar->win;
368   PetscFunctionReturn(0);
369 }
370 
371 /*@
372     PetscDrawBarSetFromOptions - Sets options related to the PetscDrawBar
373 
374     Collective over PetscDrawBar
375 
376     Options Database:
377 .  -bar_sort - sort the entries before drawing the bar graph
378 
379     Level: intermediate
380 
381 .seealso:  PetscDrawBarDestroy(), PetscDrawBarCreate(), PetscDrawBarSort()
382 @*/
383 PetscErrorCode  PetscDrawBarSetFromOptions(PetscDrawBar bar)
384 {
385   PetscBool      set;
386 
387   PetscFunctionBegin;
388   PetscValidHeaderSpecific(bar,PETSC_DRAWBAR_CLASSID,1);
389 
390   PetscCall(PetscOptionsHasName(((PetscObject)bar)->options,((PetscObject)bar)->prefix,"-bar_sort",&set));
391   if (set) {
392     PetscReal tol = bar->sorttolerance;
393     PetscCall(PetscOptionsGetReal(((PetscObject)bar)->options,((PetscObject)bar)->prefix,"-bar_sort",&tol,NULL));
394     PetscCall(PetscDrawBarSort(bar,PETSC_TRUE,tol));
395   }
396   PetscFunctionReturn(0);
397 }
398