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: /*@C
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));
45: PetscCall(PetscObjectReference((PetscObject)draw));
46: h->win = draw;
48: h->view = NULL;
49: h->destroy = NULL;
50: h->color = PETSC_DRAW_GREEN;
51: h->ymin = 0.; /* if user has not set these then they are determined from the data */
52: h->ymax = 0.;
53: h->numBins = 0;
55: PetscCall(PetscDrawAxisCreate(draw, &h->axis));
56: h->axis->xticks = NULL;
58: *bar = h;
59: PetscFunctionReturn(PETSC_SUCCESS);
60: }
62: /*@C
63: PetscDrawBarSetData - Set the data for a bar graph
65: Logically Collective
67: Input Parameters:
68: + bar - The bar graph context.
69: . bins - number of items
70: . data - values of each item
71: - labels - optional label for each bar, `NULL` terminated array of strings
73: Level: intermediate
75: Notes:
76: Call `PetscDrawBarDraw()` after this call to display the new plot
78: The data is ignored on all MPI processes except rank zero
80: .seealso: `PetscDrawBar`, `PetscDrawBarCreate()`, `PetscDrawBarDraw()`
81: @*/
82: PetscErrorCode PetscDrawBarSetData(PetscDrawBar bar, PetscInt bins, const PetscReal data[], const char *const *labels)
83: {
84: PetscFunctionBegin;
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(PETSC_SUCCESS);
96: }
98: /*@C
99: PetscDrawBarDestroy - Frees all space taken up by bar graph data structure.
101: Collective
103: Input Parameter:
104: . bar - The bar graph context
106: Level: intermediate
108: .seealso: `PetscDrawBar`, `PetscDrawBarCreate()`
109: @*/
110: PetscErrorCode PetscDrawBarDestroy(PetscDrawBar *bar)
111: {
112: PetscFunctionBegin;
113: if (!*bar) PetscFunctionReturn(PETSC_SUCCESS);
115: if (--((PetscObject)*bar)->refct > 0) PetscFunctionReturn(PETSC_SUCCESS);
117: PetscCall(PetscFree((*bar)->values));
118: PetscCall(PetscStrArrayDestroy(&(*bar)->labels));
119: PetscCall(PetscDrawAxisDestroy(&(*bar)->axis));
120: PetscCall(PetscDrawDestroy(&(*bar)->win));
121: PetscCall(PetscHeaderDestroy(bar));
122: PetscFunctionReturn(PETSC_SUCCESS);
123: }
125: /*@
126: PetscDrawBarDraw - Redraws a bar graph.
128: Collective
130: Input Parameter:
131: . bar - The bar graph context
133: Level: intermediate
135: .seealso: `PetscDrawBar`, `PetscDrawBarCreate()`, `PetscDrawBarSetData()`
136: @*/
137: PetscErrorCode PetscDrawBarDraw(PetscDrawBar bar)
138: {
139: PetscDraw draw;
140: PetscBool isnull;
141: PetscReal xmin, xmax, ymin, ymax, *values, binLeft, binRight;
142: PetscInt numValues, i, bcolor, color, idx, *perm, nplot;
143: PetscMPIInt rank;
144: char **labels;
146: PetscFunctionBegin;
148: PetscCall(PetscDrawIsNull(bar->win, &isnull));
149: if (isnull) PetscFunctionReturn(PETSC_SUCCESS);
150: PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)bar), &rank));
152: if (bar->numBins < 1) PetscFunctionReturn(PETSC_SUCCESS);
154: color = bar->color;
155: if (color == PETSC_DRAW_ROTATE) bcolor = PETSC_DRAW_BLACK + 1;
156: else bcolor = color;
158: numValues = bar->numBins;
159: values = bar->values;
160: if (bar->ymin == bar->ymax) {
161: /* user has not set bounds on bars so set them based on the data */
162: ymin = PETSC_MAX_REAL;
163: ymax = PETSC_MIN_REAL;
164: for (i = 0; i < numValues; i++) {
165: ymin = PetscMin(ymin, values[i]);
166: ymax = PetscMax(ymax, values[i]);
167: }
168: } else {
169: ymin = bar->ymin;
170: ymax = bar->ymax;
171: }
172: nplot = numValues; /* number of points to actually plot; if some are lower than requested tolerance */
173: xmin = 0.0;
174: xmax = nplot;
175: labels = bar->labels;
177: if (bar->sort) {
178: PetscCall(PetscMalloc1(numValues, &perm));
179: for (i = 0; i < numValues; i++) perm[i] = i;
180: PetscCall(PetscSortRealWithPermutation(numValues, values, perm));
181: if (bar->sorttolerance) {
182: for (i = 0; i < numValues; i++) {
183: if (values[perm[numValues - i - 1]] < bar->sorttolerance) {
184: nplot = i;
185: break;
186: }
187: }
188: }
189: }
191: draw = bar->win;
192: PetscCall(PetscDrawCheckResizedWindow(draw));
193: PetscCall(PetscDrawClear(draw));
195: PetscCall(PetscDrawAxisSetLimits(bar->axis, xmin, xmax, ymin, ymax));
196: PetscCall(PetscDrawAxisDraw(bar->axis));
198: PetscDrawCollectiveBegin(draw);
199: if (rank == 0) { /* Draw bins */
200: for (i = 0; i < nplot; i++) {
201: idx = (bar->sort ? perm[numValues - i - 1] : i);
202: binLeft = xmin + i;
203: binRight = xmin + i + 1;
204: PetscCall(PetscDrawRectangle(draw, binLeft, ymin, binRight, values[idx], bcolor, bcolor, bcolor, bcolor));
205: PetscCall(PetscDrawLine(draw, binLeft, ymin, binLeft, values[idx], PETSC_DRAW_BLACK));
206: PetscCall(PetscDrawLine(draw, binRight, ymin, binRight, values[idx], PETSC_DRAW_BLACK));
207: PetscCall(PetscDrawLine(draw, binLeft, values[idx], binRight, values[idx], PETSC_DRAW_BLACK));
208: if (labels) {
209: PetscReal h;
210: PetscCall(PetscDrawStringGetSize(draw, NULL, &h));
211: PetscCall(PetscDrawStringCentered(draw, .5 * (binLeft + binRight), ymin - 1.5 * h, bcolor, labels[idx]));
212: }
213: if (color == PETSC_DRAW_ROTATE) bcolor++;
214: if (bcolor > PETSC_DRAW_BASIC_COLORS - 1) bcolor = PETSC_DRAW_BLACK + 1;
215: }
216: }
217: PetscDrawCollectiveEnd(draw);
218: if (bar->sort) PetscCall(PetscFree(perm));
220: PetscCall(PetscDrawFlush(draw));
221: PetscCall(PetscDrawPause(draw));
222: PetscFunctionReturn(PETSC_SUCCESS);
223: }
225: /*@
226: PetscDrawBarSave - Saves a drawn bar graph
228: Collective
230: Input Parameter:
231: . bar - The bar graph context
233: Level: intermediate
235: .seealso: `PetscDrawSave()`, `PetscDrawBar`, `PetscDrawBarCreate()`, `PetscDrawBarGetDraw()`, `PetscDrawSetSave()`, `PetscDrawBarSetData()`
236: @*/
237: PetscErrorCode PetscDrawBarSave(PetscDrawBar bar)
238: {
239: PetscFunctionBegin;
241: PetscCall(PetscDrawSave(bar->win));
242: PetscFunctionReturn(PETSC_SUCCESS);
243: }
245: /*@
246: PetscDrawBarSetColor - Sets the color the bars will be drawn with.
248: Logically Collective
250: Input Parameters:
251: + bar - The bar graph context
252: - color - one of the colors defined in petscdraw.h or `PETSC_DRAW_ROTATE` to make each bar a
253: different color
255: Level: intermediate
257: .seealso: `PetscDrawBarCreate()`, `PetscDrawBar`, `PetscDrawBarSetData()`, `PetscDrawBarDraw()`, `PetscDrawBarGetAxis()`
258: @*/
259: PetscErrorCode PetscDrawBarSetColor(PetscDrawBar bar, int color)
260: {
261: PetscFunctionBegin;
263: bar->color = color;
264: PetscFunctionReturn(PETSC_SUCCESS);
265: }
267: /*@
268: PetscDrawBarSort - Sorts the values before drawing the bar chart, the bars will be in ascending order from left to right
270: Logically Collective
272: Input Parameters:
273: + bar - The bar graph context
274: . sort - `PETSC_TRUE` to sort the values
275: - tolerance - discard values less than tolerance
277: Level: intermediate
279: .seealso: `PetscDrawBar`, `PetscDrawBarCreate()`, `PetscDrawBarSetData()`, `PetscDrawBarSetColor()`, `PetscDrawBarDraw()`, `PetscDrawBarGetAxis()`
280: @*/
281: PetscErrorCode PetscDrawBarSort(PetscDrawBar bar, PetscBool sort, PetscReal tolerance)
282: {
283: PetscFunctionBegin;
285: bar->sort = sort;
286: bar->sorttolerance = tolerance;
287: PetscFunctionReturn(PETSC_SUCCESS);
288: }
290: /*@
291: PetscDrawBarSetLimits - Sets the axis limits for a bar graph. If more
292: points are added after this call, the limits will be adjusted to
293: include those additional points.
295: Logically Collective
297: Input Parameters:
298: + bar - The bar graph context
299: . y_min - The lower limit
300: - y_max - The upper limit
302: Level: intermediate
304: .seealso: `PetscDrawBar`, `PetscDrawBarCreate()`, `PetscDrawBarGetAxis()`, `PetscDrawBarSetData()`, `PetscDrawBarDraw()`
305: @*/
306: PetscErrorCode PetscDrawBarSetLimits(PetscDrawBar bar, PetscReal y_min, PetscReal y_max)
307: {
308: PetscFunctionBegin;
310: bar->ymin = y_min;
311: bar->ymax = y_max;
312: PetscFunctionReturn(PETSC_SUCCESS);
313: }
315: /*@C
316: PetscDrawBarGetAxis - Gets the axis context associated with a bar graph.
317: This is useful if one wants to change some axis property, such as
318: labels, color, etc. The axis context should not be destroyed by the
319: application code.
321: Not Collective, axis is parallel if bar is parallel
323: Input Parameter:
324: . bar - The bar graph context
326: Output Parameter:
327: . axis - The axis context
329: Level: intermediate
331: .seealso: `PetscDrawBar`, `PetscDrawBarCreate()`, `PetscDrawAxis`, `PetscDrawAxisCreate()`
332: @*/
333: PetscErrorCode PetscDrawBarGetAxis(PetscDrawBar bar, PetscDrawAxis *axis)
334: {
335: PetscFunctionBegin;
337: PetscAssertPointer(axis, 2);
338: *axis = bar->axis;
339: PetscFunctionReturn(PETSC_SUCCESS);
340: }
342: /*@C
343: PetscDrawBarGetDraw - Gets the draw context associated with a bar graph.
345: Not Collective, draw is parallel if bar is parallel
347: Input Parameter:
348: . bar - The bar graph context
350: Output Parameter:
351: . draw - The draw context
353: Level: intermediate
355: .seealso: `PetscDrawBar`, `PetscDraw`, `PetscDrawBarCreate()`, `PetscDrawBarDraw()`
356: @*/
357: PetscErrorCode PetscDrawBarGetDraw(PetscDrawBar bar, PetscDraw *draw)
358: {
359: PetscFunctionBegin;
361: PetscAssertPointer(draw, 2);
362: *draw = bar->win;
363: PetscFunctionReturn(PETSC_SUCCESS);
364: }
366: /*@
367: PetscDrawBarSetFromOptions - Sets options related to the display of the `PetscDrawBar`
369: Collective
371: Input Parameter:
372: . bar - the bar graph context
374: Options Database Key:
375: . -bar_sort - sort the entries before drawing the bar graph
377: Level: intermediate
379: Note:
380: Does not set options related to the underlying `PetscDraw` or `PetscDrawAxis`
382: .seealso: `PetscDrawBar`, `PetscDrawBarDestroy()`, `PetscDrawBarCreate()`, `PetscDrawBarSort()`
383: @*/
384: PetscErrorCode PetscDrawBarSetFromOptions(PetscDrawBar bar)
385: {
386: PetscBool set;
388: PetscFunctionBegin;
391: PetscCall(PetscOptionsHasName(((PetscObject)bar)->options, ((PetscObject)bar)->prefix, "-bar_sort", &set));
392: if (set) {
393: PetscReal tol = bar->sorttolerance;
394: PetscCall(PetscOptionsGetReal(((PetscObject)bar)->options, ((PetscObject)bar)->prefix, "-bar_sort", &tol, NULL));
395: PetscCall(PetscDrawBarSort(bar, PETSC_TRUE, tol));
396: }
397: PetscFunctionReturn(PETSC_SUCCESS);
398: }