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