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