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: }