Actual source code: bars.c
1: /*
2: Contains the data structure for plotting a bargraph in a window with an axis.
3: */
5: #include <petsc/private/drawimpl.h>
6: #include <petscviewer.h>
8: PetscClassId PETSC_DRAWBAR_CLASSID = 0;
10: /*@
11: PetscDrawBarCreate - Creates a bar graph data structure.
13: Collective
15: Input Parameter:
16: . draw - The window where the graph will be made
18: Output Parameter:
19: . bar - The bar graph context
21: Notes:
22: Call `PetscDrawBarSetData()` to provide the bins to be plotted and then `PetscDrawBarDraw()` to display the new plot
24: The difference between a bar chart, `PetscDrawBar`, and a histogram, `PetscDrawHG`, is explained here <https://stattrek.com/statistics/charts/histogram.aspx?Tutorial=AP>
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.
29: Level: intermediate
31: .seealso: `PetscDrawBar`, `PetscDrawLGCreate()`, `PetscDrawLG`, `PetscDrawSPCreate()`, `PetscDrawSP`, `PetscDrawHGCreate()`, `PetscDrawHG`, `PetscDrawBarDestroy()`, `PetscDrawBarSetData()`,
32: `PetscDrawBarDraw()`, `PetscDrawBarSave()`, `PetscDrawBarSetColor()`, `PetscDrawBarSort()`, `PetscDrawBarSetLimits()`, `PetscDrawBarGetAxis()`, `PetscDrawAxis`,
33: `PetscDrawBarGetDraw()`, `PetscDrawBarSetFromOptions()`
34: @*/
35: PetscErrorCode PetscDrawBarCreate(PetscDraw draw, PetscDrawBar *bar)
36: {
37: PetscDrawBar h;
39: PetscFunctionBegin;
41: PetscAssertPointer(bar, 2);
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: }
58: /*@C
59: PetscDrawBarSetData - Set the data for a bar graph
61: Logically Collective
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
69: Level: intermediate
71: Notes:
72: Call `PetscDrawBarDraw()` after this call to display the new plot
74: The data is ignored on all MPI processes except rank zero
76: .seealso: `PetscDrawBar`, `PetscDrawBarCreate()`, `PetscDrawBarDraw()`
77: @*/
78: PetscErrorCode PetscDrawBarSetData(PetscDrawBar bar, PetscInt bins, const PetscReal data[], const char *const labels[])
79: {
80: PetscFunctionBegin;
83: if (bar->numBins != bins) {
84: PetscCall(PetscFree(bar->values));
85: PetscCall(PetscMalloc1(bins, &bar->values));
86: bar->numBins = (int)bins;
87: }
88: PetscCall(PetscArraycpy(bar->values, data, bins));
89: bar->numBins = (int)bins;
90: if (labels) PetscCall(PetscStrArrayallocpy(labels, &bar->labels));
91: PetscFunctionReturn(PETSC_SUCCESS);
92: }
94: /*@
95: PetscDrawBarDestroy - Frees all space taken up by bar graph data structure.
97: Collective
99: Input Parameter:
100: . bar - The bar graph context
102: Level: intermediate
104: .seealso: `PetscDrawBar`, `PetscDrawBarCreate()`
105: @*/
106: PetscErrorCode PetscDrawBarDestroy(PetscDrawBar *bar)
107: {
108: PetscFunctionBegin;
109: if (!*bar) PetscFunctionReturn(PETSC_SUCCESS);
111: if (--((PetscObject)*bar)->refct > 0) PetscFunctionReturn(PETSC_SUCCESS);
113: PetscCall(PetscFree((*bar)->values));
114: PetscCall(PetscStrArrayDestroy(&(*bar)->labels));
115: PetscCall(PetscDrawAxisDestroy(&(*bar)->axis));
116: PetscCall(PetscDrawDestroy(&(*bar)->win));
117: PetscCall(PetscHeaderDestroy(bar));
118: PetscFunctionReturn(PETSC_SUCCESS);
119: }
121: /*@
122: PetscDrawBarDraw - Redraws a bar graph.
124: Collective
126: Input Parameter:
127: . bar - The bar graph context
129: Level: intermediate
131: .seealso: `PetscDrawBar`, `PetscDrawBarCreate()`, `PetscDrawBarSetData()`
132: @*/
133: PetscErrorCode PetscDrawBarDraw(PetscDrawBar bar)
134: {
135: PetscDraw draw;
136: PetscBool isnull;
137: PetscReal xmin, xmax, ymin, ymax, *values, binLeft, binRight;
138: PetscInt numValues, i, idx, *perm, nplot;
139: PetscMPIInt rank;
140: char **labels;
141: int bcolor, color;
143: PetscFunctionBegin;
145: PetscCall(PetscDrawIsNull(bar->win, &isnull));
146: if (isnull) PetscFunctionReturn(PETSC_SUCCESS);
147: PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)bar), &rank));
149: if (bar->numBins < 1) PetscFunctionReturn(PETSC_SUCCESS);
151: color = bar->color;
152: if (color == PETSC_DRAW_ROTATE) bcolor = PETSC_DRAW_BLACK + 1;
153: else bcolor = color;
155: numValues = bar->numBins;
156: values = bar->values;
157: if (bar->ymin == bar->ymax) {
158: /* user has not set bounds on bars so set them based on the data */
159: ymin = PETSC_MAX_REAL;
160: ymax = PETSC_MIN_REAL;
161: for (i = 0; i < numValues; i++) {
162: ymin = PetscMin(ymin, values[i]);
163: ymax = PetscMax(ymax, values[i]);
164: }
165: } else {
166: ymin = bar->ymin;
167: ymax = bar->ymax;
168: }
169: nplot = numValues; /* number of points to actually plot; if some are lower than requested tolerance */
170: xmin = 0.0;
171: xmax = (PetscReal)nplot;
172: labels = bar->labels;
174: if (bar->sort) {
175: PetscCall(PetscMalloc1(numValues, &perm));
176: for (i = 0; i < numValues; i++) perm[i] = i;
177: PetscCall(PetscSortRealWithPermutation(numValues, values, perm));
178: if (bar->sorttolerance) {
179: for (i = 0; i < numValues; i++) {
180: if (values[perm[numValues - i - 1]] < bar->sorttolerance) {
181: nplot = i;
182: break;
183: }
184: }
185: }
186: }
188: draw = bar->win;
189: PetscCall(PetscDrawCheckResizedWindow(draw));
190: PetscCall(PetscDrawClear(draw));
192: PetscCall(PetscDrawAxisSetLimits(bar->axis, xmin, xmax, ymin, ymax));
193: PetscCall(PetscDrawAxisDraw(bar->axis));
195: PetscDrawCollectiveBegin(draw);
196: if (rank == 0) { /* Draw bins */
197: for (i = 0; i < nplot; i++) {
198: idx = (bar->sort ? perm[numValues - i - 1] : i);
199: binLeft = xmin + (PetscReal)i;
200: binRight = xmin + (PetscReal)i + 1;
201: PetscCall(PetscDrawRectangle(draw, binLeft, ymin, binRight, values[idx], bcolor, bcolor, bcolor, bcolor));
202: PetscCall(PetscDrawLine(draw, binLeft, ymin, binLeft, values[idx], PETSC_DRAW_BLACK));
203: PetscCall(PetscDrawLine(draw, binRight, ymin, binRight, values[idx], PETSC_DRAW_BLACK));
204: PetscCall(PetscDrawLine(draw, binLeft, values[idx], binRight, values[idx], PETSC_DRAW_BLACK));
205: if (labels) {
206: 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));
218: PetscCall(PetscDrawFlush(draw));
219: PetscCall(PetscDrawPause(draw));
220: PetscFunctionReturn(PETSC_SUCCESS);
221: }
223: /*@
224: PetscDrawBarSave - Saves a drawn bar graph
226: Collective
228: Input Parameter:
229: . bar - The bar graph context
231: Level: intermediate
233: .seealso: `PetscDrawSave()`, `PetscDrawBar`, `PetscDrawBarCreate()`, `PetscDrawBarGetDraw()`, `PetscDrawSetSave()`, `PetscDrawBarSetData()`
234: @*/
235: PetscErrorCode PetscDrawBarSave(PetscDrawBar bar)
236: {
237: PetscFunctionBegin;
239: PetscCall(PetscDrawSave(bar->win));
240: PetscFunctionReturn(PETSC_SUCCESS);
241: }
243: /*@
244: PetscDrawBarSetColor - Sets the color the bars will be drawn with.
246: Logically Collective
248: Input Parameters:
249: + bar - The bar graph context
250: - color - one of the colors defined in petscdraw.h or `PETSC_DRAW_ROTATE` to make each bar a
251: different color
253: Level: intermediate
255: .seealso: `PetscDrawBarCreate()`, `PetscDrawBar`, `PetscDrawBarSetData()`, `PetscDrawBarDraw()`, `PetscDrawBarGetAxis()`
256: @*/
257: PetscErrorCode PetscDrawBarSetColor(PetscDrawBar bar, int color)
258: {
259: PetscFunctionBegin;
261: bar->color = color;
262: PetscFunctionReturn(PETSC_SUCCESS);
263: }
265: /*@
266: PetscDrawBarSort - Sorts the values before drawing the bar chart, the bars will be in ascending order from left to right
268: Logically Collective
270: Input Parameters:
271: + bar - The bar graph context
272: . sort - `PETSC_TRUE` to sort the values
273: - tolerance - discard values less than tolerance
275: Level: intermediate
277: .seealso: `PetscDrawBar`, `PetscDrawBarCreate()`, `PetscDrawBarSetData()`, `PetscDrawBarSetColor()`, `PetscDrawBarDraw()`, `PetscDrawBarGetAxis()`
278: @*/
279: PetscErrorCode PetscDrawBarSort(PetscDrawBar bar, PetscBool sort, PetscReal tolerance)
280: {
281: PetscFunctionBegin;
283: bar->sort = sort;
284: bar->sorttolerance = tolerance;
285: PetscFunctionReturn(PETSC_SUCCESS);
286: }
288: /*@
289: PetscDrawBarSetLimits - Sets the axis limits for a bar graph. If more
290: points are added after this call, the limits will be adjusted to
291: include those additional points.
293: Logically Collective
295: Input Parameters:
296: + bar - The bar graph context
297: . y_min - The lower limit
298: - y_max - The upper limit
300: Level: intermediate
302: .seealso: `PetscDrawBar`, `PetscDrawBarCreate()`, `PetscDrawBarGetAxis()`, `PetscDrawBarSetData()`, `PetscDrawBarDraw()`
303: @*/
304: PetscErrorCode PetscDrawBarSetLimits(PetscDrawBar bar, PetscReal y_min, PetscReal y_max)
305: {
306: PetscFunctionBegin;
308: bar->ymin = y_min;
309: bar->ymax = y_max;
310: PetscFunctionReturn(PETSC_SUCCESS);
311: }
313: /*@
314: PetscDrawBarGetAxis - Gets the axis context associated with a bar graph.
315: This is useful if one wants to change some axis property, such as
316: labels, color, etc. The axis context should not be destroyed by the
317: application code.
319: Not Collective, axis is parallel if bar is parallel
321: Input Parameter:
322: . bar - The bar graph context
324: Output Parameter:
325: . axis - The axis context
327: Level: intermediate
329: .seealso: `PetscDrawBar`, `PetscDrawBarCreate()`, `PetscDrawAxis`, `PetscDrawAxisCreate()`
330: @*/
331: PetscErrorCode PetscDrawBarGetAxis(PetscDrawBar bar, PetscDrawAxis *axis)
332: {
333: PetscFunctionBegin;
335: PetscAssertPointer(axis, 2);
336: *axis = bar->axis;
337: PetscFunctionReturn(PETSC_SUCCESS);
338: }
340: /*@
341: PetscDrawBarGetDraw - Gets the draw context associated with a bar graph.
343: Not Collective, draw is parallel if bar is parallel
345: Input Parameter:
346: . bar - The bar graph context
348: Output Parameter:
349: . draw - The draw context
351: Level: intermediate
353: .seealso: `PetscDrawBar`, `PetscDraw`, `PetscDrawBarCreate()`, `PetscDrawBarDraw()`
354: @*/
355: PetscErrorCode PetscDrawBarGetDraw(PetscDrawBar bar, PetscDraw *draw)
356: {
357: PetscFunctionBegin;
359: PetscAssertPointer(draw, 2);
360: *draw = bar->win;
361: PetscFunctionReturn(PETSC_SUCCESS);
362: }
364: /*@
365: PetscDrawBarSetFromOptions - Sets options related to the display of the `PetscDrawBar`
367: Collective
369: Input Parameter:
370: . bar - the bar graph context
372: Options Database Key:
373: . -bar_sort - sort the entries before drawing the bar graph
375: Level: intermediate
377: Note:
378: Does not set options related to the underlying `PetscDraw` or `PetscDrawAxis`
380: .seealso: `PetscDrawBar`, `PetscDrawBarDestroy()`, `PetscDrawBarCreate()`, `PetscDrawBarSort()`
381: @*/
382: PetscErrorCode PetscDrawBarSetFromOptions(PetscDrawBar bar)
383: {
384: PetscBool set;
386: PetscFunctionBegin;
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(PETSC_SUCCESS);
396: }