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