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 Parameters:
 17: .  draw  - The window where the graph will be made

 19:    Output Parameters:
 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;


 43:   PetscHeaderCreate(h, PETSC_DRAWBAR_CLASSID, "DrawBar", "Bar Graph", "Draw", PetscObjectComm((PetscObject)draw), PetscDrawBarDestroy, NULL);

 45:   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:   PetscDrawAxisCreate(draw, &h->axis);
 56:   h->axis->xticks = NULL;

 58:   *bar = h;
 59:   return 0;
 60: }

 62: /*@C
 63:    PetscDrawBarSetData

 65:    Logically Collective

 67:    Input Parameters:
 68: +  bar - The bar graph context.
 69: .  bins  - number of items
 70: .  values - 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()`, `PetscDrawBar`, `PetscDrawBarDraw()`
 81: @*/
 82: PetscErrorCode PetscDrawBarSetData(PetscDrawBar bar, PetscInt bins, const PetscReal data[], const char *const *labels)
 83: {

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

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

100:   Collective over bar

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

105:   Level: intermediate

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

115:   PetscFree((*bar)->values);
116:   PetscStrArrayDestroy(&(*bar)->labels);
117:   PetscDrawAxisDestroy(&(*bar)->axis);
118:   PetscDrawDestroy(&(*bar)->win);
119:   PetscHeaderDestroy(bar);
120:   return 0;
121: }

123: /*@
124:   PetscDrawBarDraw - Redraws a bar graph.

126:   Collective

128:   Input Parameter:
129: . bar - The bar graph context

131:   Level: intermediate

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

145:   PetscDrawIsNull(bar->win, &isnull);
146:   if (isnull) return 0;
147:   MPI_Comm_rank(PetscObjectComm((PetscObject)bar), &rank);

149:   if (bar->numBins < 1) return 0;

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   = nplot;
172:   labels = bar->labels;

174:   if (bar->sort) {
175:     PetscMalloc1(numValues, &perm);
176:     for (i = 0; i < numValues; i++) perm[i] = i;
177:     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:   PetscDrawCheckResizedWindow(draw);
190:   PetscDrawClear(draw);

192:   PetscDrawAxisSetLimits(bar->axis, xmin, xmax, ymin, ymax);
193:   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 + i;
200:       binRight = xmin + i + 1;
201:       PetscDrawRectangle(draw, binLeft, ymin, binRight, values[idx], bcolor, bcolor, bcolor, bcolor);
202:       PetscDrawLine(draw, binLeft, ymin, binLeft, values[idx], PETSC_DRAW_BLACK);
203:       PetscDrawLine(draw, binRight, ymin, binRight, values[idx], PETSC_DRAW_BLACK);
204:       PetscDrawLine(draw, binLeft, values[idx], binRight, values[idx], PETSC_DRAW_BLACK);
205:       if (labels) {
206:         PetscReal h;
207:         PetscDrawStringGetSize(draw, NULL, &h);
208:         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) PetscFree(perm);

217:   PetscDrawFlush(draw);
218:   PetscDrawPause(draw);
219:   return 0;
220: }

222: /*@
223:   PetscDrawBarSave - Saves a drawn bar graph

225:   Collective

227:   Input Parameters:
228: . bar - The bar graph context

230:   Level: intermediate

232: .seealso: `PetscDrawSave()`, `PetscDrawBar`, `PetscDrawBarCreate()`, `PetscDrawBarGetDraw()`, `PetscDrawSetSave()`, `PetscDrawSave()`, `PetscDrawBarSetData()`
233: @*/
234: PetscErrorCode PetscDrawBarSave(PetscDrawBar bar)
235: {
237:   PetscDrawSave(bar->win);
238:   return 0;
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: {
258:   bar->color = color;
259:   return 0;
260: }

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

265:   Logically Collective

267:   Input Parameters:
268: + bar - The bar graph context
269: . sort - `PETSC_TRUE` to sort the values
270: - tolerance - discard values less than tolerance

272:   Level: intermediate

274: .seealso: `PetscDrawBar`, `PetscDrawBarCreate()`, `PetscDrawBar`, `PetscDrawBarSetData()`, `PetscDrawBarSetColor()`, `PetscDrawBarDraw()`, `PetscDrawBarGetAxis()`
275: @*/
276: PetscErrorCode PetscDrawBarSort(PetscDrawBar bar, PetscBool sort, PetscReal tolerance)
277: {
279:   bar->sort          = sort;
280:   bar->sorttolerance = tolerance;
281:   return 0;
282: }

284: /*@
285:   PetscDrawBarSetLimits - Sets the axis limits for a bar graph. If more
286:   points are added after this call, the limits will be adjusted to
287:   include those additional points.

289:   Logically Collective

291:   Input Parameters:
292: + bar - The bar graph context
293: - y_min,y_max - The limits

295:   Level: intermediate

297: .seealso: `PetscDrawBar`, `PetscDrawBarCreate()`, `PetscDrawBar`, `PetscDrawBarGetAxis()`, `PetscDrawBarSetData()`, `PetscDrawBarDraw()`
298: @*/
299: PetscErrorCode PetscDrawBarSetLimits(PetscDrawBar bar, PetscReal y_min, PetscReal y_max)
300: {
302:   bar->ymin = y_min;
303:   bar->ymax = y_max;
304:   return 0;
305: }

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

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

315:   Input Parameter:
316: . bar - The bar graph context

318:   Output Parameter:
319: . axis - The axis context

321:   Level: intermediate

323: .seealso: `PetscDrawBar`, `PetscDrawBarCreate()`, `PetscDrawBar`, `PetscDrawAxis`, `PetscDrawAxisCreate()`
324: @*/
325: PetscErrorCode PetscDrawBarGetAxis(PetscDrawBar bar, PetscDrawAxis *axis)
326: {
329:   *axis = bar->axis;
330:   return 0;
331: }

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

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

338:   Input Parameter:
339: . bar - The bar graph context

341:   Output Parameter:
342: . draw  - The draw context

344:   Level: intermediate

346: .seealso: `PetscDrawBar`, `PetscDraw`, `PetscDrawBarCreate()`, `PetscDrawBar`, `PetscDrawBarDraw()`, `PetscDraw`
347: @*/
348: PetscErrorCode PetscDrawBarGetDraw(PetscDrawBar bar, PetscDraw *draw)
349: {
352:   *draw = bar->win;
353:   return 0;
354: }

356: /*@
357:     PetscDrawBarSetFromOptions - Sets options related to the display of the `PetscDrawBar`

359:     Collective over bar

361:     Options Database Key:
362: .  -bar_sort - sort the entries before drawing the bar graph

364:     Level: intermediate

366:     Note:
367:     Does not set options related to the underlying `PetscDraw` or `PetscDrawAxis`

369: .seealso: `PetscDrawBar`, `PetscDrawBarDestroy()`, `PetscDrawBarCreate()`, `PetscDrawBarSort()`
370: @*/
371: PetscErrorCode PetscDrawBarSetFromOptions(PetscDrawBar bar)
372: {
373:   PetscBool set;


377:   PetscOptionsHasName(((PetscObject)bar)->options, ((PetscObject)bar)->prefix, "-bar_sort", &set);
378:   if (set) {
379:     PetscReal tol = bar->sorttolerance;
380:     PetscOptionsGetReal(((PetscObject)bar)->options, ((PetscObject)bar)->prefix, "-bar_sort", &tol, NULL);
381:     PetscDrawBarSort(bar, PETSC_TRUE, tol);
382:   }
383:   return 0;
384: }