xref: /petsc/src/sys/classes/draw/utils/bars.c (revision 0ea77eda237b1068ff0d8bfa28c3463dc2087695)
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 draw
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 rank in the communicator. All MPI ranks in the communicator must call `PetscDrawBarDraw()` to display the updated graph.
29 
30    Level: intermediate
31 
32 .seealso: `PetscDrawBar`, `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 bar
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    The data is ignored on all ranks except zero
80 
81 .seealso: `PetscDrawBar`, `PetscDrawBarCreate()`, `PetscDrawBar`, `PetscDrawBarDraw()`
82 @*/
83 PetscErrorCode PetscDrawBarSetData(PetscDrawBar bar, PetscInt bins, const PetscReal data[], const char *const *labels) {
84   PetscFunctionBegin;
85   PetscValidHeaderSpecific(bar, PETSC_DRAWBAR_CLASSID, 1);
86 
87   if (bar->numBins != bins) {
88     PetscCall(PetscFree(bar->values));
89     PetscCall(PetscMalloc1(bins, &bar->values));
90     bar->numBins = bins;
91   }
92   PetscCall(PetscArraycpy(bar->values, data, bins));
93   bar->numBins = bins;
94   if (labels) PetscCall(PetscStrArrayallocpy(labels, &bar->labels));
95   PetscFunctionReturn(0);
96 }
97 
98 /*@C
99   PetscDrawBarDestroy - Frees all space taken up by bar graph data structure.
100 
101   Collective over bar
102 
103   Input Parameter:
104 . bar - The bar graph context
105 
106   Level: intermediate
107 
108 .seealso: `PetscDrawBar`, `PetscDrawBarCreate()`
109 @*/
110 PetscErrorCode PetscDrawBarDestroy(PetscDrawBar *bar) {
111   PetscFunctionBegin;
112   if (!*bar) PetscFunctionReturn(0);
113   PetscValidHeaderSpecific(*bar, PETSC_DRAWBAR_CLASSID, 1);
114   if (--((PetscObject)(*bar))->refct > 0) PetscFunctionReturn(0);
115 
116   PetscCall(PetscFree((*bar)->values));
117   PetscCall(PetscStrArrayDestroy(&(*bar)->labels));
118   PetscCall(PetscDrawAxisDestroy(&(*bar)->axis));
119   PetscCall(PetscDrawDestroy(&(*bar)->win));
120   PetscCall(PetscHeaderDestroy(bar));
121   PetscFunctionReturn(0);
122 }
123 
124 /*@
125   PetscDrawBarDraw - Redraws a bar graph.
126 
127   Collective on bar
128 
129   Input Parameter:
130 . bar - The bar graph context
131 
132   Level: intermediate
133 
134 .seealso: `PetscDrawBar`, `PetscDrawBarCreate()`, `PetscDrawBarSetData()`
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 bar graph
225 
226   Collective on bar
227 
228   Input Parameters:
229 . bar - The bar graph context
230 
231   Level: intermediate
232 
233 .seealso: `PetscDrawSave()`, `PetscDrawBar`, `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 bar
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 PetscErrorCode PetscDrawBarSetColor(PetscDrawBar bar, int color) {
257   PetscFunctionBegin;
258   PetscValidHeaderSpecific(bar, PETSC_DRAWBAR_CLASSID, 1);
259   bar->color = color;
260   PetscFunctionReturn(0);
261 }
262 
263 /*@
264   PetscDrawBarSort - Sorts the values before drawing the bar chart, the bars will be in ascending order from left to right
265 
266   Logically Collective on bar
267 
268   Input Parameters:
269 + bar - The bar graph context
270 . sort - `PETSC_TRUE` to sort the values
271 - tolerance - discard values less than tolerance
272 
273   Level: intermediate
274 
275 .seealso: `PetscDrawBar`, `PetscDrawBarCreate()`, `PetscDrawBar`, `PetscDrawBarSetData()`, `PetscDrawBarSetColor()`, `PetscDrawBarDraw()`, `PetscDrawBarGetAxis()`
276 @*/
277 PetscErrorCode PetscDrawBarSort(PetscDrawBar bar, PetscBool sort, PetscReal tolerance) {
278   PetscFunctionBegin;
279   PetscValidHeaderSpecific(bar, PETSC_DRAWBAR_CLASSID, 1);
280   bar->sort          = sort;
281   bar->sorttolerance = tolerance;
282   PetscFunctionReturn(0);
283 }
284 
285 /*@
286   PetscDrawBarSetLimits - Sets the axis limits for a bar graph. If more
287   points are added after this call, the limits will be adjusted to
288   include those additional points.
289 
290   Logically Collective on bar
291 
292   Input Parameters:
293 + bar - The bar graph context
294 - y_min,y_max - The limits
295 
296   Level: intermediate
297 
298 .seealso: `PetscDrawBar`, `PetscDrawBarCreate()`, `PetscDrawBar`, `PetscDrawBarGetAxis()`, `PetscDrawBarSetData()`, `PetscDrawBarDraw()`
299 @*/
300 PetscErrorCode PetscDrawBarSetLimits(PetscDrawBar bar, PetscReal y_min, PetscReal y_max) {
301   PetscFunctionBegin;
302   PetscValidHeaderSpecific(bar, PETSC_DRAWBAR_CLASSID, 1);
303   bar->ymin = y_min;
304   bar->ymax = y_max;
305   PetscFunctionReturn(0);
306 }
307 
308 /*@C
309   PetscDrawBarGetAxis - Gets the axis context associated with a bar graph.
310   This is useful if one wants to change some axis property, such as
311   labels, color, etc. The axis context should not be destroyed by the
312   application code.
313 
314   Not Collective, axis is parallel if bar is parallel
315 
316   Input Parameter:
317 . bar - The bar graph context
318 
319   Output Parameter:
320 . axis - The axis context
321 
322   Level: intermediate
323 
324 .seealso: `PetscDrawBar`, `PetscDrawBarCreate()`, `PetscDrawBar`, `PetscDrawAxis`, `PetscDrawAxisCreate()`
325 @*/
326 PetscErrorCode PetscDrawBarGetAxis(PetscDrawBar bar, PetscDrawAxis *axis) {
327   PetscFunctionBegin;
328   PetscValidHeaderSpecific(bar, PETSC_DRAWBAR_CLASSID, 1);
329   PetscValidPointer(axis, 2);
330   *axis = bar->axis;
331   PetscFunctionReturn(0);
332 }
333 
334 /*@C
335   PetscDrawBarGetDraw - Gets the draw context associated with a bar graph.
336 
337   Not Collective, draw is parallel if bar is parallel
338 
339   Input Parameter:
340 . bar - The bar graph context
341 
342   Output Parameter:
343 . draw  - The draw context
344 
345   Level: intermediate
346 
347 .seealso: `PetscDrawBar`, `PetscDraw`, `PetscDrawBarCreate()`, `PetscDrawBar`, `PetscDrawBarDraw()`, `PetscDraw`
348 @*/
349 PetscErrorCode PetscDrawBarGetDraw(PetscDrawBar bar, PetscDraw *draw) {
350   PetscFunctionBegin;
351   PetscValidHeaderSpecific(bar, PETSC_DRAWBAR_CLASSID, 1);
352   PetscValidPointer(draw, 2);
353   *draw = bar->win;
354   PetscFunctionReturn(0);
355 }
356 
357 /*@
358     PetscDrawBarSetFromOptions - Sets options related to the display of the `PetscDrawBar`
359 
360     Collective over bar
361 
362     Options Database Key:
363 .  -bar_sort - sort the entries before drawing the bar graph
364 
365     Level: intermediate
366 
367     Note:
368     Does not set options related to the underlying `PetscDraw` or `PetscDrawAxis`
369 
370 .seealso: `PetscDrawBar`, `PetscDrawBarDestroy()`, `PetscDrawBarCreate()`, `PetscDrawBarSort()`
371 @*/
372 PetscErrorCode PetscDrawBarSetFromOptions(PetscDrawBar bar) {
373   PetscBool set;
374 
375   PetscFunctionBegin;
376   PetscValidHeaderSpecific(bar, PETSC_DRAWBAR_CLASSID, 1);
377 
378   PetscCall(PetscOptionsHasName(((PetscObject)bar)->options, ((PetscObject)bar)->prefix, "-bar_sort", &set));
379   if (set) {
380     PetscReal tol = bar->sorttolerance;
381     PetscCall(PetscOptionsGetReal(((PetscObject)bar)->options, ((PetscObject)bar)->prefix, "-bar_sort", &tol, NULL));
382     PetscCall(PetscDrawBarSort(bar, PETSC_TRUE, tol));
383   }
384   PetscFunctionReturn(0);
385 }
386