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: /*@C
 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));

 45:   PetscCall(PetscObjectReference((PetscObject)draw));
 46:   h->win = draw;

 48:   h->view    = NULL;
 49:   h->destroy = NULL;
 50:   h->color   = PETSC_DRAW_GREEN;
 51:   h->ymin    = 0.; /* if user has not set these then they are determined from the data */
 52:   h->ymax    = 0.;
 53:   h->numBins = 0;

 55:   PetscCall(PetscDrawAxisCreate(draw, &h->axis));
 56:   h->axis->xticks = NULL;

 58:   *bar = h;
 59:   PetscFunctionReturn(PETSC_SUCCESS);
 60: }

 62: /*@C
 63:   PetscDrawBarSetData - Set the data for a bar graph

 65:   Logically Collective

 67:   Input Parameters:
 68: + bar    - The bar graph context.
 69: . bins   - number of items
 70: . data   - values of each item
 71: - labels - optional label for each bar, NULL terminated array of strings

 73:   Level: intermediate

 75:   Notes:
 76:   Call `PetscDrawBarDraw()` after this call to display the new plot

 78:   The data is ignored on all ranks except zero

 80: .seealso: `PetscDrawBar`, `PetscDrawBarCreate()`, `PetscDrawBarDraw()`
 81: @*/
 82: PetscErrorCode PetscDrawBarSetData(PetscDrawBar bar, PetscInt bins, const PetscReal data[], const char *const *labels)
 83: {
 84:   PetscFunctionBegin;

 87:   if (bar->numBins != bins) {
 88:     PetscCall(PetscFree(bar->values));
 89:     PetscCall(PetscMalloc1(bins, &bar->values));
 90:     bar->numBins = bins;
 91:   }
 92:   PetscCall(PetscArraycpy(bar->values, data, bins));
 93:   bar->numBins = bins;
 94:   if (labels) PetscCall(PetscStrArrayallocpy(labels, &bar->labels));
 95:   PetscFunctionReturn(PETSC_SUCCESS);
 96: }

 98: /*@C
 99:   PetscDrawBarDestroy - Frees all space taken up by bar graph data structure.

101:   Collective

103:   Input Parameter:
104: . bar - The bar graph context

106:   Level: intermediate

108: .seealso: `PetscDrawBar`, `PetscDrawBarCreate()`
109: @*/
110: PetscErrorCode PetscDrawBarDestroy(PetscDrawBar *bar)
111: {
112:   PetscFunctionBegin;
113:   if (!*bar) PetscFunctionReturn(PETSC_SUCCESS);
115:   if (--((PetscObject)(*bar))->refct > 0) PetscFunctionReturn(PETSC_SUCCESS);

117:   PetscCall(PetscFree((*bar)->values));
118:   PetscCall(PetscStrArrayDestroy(&(*bar)->labels));
119:   PetscCall(PetscDrawAxisDestroy(&(*bar)->axis));
120:   PetscCall(PetscDrawDestroy(&(*bar)->win));
121:   PetscCall(PetscHeaderDestroy(bar));
122:   PetscFunctionReturn(PETSC_SUCCESS);
123: }

125: /*@
126:   PetscDrawBarDraw - Redraws a bar graph.

128:   Collective

130:   Input Parameter:
131: . bar - The bar graph context

133:   Level: intermediate

135: .seealso: `PetscDrawBar`, `PetscDrawBarCreate()`, `PetscDrawBarSetData()`
136: @*/
137: PetscErrorCode PetscDrawBarDraw(PetscDrawBar bar)
138: {
139:   PetscDraw   draw;
140:   PetscBool   isnull;
141:   PetscReal   xmin, xmax, ymin, ymax, *values, binLeft, binRight;
142:   PetscInt    numValues, i, bcolor, color, idx, *perm, nplot;
143:   PetscMPIInt rank;
144:   char      **labels;

146:   PetscFunctionBegin;
148:   PetscCall(PetscDrawIsNull(bar->win, &isnull));
149:   if (isnull) PetscFunctionReturn(PETSC_SUCCESS);
150:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)bar), &rank));

152:   if (bar->numBins < 1) PetscFunctionReturn(PETSC_SUCCESS);

154:   color = bar->color;
155:   if (color == PETSC_DRAW_ROTATE) bcolor = PETSC_DRAW_BLACK + 1;
156:   else bcolor = color;

158:   numValues = bar->numBins;
159:   values    = bar->values;
160:   if (bar->ymin == bar->ymax) {
161:     /* user has not set bounds on bars so set them based on the data */
162:     ymin = PETSC_MAX_REAL;
163:     ymax = PETSC_MIN_REAL;
164:     for (i = 0; i < numValues; i++) {
165:       ymin = PetscMin(ymin, values[i]);
166:       ymax = PetscMax(ymax, values[i]);
167:     }
168:   } else {
169:     ymin = bar->ymin;
170:     ymax = bar->ymax;
171:   }
172:   nplot  = numValues; /* number of points to actually plot; if some are lower than requested tolerance */
173:   xmin   = 0.0;
174:   xmax   = nplot;
175:   labels = bar->labels;

177:   if (bar->sort) {
178:     PetscCall(PetscMalloc1(numValues, &perm));
179:     for (i = 0; i < numValues; i++) perm[i] = i;
180:     PetscCall(PetscSortRealWithPermutation(numValues, values, perm));
181:     if (bar->sorttolerance) {
182:       for (i = 0; i < numValues; i++) {
183:         if (values[perm[numValues - i - 1]] < bar->sorttolerance) {
184:           nplot = i;
185:           break;
186:         }
187:       }
188:     }
189:   }

191:   draw = bar->win;
192:   PetscCall(PetscDrawCheckResizedWindow(draw));
193:   PetscCall(PetscDrawClear(draw));

195:   PetscCall(PetscDrawAxisSetLimits(bar->axis, xmin, xmax, ymin, ymax));
196:   PetscCall(PetscDrawAxisDraw(bar->axis));

198:   PetscDrawCollectiveBegin(draw);
199:   if (rank == 0) { /* Draw bins */
200:     for (i = 0; i < nplot; i++) {
201:       idx      = (bar->sort ? perm[numValues - i - 1] : i);
202:       binLeft  = xmin + i;
203:       binRight = xmin + i + 1;
204:       PetscCall(PetscDrawRectangle(draw, binLeft, ymin, binRight, values[idx], bcolor, bcolor, bcolor, bcolor));
205:       PetscCall(PetscDrawLine(draw, binLeft, ymin, binLeft, values[idx], PETSC_DRAW_BLACK));
206:       PetscCall(PetscDrawLine(draw, binRight, ymin, binRight, values[idx], PETSC_DRAW_BLACK));
207:       PetscCall(PetscDrawLine(draw, binLeft, values[idx], binRight, values[idx], PETSC_DRAW_BLACK));
208:       if (labels) {
209:         PetscReal h;
210:         PetscCall(PetscDrawStringGetSize(draw, NULL, &h));
211:         PetscCall(PetscDrawStringCentered(draw, .5 * (binLeft + binRight), ymin - 1.5 * h, bcolor, labels[idx]));
212:       }
213:       if (color == PETSC_DRAW_ROTATE) bcolor++;
214:       if (bcolor > PETSC_DRAW_BASIC_COLORS - 1) bcolor = PETSC_DRAW_BLACK + 1;
215:     }
216:   }
217:   PetscDrawCollectiveEnd(draw);
218:   if (bar->sort) PetscCall(PetscFree(perm));

220:   PetscCall(PetscDrawFlush(draw));
221:   PetscCall(PetscDrawPause(draw));
222:   PetscFunctionReturn(PETSC_SUCCESS);
223: }

225: /*@
226:   PetscDrawBarSave - Saves a drawn bar graph

228:   Collective

230:   Input Parameter:
231: . bar - The bar graph context

233:   Level: intermediate

235: .seealso: `PetscDrawSave()`, `PetscDrawBar`, `PetscDrawBarCreate()`, `PetscDrawBarGetDraw()`, `PetscDrawSetSave()`, `PetscDrawBarSetData()`
236: @*/
237: PetscErrorCode PetscDrawBarSave(PetscDrawBar bar)
238: {
239:   PetscFunctionBegin;
241:   PetscCall(PetscDrawSave(bar->win));
242:   PetscFunctionReturn(PETSC_SUCCESS);
243: }

245: /*@
246:   PetscDrawBarSetColor - Sets the color the bars will be drawn with.

248:   Logically Collective

250:   Input Parameters:
251: + bar   - The bar graph context
252: - color - one of the colors defined in petscdraw.h or `PETSC_DRAW_ROTATE` to make each bar a
253:           different color

255:   Level: intermediate

257: .seealso: `PetscDrawBarCreate()`, `PetscDrawBar`, `PetscDrawBarSetData()`, `PetscDrawBarDraw()`, `PetscDrawBarGetAxis()`
258: @*/
259: PetscErrorCode PetscDrawBarSetColor(PetscDrawBar bar, int color)
260: {
261:   PetscFunctionBegin;
263:   bar->color = color;
264:   PetscFunctionReturn(PETSC_SUCCESS);
265: }

267: /*@
268:   PetscDrawBarSort - Sorts the values before drawing the bar chart, the bars will be in ascending order from left to right

270:   Logically Collective

272:   Input Parameters:
273: + bar       - The bar graph context
274: . sort      - `PETSC_TRUE` to sort the values
275: - tolerance - discard values less than tolerance

277:   Level: intermediate

279: .seealso: `PetscDrawBar`, `PetscDrawBarCreate()`, `PetscDrawBarSetData()`, `PetscDrawBarSetColor()`, `PetscDrawBarDraw()`, `PetscDrawBarGetAxis()`
280: @*/
281: PetscErrorCode PetscDrawBarSort(PetscDrawBar bar, PetscBool sort, PetscReal tolerance)
282: {
283:   PetscFunctionBegin;
285:   bar->sort          = sort;
286:   bar->sorttolerance = tolerance;
287:   PetscFunctionReturn(PETSC_SUCCESS);
288: }

290: /*@
291:   PetscDrawBarSetLimits - Sets the axis limits for a bar graph. If more
292:   points are added after this call, the limits will be adjusted to
293:   include those additional points.

295:   Logically Collective

297:   Input Parameters:
298: + bar   - The bar graph context
299: . y_min - The lower limit
300: - y_max - The upper limit

302:   Level: intermediate

304: .seealso: `PetscDrawBar`, `PetscDrawBarCreate()`, `PetscDrawBarGetAxis()`, `PetscDrawBarSetData()`, `PetscDrawBarDraw()`
305: @*/
306: PetscErrorCode PetscDrawBarSetLimits(PetscDrawBar bar, PetscReal y_min, PetscReal y_max)
307: {
308:   PetscFunctionBegin;
310:   bar->ymin = y_min;
311:   bar->ymax = y_max;
312:   PetscFunctionReturn(PETSC_SUCCESS);
313: }

315: /*@C
316:   PetscDrawBarGetAxis - Gets the axis context associated with a bar graph.
317:   This is useful if one wants to change some axis property, such as
318:   labels, color, etc. The axis context should not be destroyed by the
319:   application code.

321:   Not Collective, axis is parallel if bar is parallel

323:   Input Parameter:
324: . bar - The bar graph context

326:   Output Parameter:
327: . axis - The axis context

329:   Level: intermediate

331: .seealso: `PetscDrawBar`, `PetscDrawBarCreate()`, `PetscDrawAxis`, `PetscDrawAxisCreate()`
332: @*/
333: PetscErrorCode PetscDrawBarGetAxis(PetscDrawBar bar, PetscDrawAxis *axis)
334: {
335:   PetscFunctionBegin;
337:   PetscAssertPointer(axis, 2);
338:   *axis = bar->axis;
339:   PetscFunctionReturn(PETSC_SUCCESS);
340: }

342: /*@C
343:   PetscDrawBarGetDraw - Gets the draw context associated with a bar graph.

345:   Not Collective, draw is parallel if bar is parallel

347:   Input Parameter:
348: . bar - The bar graph context

350:   Output Parameter:
351: . draw - The draw context

353:   Level: intermediate

355: .seealso: `PetscDrawBar`, `PetscDraw`, `PetscDrawBarCreate()`, `PetscDrawBarDraw()`
356: @*/
357: PetscErrorCode PetscDrawBarGetDraw(PetscDrawBar bar, PetscDraw *draw)
358: {
359:   PetscFunctionBegin;
361:   PetscAssertPointer(draw, 2);
362:   *draw = bar->win;
363:   PetscFunctionReturn(PETSC_SUCCESS);
364: }

366: /*@
367:   PetscDrawBarSetFromOptions - Sets options related to the display of the `PetscDrawBar`

369:   Collective

371:   Input Parameter:
372: . bar - the bar graph context

374:   Options Database Key:
375: . -bar_sort - sort the entries before drawing the bar graph

377:   Level: intermediate

379:   Note:
380:   Does not set options related to the underlying `PetscDraw` or `PetscDrawAxis`

382: .seealso: `PetscDrawBar`, `PetscDrawBarDestroy()`, `PetscDrawBarCreate()`, `PetscDrawBarSort()`
383: @*/
384: PetscErrorCode PetscDrawBarSetFromOptions(PetscDrawBar bar)
385: {
386:   PetscBool set;

388:   PetscFunctionBegin;

391:   PetscCall(PetscOptionsHasName(((PetscObject)bar)->options, ((PetscObject)bar)->prefix, "-bar_sort", &set));
392:   if (set) {
393:     PetscReal tol = bar->sorttolerance;
394:     PetscCall(PetscOptionsGetReal(((PetscObject)bar)->options, ((PetscObject)bar)->prefix, "-bar_sort", &tol, NULL));
395:     PetscCall(PetscDrawBarSort(bar, PETSC_TRUE, tol));
396:   }
397:   PetscFunctionReturn(PETSC_SUCCESS);
398: }