Actual source code: bars.c
2: /*
3: Contains the data structure for plotting a bargraph in a window with an axis.
4: */
6: #include <petsc/private/drawimpl.h>
7: #include <petscviewer.h>
9: PetscClassId PETSC_DRAWBAR_CLASSID = 0;
11: /*@C
12: PetscDrawBarCreate - Creates a bar graph data structure.
14: Collective over draw
16: Input Parameter:
17: . draw - The window where the graph will be made
19: Output Parameter:
20: . bar - The bar graph context
22: Notes:
23: Call `PetscDrawBarSetData()` to provide the bins to be plotted and then `PetscDrawBarDraw()` to display the new plot
25: The difference between a bar chart, `PetscDrawBar`, and a histogram, `PetscDrawHG`, is explained here https://stattrek.com/statistics/charts/histogram.aspx?Tutorial=AP
27: 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
28: zeroth MPI rank in the communicator. All MPI ranks in the communicator must call `PetscDrawBarDraw()` to display the updated graph.
30: Level: intermediate
32: .seealso: `PetscDrawBar`, `PetscDrawLGCreate()`, `PetscDrawLG`, `PetscDrawSPCreate()`, `PetscDrawSP`, `PetscDrawHGCreate()`, `PetscDrawHG`, `PetscDrawBarDestroy()`, `PetscDrawBarSetData()`,
33: `PetscDrawBar`, `PetscDrawBarDraw()`, `PetscDrawBarSave()`, `PetscDrawBarSetColor()`, `PetscDrawBarSort()`, `PetscDrawBarSetLimits()`, `PetscDrawBarGetAxis()`, `PetscDrawAxis`,
34: `PetscDrawBarGetDraw()`, `PetscDrawBarSetFromOptions()`
35: @*/
36: PetscErrorCode PetscDrawBarCreate(PetscDraw draw, PetscDrawBar *bar)
37: {
38: PetscDrawBar h;
40: PetscFunctionBegin;
44: PetscCall(PetscHeaderCreate(h, PETSC_DRAWBAR_CLASSID, "DrawBar", "Bar Graph", "Draw", PetscObjectComm((PetscObject)draw), PetscDrawBarDestroy, NULL));
46: PetscCall(PetscObjectReference((PetscObject)draw));
47: h->win = draw;
49: h->view = NULL;
50: h->destroy = NULL;
51: h->color = PETSC_DRAW_GREEN;
52: h->ymin = 0.; /* if user has not set these then they are determined from the data */
53: h->ymax = 0.;
54: h->numBins = 0;
56: PetscCall(PetscDrawAxisCreate(draw, &h->axis));
57: h->axis->xticks = NULL;
59: *bar = h;
60: PetscFunctionReturn(PETSC_SUCCESS);
61: }
63: /*@C
64: PetscDrawBarSetData
66: Logically Collective
68: Input Parameters:
69: + bar - The bar graph context.
70: . bins - number of items
71: . values - values of each item
72: - labels - optional label for each bar, NULL terminated array of strings
74: Level: intermediate
76: Notes:
77: Call `PetscDrawBarDraw()` after this call to display the new plot
79: The data is ignored on all ranks except zero
81: .seealso: `PetscDrawBar`, `PetscDrawBarCreate()`, `PetscDrawBar`, `PetscDrawBarDraw()`
82: @*/
83: PetscErrorCode PetscDrawBarSetData(PetscDrawBar bar, PetscInt bins, const PetscReal data[], const char *const *labels)
84: {
85: PetscFunctionBegin;
88: if (bar->numBins != bins) {
89: PetscCall(PetscFree(bar->values));
90: PetscCall(PetscMalloc1(bins, &bar->values));
91: bar->numBins = bins;
92: }
93: PetscCall(PetscArraycpy(bar->values, data, bins));
94: bar->numBins = bins;
95: if (labels) PetscCall(PetscStrArrayallocpy(labels, &bar->labels));
96: PetscFunctionReturn(PETSC_SUCCESS);
97: }
99: /*@C
100: PetscDrawBarDestroy - Frees all space taken up by bar graph data structure.
102: Collective over bar
104: Input Parameter:
105: . bar - The bar graph context
107: Level: intermediate
109: .seealso: `PetscDrawBar`, `PetscDrawBarCreate()`
110: @*/
111: PetscErrorCode PetscDrawBarDestroy(PetscDrawBar *bar)
112: {
113: PetscFunctionBegin;
114: if (!*bar) PetscFunctionReturn(PETSC_SUCCESS);
116: if (--((PetscObject)(*bar))->refct > 0) PetscFunctionReturn(PETSC_SUCCESS);
118: PetscCall(PetscFree((*bar)->values));
119: PetscCall(PetscStrArrayDestroy(&(*bar)->labels));
120: PetscCall(PetscDrawAxisDestroy(&(*bar)->axis));
121: PetscCall(PetscDrawDestroy(&(*bar)->win));
122: PetscCall(PetscHeaderDestroy(bar));
123: PetscFunctionReturn(PETSC_SUCCESS);
124: }
126: /*@
127: PetscDrawBarDraw - Redraws a bar graph.
129: Collective
131: Input Parameter:
132: . bar - The bar graph context
134: Level: intermediate
136: .seealso: `PetscDrawBar`, `PetscDrawBarCreate()`, `PetscDrawBarSetData()`
137: @*/
138: PetscErrorCode PetscDrawBarDraw(PetscDrawBar bar)
139: {
140: PetscDraw draw;
141: PetscBool isnull;
142: PetscReal xmin, xmax, ymin, ymax, *values, binLeft, binRight;
143: PetscInt numValues, i, bcolor, color, idx, *perm, nplot;
144: PetscMPIInt rank;
145: char **labels;
147: PetscFunctionBegin;
149: PetscCall(PetscDrawIsNull(bar->win, &isnull));
150: if (isnull) PetscFunctionReturn(PETSC_SUCCESS);
151: PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)bar), &rank));
153: if (bar->numBins < 1) PetscFunctionReturn(PETSC_SUCCESS);
155: color = bar->color;
156: if (color == PETSC_DRAW_ROTATE) bcolor = PETSC_DRAW_BLACK + 1;
157: else bcolor = color;
159: numValues = bar->numBins;
160: values = bar->values;
161: if (bar->ymin == bar->ymax) {
162: /* user has not set bounds on bars so set them based on the data */
163: ymin = PETSC_MAX_REAL;
164: ymax = PETSC_MIN_REAL;
165: for (i = 0; i < numValues; i++) {
166: ymin = PetscMin(ymin, values[i]);
167: ymax = PetscMax(ymax, values[i]);
168: }
169: } else {
170: ymin = bar->ymin;
171: ymax = bar->ymax;
172: }
173: nplot = numValues; /* number of points to actually plot; if some are lower than requested tolerance */
174: xmin = 0.0;
175: xmax = nplot;
176: labels = bar->labels;
178: if (bar->sort) {
179: PetscCall(PetscMalloc1(numValues, &perm));
180: for (i = 0; i < numValues; i++) perm[i] = i;
181: PetscCall(PetscSortRealWithPermutation(numValues, values, perm));
182: if (bar->sorttolerance) {
183: for (i = 0; i < numValues; i++) {
184: if (values[perm[numValues - i - 1]] < bar->sorttolerance) {
185: nplot = i;
186: break;
187: }
188: }
189: }
190: }
192: draw = bar->win;
193: PetscCall(PetscDrawCheckResizedWindow(draw));
194: PetscCall(PetscDrawClear(draw));
196: PetscCall(PetscDrawAxisSetLimits(bar->axis, xmin, xmax, ymin, ymax));
197: PetscCall(PetscDrawAxisDraw(bar->axis));
199: PetscDrawCollectiveBegin(draw);
200: if (rank == 0) { /* Draw bins */
201: for (i = 0; i < nplot; i++) {
202: idx = (bar->sort ? perm[numValues - i - 1] : i);
203: binLeft = xmin + i;
204: binRight = xmin + i + 1;
205: PetscCall(PetscDrawRectangle(draw, binLeft, ymin, binRight, values[idx], bcolor, bcolor, bcolor, bcolor));
206: PetscCall(PetscDrawLine(draw, binLeft, ymin, binLeft, values[idx], PETSC_DRAW_BLACK));
207: PetscCall(PetscDrawLine(draw, binRight, ymin, binRight, values[idx], PETSC_DRAW_BLACK));
208: PetscCall(PetscDrawLine(draw, binLeft, values[idx], binRight, values[idx], PETSC_DRAW_BLACK));
209: if (labels) {
210: PetscReal h;
211: PetscCall(PetscDrawStringGetSize(draw, NULL, &h));
212: PetscCall(PetscDrawStringCentered(draw, .5 * (binLeft + binRight), ymin - 1.5 * h, bcolor, labels[idx]));
213: }
214: if (color == PETSC_DRAW_ROTATE) bcolor++;
215: if (bcolor > PETSC_DRAW_BASIC_COLORS - 1) bcolor = PETSC_DRAW_BLACK + 1;
216: }
217: }
218: PetscDrawCollectiveEnd(draw);
219: if (bar->sort) PetscCall(PetscFree(perm));
221: PetscCall(PetscDrawFlush(draw));
222: PetscCall(PetscDrawPause(draw));
223: PetscFunctionReturn(PETSC_SUCCESS);
224: }
226: /*@
227: PetscDrawBarSave - Saves a drawn bar graph
229: Collective
231: Input Parameter:
232: . bar - The bar graph context
234: Level: intermediate
236: .seealso: `PetscDrawSave()`, `PetscDrawBar`, `PetscDrawBarCreate()`, `PetscDrawBarGetDraw()`, `PetscDrawSetSave()`, `PetscDrawSave()`, `PetscDrawBarSetData()`
237: @*/
238: PetscErrorCode PetscDrawBarSave(PetscDrawBar bar)
239: {
240: PetscFunctionBegin;
242: PetscCall(PetscDrawSave(bar->win));
243: PetscFunctionReturn(PETSC_SUCCESS);
244: }
246: /*@
247: PetscDrawBarSetColor - Sets the color the bars will be drawn with.
249: Logically Collective
251: Input Parameters:
252: + bar - The bar graph context
253: - color - one of the colors defined in petscdraw.h or `PETSC_DRAW_ROTATE` to make each bar a
254: different color
256: Level: intermediate
258: .seealso: `PetscDrawBarCreate()`, `PetscDrawBar`, `PetscDrawBarSetData()`, `PetscDrawBarDraw()`, `PetscDrawBarGetAxis()`
259: @*/
260: PetscErrorCode PetscDrawBarSetColor(PetscDrawBar bar, int color)
261: {
262: PetscFunctionBegin;
264: bar->color = color;
265: PetscFunctionReturn(PETSC_SUCCESS);
266: }
268: /*@
269: PetscDrawBarSort - Sorts the values before drawing the bar chart, the bars will be in ascending order from left to right
271: Logically Collective
273: Input Parameters:
274: + bar - The bar graph context
275: . sort - `PETSC_TRUE` to sort the values
276: - tolerance - discard values less than tolerance
278: Level: intermediate
280: .seealso: `PetscDrawBar`, `PetscDrawBarCreate()`, `PetscDrawBar`, `PetscDrawBarSetData()`, `PetscDrawBarSetColor()`, `PetscDrawBarDraw()`, `PetscDrawBarGetAxis()`
281: @*/
282: PetscErrorCode PetscDrawBarSort(PetscDrawBar bar, PetscBool sort, PetscReal tolerance)
283: {
284: PetscFunctionBegin;
286: bar->sort = sort;
287: bar->sorttolerance = tolerance;
288: PetscFunctionReturn(PETSC_SUCCESS);
289: }
291: /*@
292: PetscDrawBarSetLimits - Sets the axis limits for a bar graph. If more
293: points are added after this call, the limits will be adjusted to
294: include those additional points.
296: Logically Collective
298: Input Parameters:
299: + bar - The bar graph context
300: . y_min - The lower limit
301: - y_max - The upper limit
303: Level: intermediate
305: .seealso: `PetscDrawBar`, `PetscDrawBarCreate()`, `PetscDrawBar`, `PetscDrawBarGetAxis()`, `PetscDrawBarSetData()`, `PetscDrawBarDraw()`
306: @*/
307: PetscErrorCode PetscDrawBarSetLimits(PetscDrawBar bar, PetscReal y_min, PetscReal y_max)
308: {
309: PetscFunctionBegin;
311: bar->ymin = y_min;
312: bar->ymax = y_max;
313: PetscFunctionReturn(PETSC_SUCCESS);
314: }
316: /*@C
317: PetscDrawBarGetAxis - Gets the axis context associated with a bar graph.
318: This is useful if one wants to change some axis property, such as
319: labels, color, etc. The axis context should not be destroyed by the
320: application code.
322: Not Collective, axis is parallel if bar is parallel
324: Input Parameter:
325: . bar - The bar graph context
327: Output Parameter:
328: . axis - The axis context
330: Level: intermediate
332: .seealso: `PetscDrawBar`, `PetscDrawBarCreate()`, `PetscDrawBar`, `PetscDrawAxis`, `PetscDrawAxisCreate()`
333: @*/
334: PetscErrorCode PetscDrawBarGetAxis(PetscDrawBar bar, PetscDrawAxis *axis)
335: {
336: PetscFunctionBegin;
339: *axis = bar->axis;
340: PetscFunctionReturn(PETSC_SUCCESS);
341: }
343: /*@C
344: PetscDrawBarGetDraw - Gets the draw context associated with a bar graph.
346: Not Collective, draw is parallel if bar is parallel
348: Input Parameter:
349: . bar - The bar graph context
351: Output Parameter:
352: . draw - The draw context
354: Level: intermediate
356: .seealso: `PetscDrawBar`, `PetscDraw`, `PetscDrawBarCreate()`, `PetscDrawBar`, `PetscDrawBarDraw()`, `PetscDraw`
357: @*/
358: PetscErrorCode PetscDrawBarGetDraw(PetscDrawBar bar, PetscDraw *draw)
359: {
360: PetscFunctionBegin;
363: *draw = bar->win;
364: PetscFunctionReturn(PETSC_SUCCESS);
365: }
367: /*@
368: PetscDrawBarSetFromOptions - Sets options related to the display of the `PetscDrawBar`
370: Collective over bar
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: }