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