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: }
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: }
93: /*@
94: PetscDrawBarDestroy - Frees all space taken up by bar graph data structure.
96: Collective
98: Input Parameter:
99: . bar - The bar graph context
101: Level: intermediate
103: .seealso: `PetscDrawBar`, `PetscDrawBarCreate()`
104: @*/
105: PetscErrorCode PetscDrawBarDestroy(PetscDrawBar *bar)
106: {
107: PetscFunctionBegin;
108: if (!*bar) PetscFunctionReturn(PETSC_SUCCESS);
110: if (--((PetscObject)*bar)->refct > 0) PetscFunctionReturn(PETSC_SUCCESS);
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: }
120: /*@
121: PetscDrawBarDraw - Redraws a bar graph.
123: Collective
125: Input Parameter:
126: . bar - The bar graph context
128: Level: intermediate
130: .seealso: `PetscDrawBar`, `PetscDrawBarCreate()`, `PetscDrawBarSetData()`
131: @*/
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;
142: PetscFunctionBegin;
144: PetscCall(PetscDrawIsNull(bar->win, &isnull));
145: if (isnull) PetscFunctionReturn(PETSC_SUCCESS);
146: PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)bar), &rank));
148: if (bar->numBins < 1) PetscFunctionReturn(PETSC_SUCCESS);
150: color = bar->color;
151: if (color == PETSC_DRAW_ROTATE) bcolor = PETSC_DRAW_BLACK + 1;
152: else bcolor = color;
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;
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: }
187: draw = bar->win;
188: PetscCall(PetscDrawCheckResizedWindow(draw));
189: PetscCall(PetscDrawClear(draw));
191: PetscCall(PetscDrawAxisSetLimits(bar->axis, xmin, xmax, ymin, ymax));
192: PetscCall(PetscDrawAxisDraw(bar->axis));
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;
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));
217: PetscCall(PetscDrawFlush(draw));
218: PetscCall(PetscDrawPause(draw));
219: PetscFunctionReturn(PETSC_SUCCESS);
220: }
222: /*@
223: PetscDrawBarSave - Saves a drawn bar graph
225: Collective
227: Input Parameter:
228: . bar - The bar graph context
230: Level: intermediate
232: .seealso: `PetscDrawSave()`, `PetscDrawBar`, `PetscDrawBarCreate()`, `PetscDrawBarGetDraw()`, `PetscDrawSetSave()`, `PetscDrawBarSetData()`
233: @*/
234: PetscErrorCode PetscDrawBarSave(PetscDrawBar bar)
235: {
236: PetscFunctionBegin;
238: PetscCall(PetscDrawSave(bar->win));
239: PetscFunctionReturn(PETSC_SUCCESS);
240: }
242: /*@
243: PetscDrawBarSetColor - Sets the color the bars will be drawn with.
245: Logically Collective
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
252: Level: intermediate
254: .seealso: `PetscDrawBarCreate()`, `PetscDrawBar`, `PetscDrawBarSetData()`, `PetscDrawBarDraw()`, `PetscDrawBarGetAxis()`
255: @*/
256: PetscErrorCode PetscDrawBarSetColor(PetscDrawBar bar, int color)
257: {
258: PetscFunctionBegin;
260: bar->color = color;
261: PetscFunctionReturn(PETSC_SUCCESS);
262: }
264: /*@
265: PetscDrawBarSort - Sorts the values before drawing the bar chart, the bars will be in ascending order from left to right
267: Logically Collective
269: Input Parameters:
270: + bar - The bar graph context
271: . sort - `PETSC_TRUE` to sort the values
272: - tolerance - discard values less than tolerance
274: Level: intermediate
276: .seealso: `PetscDrawBar`, `PetscDrawBarCreate()`, `PetscDrawBarSetData()`, `PetscDrawBarSetColor()`, `PetscDrawBarDraw()`, `PetscDrawBarGetAxis()`
277: @*/
278: PetscErrorCode PetscDrawBarSort(PetscDrawBar bar, PetscBool sort, PetscReal tolerance)
279: {
280: PetscFunctionBegin;
282: bar->sort = sort;
283: bar->sorttolerance = tolerance;
284: PetscFunctionReturn(PETSC_SUCCESS);
285: }
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.
292: Logically Collective
294: Input Parameters:
295: + bar - The bar graph context
296: . y_min - The lower limit
297: - y_max - The upper limit
299: Level: intermediate
301: .seealso: `PetscDrawBar`, `PetscDrawBarCreate()`, `PetscDrawBarGetAxis()`, `PetscDrawBarSetData()`, `PetscDrawBarDraw()`
302: @*/
303: PetscErrorCode PetscDrawBarSetLimits(PetscDrawBar bar, PetscReal y_min, PetscReal y_max)
304: {
305: PetscFunctionBegin;
307: bar->ymin = y_min;
308: bar->ymax = y_max;
309: PetscFunctionReturn(PETSC_SUCCESS);
310: }
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.
318: Not Collective, axis is parallel if bar is parallel
320: Input Parameter:
321: . bar - The bar graph context
323: Output Parameter:
324: . axis - The axis context
326: Level: intermediate
328: .seealso: `PetscDrawBar`, `PetscDrawBarCreate()`, `PetscDrawAxis`, `PetscDrawAxisCreate()`
329: @*/
330: PetscErrorCode PetscDrawBarGetAxis(PetscDrawBar bar, PetscDrawAxis *axis)
331: {
332: PetscFunctionBegin;
334: PetscAssertPointer(axis, 2);
335: *axis = bar->axis;
336: PetscFunctionReturn(PETSC_SUCCESS);
337: }
339: /*@
340: PetscDrawBarGetDraw - Gets the draw context associated with a bar graph.
342: Not Collective, draw is parallel if bar is parallel
344: Input Parameter:
345: . bar - The bar graph context
347: Output Parameter:
348: . draw - The draw context
350: Level: intermediate
352: .seealso: `PetscDrawBar`, `PetscDraw`, `PetscDrawBarCreate()`, `PetscDrawBarDraw()`
353: @*/
354: PetscErrorCode PetscDrawBarGetDraw(PetscDrawBar bar, PetscDraw *draw)
355: {
356: PetscFunctionBegin;
358: PetscAssertPointer(draw, 2);
359: *draw = bar->win;
360: PetscFunctionReturn(PETSC_SUCCESS);
361: }
363: /*@
364: PetscDrawBarSetFromOptions - Sets options related to the display of the `PetscDrawBar`
366: Collective
368: Input Parameter:
369: . bar - the bar graph context
371: Options Database Key:
372: . -bar_sort - sort the entries before drawing the bar graph
374: Level: intermediate
376: Note:
377: Does not set options related to the underlying `PetscDraw` or `PetscDrawAxis`
379: .seealso: `PetscDrawBar`, `PetscDrawBarDestroy()`, `PetscDrawBarCreate()`, `PetscDrawBarSort()`
380: @*/
381: PetscErrorCode PetscDrawBarSetFromOptions(PetscDrawBar bar)
382: {
383: PetscBool set;
385: PetscFunctionBegin;
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: }