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