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