Actual source code: hists.c

  1: /*
  2:   Contains the data structure for plotting a histogram in a window with an axis.
  3: */
  4: #include <petscdraw.h>
  5: #include <petsc/private/petscimpl.h>

  7: PetscClassId PETSC_DRAWHG_CLASSID = 0;

  9: struct _p_PetscDrawHG {
 10:   PETSCHEADER(int);
 11:   PetscErrorCode (*destroy)(PetscDrawSP);
 12:   PetscErrorCode (*view)(PetscDrawSP, PetscViewer);
 13:   PetscDraw     win;
 14:   PetscDrawAxis axis;
 15:   PetscReal     xmin, xmax;
 16:   PetscReal     ymin, ymax;
 17:   int           numBins;
 18:   int           maxBins;
 19:   PetscReal    *bins;
 20:   int           numValues;
 21:   int           maxValues;
 22:   PetscReal    *values;
 23:   PetscReal    *weights;
 24:   int           color;
 25:   PetscBool     calcStats;
 26:   PetscBool     integerBins;
 27: };

 29: #define CHUNKSIZE 100

 31: /*@
 32:   PetscDrawHGCreate - Creates a histogram data structure.

 34:   Collective

 36:   Input Parameters:
 37: + draw - The window where the graph will be made
 38: - bins - The number of bins to use

 40:   Output Parameter:
 41: . hist - The histogram context

 43:   Level: intermediate

 45:   Notes:
 46:   The difference between a bar chart, `PetscDrawBar`, and a histogram, `PetscDrawHG`, is explained here <https://stattrek.com/statistics/charts/histogram.aspx?Tutorial=AP>

 48:   The histogram is only displayed when `PetscDrawHGDraw()` is called.

 50:   The MPI communicator that owns the `PetscDraw` owns this `PetscDrawHG`, but the calls to set options and add data are ignored on all processes except the
 51:   zeroth MPI process in the communicator. All MPI processes in the communicator must call `PetscDrawHGDraw()` to display the updated graph.

 53: .seealso: `PetscDrawHGDestroy()`, `PetscDrawHG`, `PetscDrawBarCreate()`, `PetscDrawBar`, `PetscDrawLGCreate()`, `PetscDrawLG`, `PetscDrawSPCreate()`, `PetscDrawSP`,
 54:           `PetscDrawHGSetNumberBins()`, `PetscDrawHGReset()`, `PetscDrawHGAddValue()`, `PetscDrawHGDraw()`, `PetscDrawHGSave()`, `PetscDrawHGView()`, `PetscDrawHGSetColor()`,
 55:           `PetscDrawHGSetLimits()`, `PetscDrawHGCalcStats()`, `PetscDrawHGIntegerBins()`, `PetscDrawHGGetAxis()`, `PetscDrawAxis`, `PetscDrawHGGetDraw()`
 56: @*/
 57: PetscErrorCode PetscDrawHGCreate(PetscDraw draw, int bins, PetscDrawHG *hist)
 58: {
 59:   PetscDrawHG h;

 61:   PetscFunctionBegin;
 64:   PetscAssertPointer(hist, 3);

 66:   PetscCall(PetscHeaderCreate(h, PETSC_DRAWHG_CLASSID, "DrawHG", "Histogram", "Draw", PetscObjectComm((PetscObject)draw), PetscDrawHGDestroy, NULL));
 67:   PetscCall(PetscObjectReference((PetscObject)draw));
 68:   h->win     = draw;
 69:   h->view    = NULL;
 70:   h->destroy = NULL;
 71:   h->color   = PETSC_DRAW_GREEN;
 72:   h->xmin    = PETSC_MAX_REAL;
 73:   h->xmax    = PETSC_MIN_REAL;
 74:   h->ymin    = 0.;
 75:   h->ymax    = 1.e-6;
 76:   h->numBins = bins;
 77:   h->maxBins = bins;
 78:   PetscCall(PetscMalloc1(h->maxBins, &h->bins));
 79:   h->numValues   = 0;
 80:   h->maxValues   = CHUNKSIZE;
 81:   h->calcStats   = PETSC_FALSE;
 82:   h->integerBins = PETSC_FALSE;
 83:   PetscCall(PetscMalloc2(h->maxValues, &h->values, h->maxValues, &h->weights));
 84:   PetscCall(PetscDrawAxisCreate(draw, &h->axis));
 85:   *hist = h;
 86:   PetscFunctionReturn(PETSC_SUCCESS);
 87: }

 89: /*@
 90:   PetscDrawHGSetNumberBins - Change the number of bins that are to be drawn in the histogram

 92:   Logically Collective

 94:   Input Parameters:
 95: + hist - The histogram context.
 96: - bins - The number of bins.

 98:   Level: intermediate

100: .seealso: `PetscDrawHGCreate()`, `PetscDrawHG`, `PetscDrawHGDraw()`, `PetscDrawHGIntegerBins()`
101: @*/
102: PetscErrorCode PetscDrawHGSetNumberBins(PetscDrawHG hist, int bins)
103: {
104:   PetscFunctionBegin;

108:   if (hist->maxBins < bins) {
109:     PetscCall(PetscFree(hist->bins));
110:     PetscCall(PetscMalloc1(bins, &hist->bins));
111:     hist->maxBins = bins;
112:   }
113:   hist->numBins = bins;
114:   PetscFunctionReturn(PETSC_SUCCESS);
115: }

117: /*@
118:   PetscDrawHGReset - Clears histogram to allow for reuse with new data.

120:   Logically Collective

122:   Input Parameter:
123: . hist - The histogram context.

125:   Level: intermediate

127: .seealso: `PetscDrawHGCreate()`, `PetscDrawHG`, `PetscDrawHGDraw()`, `PetscDrawHGAddValue()`
128: @*/
129: PetscErrorCode PetscDrawHGReset(PetscDrawHG hist)
130: {
131:   PetscFunctionBegin;

134:   hist->xmin      = PETSC_MAX_REAL;
135:   hist->xmax      = PETSC_MIN_REAL;
136:   hist->ymin      = 0.0;
137:   hist->ymax      = 1.e-6;
138:   hist->numValues = 0;
139:   PetscFunctionReturn(PETSC_SUCCESS);
140: }

142: /*@
143:   PetscDrawHGDestroy - Frees all space taken up by histogram data structure.

145:   Collective

147:   Input Parameter:
148: . hist - The histogram context

150:   Level: intermediate

152: .seealso: `PetscDrawHGCreate()`, `PetscDrawHG`
153: @*/
154: PetscErrorCode PetscDrawHGDestroy(PetscDrawHG *hist)
155: {
156:   PetscFunctionBegin;
157:   if (!*hist) PetscFunctionReturn(PETSC_SUCCESS);
159:   if (--((PetscObject)*hist)->refct > 0) {
160:     *hist = NULL;
161:     PetscFunctionReturn(PETSC_SUCCESS);
162:   }

164:   PetscCall(PetscFree((*hist)->bins));
165:   PetscCall(PetscFree2((*hist)->values, (*hist)->weights));
166:   PetscCall(PetscDrawAxisDestroy(&(*hist)->axis));
167:   PetscCall(PetscDrawDestroy(&(*hist)->win));
168:   PetscCall(PetscHeaderDestroy(hist));
169:   PetscFunctionReturn(PETSC_SUCCESS);
170: }

172: /*@
173:   PetscDrawHGAddValue - Adds another value to the histogram.

175:   Logically Collective

177:   Input Parameters:
178: + hist  - The histogram
179: - value - The value

181:   Level: intermediate

183:   Note:
184:   Calls to this function are used to create a standard histogram with integer bin heights. Use calls to `PetscDrawHGAddWeightedValue()` to create a histogram with non-integer bin heights.

186: .seealso: `PetscDrawHGCreate()`, `PetscDrawHG`, `PetscDrawHGDraw()`, `PetscDrawHGReset()`, `PetscDrawHGAddWeightedValue()`
187: @*/
188: PetscErrorCode PetscDrawHGAddValue(PetscDrawHG hist, PetscReal value)
189: {
190:   PetscFunctionBegin;

193:   /* Allocate more memory if necessary */
194:   if (hist->numValues >= hist->maxValues) {
195:     PetscReal *tmp, *tmpw;

197:     PetscCall(PetscMalloc2(hist->maxValues + CHUNKSIZE, &tmp, hist->maxValues + CHUNKSIZE, &tmpw));
198:     PetscCall(PetscArraycpy(tmp, hist->values, hist->maxValues));
199:     PetscCall(PetscArraycpy(tmpw, hist->weights, hist->maxValues));
200:     PetscCall(PetscFree2(hist->values, hist->weights));

202:     hist->values  = tmp;
203:     hist->weights = tmpw;
204:     hist->maxValues += CHUNKSIZE;
205:   }
206:   /* I disagree with the original PETSc implementation here. There should be no overshoot, but rather the
207:      stated convention of using half-open intervals (always the way to go) */
208:   if (!hist->numValues && (hist->xmin == PETSC_MAX_REAL) && (hist->xmax == PETSC_MIN_REAL)) {
209:     hist->xmin = value;
210:     hist->xmax = value;
211: #if 1
212:   } else {
213:     /* Update limits */
214:     if (value > hist->xmax) hist->xmax = value;
215:     if (value < hist->xmin) hist->xmin = value;
216: #else
217:   } else if (hist->numValues == 1) {
218:     /* Update limits -- We need to overshoot the largest value somewhat */
219:     if (value > hist->xmax) hist->xmax = value + 0.001 * (value - hist->xmin) / (PetscReal)hist->numBins;
220:     if (value < hist->xmin) {
221:       hist->xmin = value;
222:       hist->xmax = hist->xmax + 0.001 * (hist->xmax - hist->xmin) / (PetscReal)hist->numBins;
223:     }
224:   } else {
225:     /* Update limits -- We need to overshoot the largest value somewhat */
226:     if (value > hist->xmax) hist->xmax = value + 0.001 * (hist->xmax - hist->xmin) / (PetscReal)hist->numBins;
227:     if (value < hist->xmin) hist->xmin = value;
228: #endif
229:   }

231:   hist->values[hist->numValues]  = value;
232:   hist->weights[hist->numValues] = 1.;
233:   ++hist->numValues;
234:   PetscFunctionReturn(PETSC_SUCCESS);
235: }

237: /*@
238:   PetscDrawHGAddWeightedValue - Adds another value to the histogram with a weight.

240:   Logically Collective

242:   Input Parameters:
243: + hist   - The histogram
244: . value  - The value
245: - weight - The value weight

247:   Level: intermediate

249:   Notes:
250:   Calls to this function are used to create a histogram with non-integer bin heights. Use calls to `PetscDrawHGAddValue()` to create a standard histogram with integer bin heights.

252:   This allows us to histogram frequency and probability distributions (<https://learnche.org/pid/univariate-review/histograms-and-probability-distributions>). We can use this to look at particle weight distributions in Particle-in-Cell (PIC) methods, for example.

254: .seealso: `PetscDrawHGCreate()`, `PetscDrawHG`, `PetscDrawHGDraw()`, `PetscDrawHGReset()`, `PetscDrawHGAddValue()`
255: @*/
256: PetscErrorCode PetscDrawHGAddWeightedValue(PetscDrawHG hist, PetscReal value, PetscReal weight)
257: {
258:   PetscFunctionBegin;

261:   /* Allocate more memory if necessary */
262:   if (hist->numValues >= hist->maxValues) {
263:     PetscReal *tmp, *tmpw;

265:     PetscCall(PetscMalloc2(hist->maxValues + CHUNKSIZE, &tmp, hist->maxValues + CHUNKSIZE, &tmpw));
266:     PetscCall(PetscArraycpy(tmp, hist->values, hist->maxValues));
267:     PetscCall(PetscArraycpy(tmpw, hist->weights, hist->maxValues));
268:     PetscCall(PetscFree2(hist->values, hist->weights));

270:     hist->values  = tmp;
271:     hist->weights = tmpw;
272:     hist->maxValues += CHUNKSIZE;
273:   }
274:   /* I disagree with the original PETSc implementation here. There should be no overshoot, but rather the
275:      stated convention of using half-open intervals (always the way to go) */
276:   if (!hist->numValues && (hist->xmin == PETSC_MAX_REAL) && (hist->xmax == PETSC_MIN_REAL)) {
277:     hist->xmin = value;
278:     hist->xmax = value;
279:   } else {
280:     /* Update limits */
281:     if (value > hist->xmax) hist->xmax = value;
282:     if (value < hist->xmin) hist->xmin = value;
283:   }

285:   hist->values[hist->numValues]  = value;
286:   hist->weights[hist->numValues] = weight;
287:   ++hist->numValues;
288:   PetscFunctionReturn(PETSC_SUCCESS);
289: }

291: /*@
292:   PetscDrawHGDraw - Redraws a histogram.

294:   Collective

296:   Input Parameter:
297: . hist - The histogram context

299:   Level: intermediate

301: .seealso: `PetscDrawHGCreate()`, `PetscDrawHG`, `PetscDrawHGAddValue()`, `PetscDrawHGReset()`
302: @*/
303: PetscErrorCode PetscDrawHGDraw(PetscDrawHG hist)
304: {
305:   PetscDraw   draw;
306:   PetscBool   isnull, usewt = PETSC_FALSE;
307:   PetscReal   xmin, xmax, ymin, ymax, *bins, *values, *weights, binSize, binLeft, binRight, maxHeight, mean, var, totwt = 0.;
308:   char        title[256];
309:   char        xlabel[256];
310:   PetscInt    numValues, initSize, i, p;
311:   int         bcolor, color, numBins, numBinsOld;
312:   PetscMPIInt rank;

314:   PetscFunctionBegin;
316:   PetscCall(PetscDrawIsNull(hist->win, &isnull));
317:   if (isnull) PetscFunctionReturn(PETSC_SUCCESS);
318:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)hist), &rank));

320:   if (hist->xmin >= hist->xmax || hist->ymin >= hist->ymax) PetscFunctionReturn(PETSC_SUCCESS);
321:   if (hist->numValues < 1) PetscFunctionReturn(PETSC_SUCCESS);

323:   color = hist->color;
324:   if (color == PETSC_DRAW_ROTATE) bcolor = PETSC_DRAW_BLACK + 1;
325:   else bcolor = color;

327:   xmin      = hist->xmin;
328:   xmax      = hist->xmax;
329:   ymin      = hist->ymin;
330:   ymax      = hist->ymax;
331:   numValues = hist->numValues;
332:   values    = hist->values;
333:   weights   = hist->weights;
334:   mean      = 0.0;
335:   var       = 0.0;

337:   draw = hist->win;
338:   PetscCall(PetscDrawCheckResizedWindow(draw));
339:   PetscCall(PetscDrawClear(draw));

341:   if (xmin == xmax) {
342:     /* Calculate number of points in each bin */
343:     bins    = hist->bins;
344:     bins[0] = 0.;
345:     for (p = 0; p < numValues; p++) {
346:       if (values[p] == xmin) bins[0] += weights[0];
347:       mean += values[p] * weights[p];
348:       var += values[p] * values[p] * weights[p];
349:       totwt += weights[p];
350:       if (weights[p] != 1.) usewt = PETSC_TRUE;
351:     }
352:     maxHeight = bins[0];
353:     if (maxHeight > ymax) ymax = hist->ymax = maxHeight;
354:     xmax = xmin + 1;
355:     PetscCall(PetscDrawAxisSetLimits(hist->axis, xmin, xmax, ymin, ymax));
356:     if (hist->calcStats) {
357:       if (usewt) {
358:         mean /= totwt;
359:         var = (var - totwt * mean * mean) / totwt;

361:         PetscCall(PetscSNPrintf(xlabel, 256, "Total Weight: %g", (double)totwt));
362:       } else {
363:         mean /= numValues;
364:         if (numValues > 1) var = (var - numValues * mean * mean) / (PetscReal)(numValues - 1);
365:         else var = 0.0;

367:         PetscCall(PetscSNPrintf(xlabel, 256, "Total: %" PetscInt_FMT, numValues));
368:       }
369:       PetscCall(PetscSNPrintf(title, 256, "Mean: %g  Var: %g", (double)mean, (double)var));
370:       PetscCall(PetscDrawAxisSetLabels(hist->axis, title, xlabel, NULL));
371:     }
372:     PetscCall(PetscDrawAxisDraw(hist->axis));
373:     PetscDrawCollectiveBegin(draw);
374:     if (rank == 0) { /* Draw bins */
375:       binLeft  = xmin;
376:       binRight = xmax;
377:       PetscCall(PetscDrawRectangle(draw, binLeft, ymin, binRight, bins[0], bcolor, bcolor, bcolor, bcolor));
378:       PetscCall(PetscDrawLine(draw, binLeft, ymin, binLeft, bins[0], PETSC_DRAW_BLACK));
379:       PetscCall(PetscDrawLine(draw, binRight, ymin, binRight, bins[0], PETSC_DRAW_BLACK));
380:       PetscCall(PetscDrawLine(draw, binLeft, bins[0], binRight, bins[0], PETSC_DRAW_BLACK));
381:     }
382:     PetscDrawCollectiveEnd(draw);
383:   } else {
384:     numBins    = hist->numBins;
385:     numBinsOld = hist->numBins;
386:     if (hist->integerBins && (((int)xmax - xmin) + 1.0e-05 > xmax - xmin)) {
387:       initSize = ((int)(xmax - xmin)) / numBins;
388:       while (initSize * numBins != (int)xmax - xmin) {
389:         initSize = PetscMax(initSize - 1, 1);
390:         numBins  = ((int)(xmax - xmin)) / initSize;
391:         PetscCall(PetscDrawHGSetNumberBins(hist, numBins));
392:       }
393:     }
394:     binSize = (xmax - xmin) / (PetscReal)numBins;
395:     bins    = hist->bins;

397:     PetscCall(PetscArrayzero(bins, numBins));

399:     maxHeight = 0.0;
400:     for (i = 0; i < numBins; i++) {
401:       binLeft  = xmin + binSize * i;
402:       binRight = xmin + binSize * (i + 1);
403:       for (p = 0; p < numValues; p++) {
404:         if (values[p] >= binLeft && values[p] < binRight) bins[i] += weights[p];
405:         /* Handle last bin separately */
406:         if (i == numBins - 1 && values[p] == binRight) bins[i] += weights[p];
407:         if (!i) {
408:           mean += values[p] * weights[p];
409:           var += values[p] * values[p] * weights[p];
410:           totwt += weights[p];
411:           if (weights[p] != 1.) usewt = PETSC_TRUE;
412:         }
413:       }
414:       maxHeight = PetscMax(maxHeight, bins[i]);
415:     }
416:     if (maxHeight > ymax) ymax = hist->ymax = maxHeight;

418:     PetscCall(PetscDrawAxisSetLimits(hist->axis, xmin, xmax, ymin, ymax));
419:     if (hist->calcStats) {
420:       if (usewt) {
421:         mean /= totwt;
422:         var = (var - totwt * mean * mean) / totwt;

424:         PetscCall(PetscSNPrintf(xlabel, 256, "Total Weight: %g", (double)totwt));
425:       } else {
426:         mean /= numValues;
427:         if (numValues > 1) var = (var - numValues * mean * mean) / (PetscReal)(numValues - 1);
428:         else var = 0.0;

430:         PetscCall(PetscSNPrintf(xlabel, 256, "Total: %" PetscInt_FMT, numValues));
431:       }
432:       PetscCall(PetscSNPrintf(title, 256, "Mean: %g  Var: %g", (double)mean, (double)var));
433:       PetscCall(PetscDrawAxisSetLabels(hist->axis, title, xlabel, NULL));
434:     }
435:     PetscCall(PetscDrawAxisDraw(hist->axis));
436:     PetscDrawCollectiveBegin(draw);
437:     if (rank == 0) { /* Draw bins */
438:       for (i = 0; i < numBins; i++) {
439:         binLeft  = xmin + binSize * i;
440:         binRight = xmin + binSize * (i + 1);
441:         PetscCall(PetscDrawRectangle(draw, binLeft, ymin, binRight, bins[i], bcolor, bcolor, bcolor, bcolor));
442:         PetscCall(PetscDrawLine(draw, binLeft, ymin, binLeft, bins[i], PETSC_DRAW_BLACK));
443:         PetscCall(PetscDrawLine(draw, binRight, ymin, binRight, bins[i], PETSC_DRAW_BLACK));
444:         PetscCall(PetscDrawLine(draw, binLeft, bins[i], binRight, bins[i], PETSC_DRAW_BLACK));
445:         if (color == PETSC_DRAW_ROTATE && bins[i]) bcolor++;
446:         if (bcolor > PETSC_DRAW_BASIC_COLORS - 1) bcolor = PETSC_DRAW_BLACK + 1;
447:       }
448:     }
449:     PetscDrawCollectiveEnd(draw);
450:     PetscCall(PetscDrawHGSetNumberBins(hist, numBinsOld));
451:   }

453:   PetscCall(PetscDrawFlush(draw));
454:   PetscCall(PetscDrawPause(draw));
455:   PetscFunctionReturn(PETSC_SUCCESS);
456: }

458: /*@
459:   PetscDrawHGSave - Saves a drawn image

461:   Collective

463:   Input Parameter:
464: . hg - The histogram context

466:   Level: intermediate

468: .seealso: `PetscDrawSave()`, `PetscDrawHGCreate()`, `PetscDrawHGGetDraw()`, `PetscDrawSetSave()`, `PetscDrawHGDraw()`
469: @*/
470: PetscErrorCode PetscDrawHGSave(PetscDrawHG hg)
471: {
472:   PetscFunctionBegin;
474:   PetscCall(PetscDrawSave(hg->win));
475:   PetscFunctionReturn(PETSC_SUCCESS);
476: }

478: /*@
479:   PetscDrawHGView - Prints the histogram information to a viewer

481:   Not Collective

483:   Input Parameters:
484: + hist   - The histogram context
485: - viewer - The viewer to view it with

487:   Level: beginner

489: .seealso: `PetscDrawHG`, `PetscViewer`, `PetscDrawHGCreate()`, `PetscDrawHGGetDraw()`, `PetscDrawSetSave()`, `PetscDrawSave()`, `PetscDrawHGDraw()`
490: @*/
491: PetscErrorCode PetscDrawHGView(PetscDrawHG hist, PetscViewer viewer)
492: {
493:   PetscReal xmax, xmin, *bins, *values, *weights, binSize, binLeft, binRight, mean, var, totwt = 0.;
494:   PetscInt  numBins, numBinsOld, numValues, initSize, i, p;
495:   PetscBool usewt = PETSC_FALSE;
496:   int       inumBins;

498:   PetscFunctionBegin;

501:   if (hist->xmin > hist->xmax || hist->ymin >= hist->ymax) PetscFunctionReturn(PETSC_SUCCESS);
502:   if (hist->numValues < 1) PetscFunctionReturn(PETSC_SUCCESS);

504:   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)hist), &viewer));
505:   PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)hist, viewer));
506:   xmax      = hist->xmax;
507:   xmin      = hist->xmin;
508:   numValues = hist->numValues;
509:   values    = hist->values;
510:   weights   = hist->weights;
511:   mean      = 0.0;
512:   var       = 0.0;
513:   if (xmax == xmin) {
514:     /* Calculate number of points in the bin */
515:     bins    = hist->bins;
516:     bins[0] = 0.;
517:     for (p = 0; p < numValues; p++) {
518:       if (values[p] == xmin) bins[0] += weights[0];
519:       mean += values[p] * weights[p];
520:       var += values[p] * values[p] * weights[p];
521:       totwt += weights[p];
522:       if (weights[p] != 1.) usewt = PETSC_TRUE;
523:     }
524:     /* Draw bins */
525:     PetscCall(PetscViewerASCIIPrintf(viewer, "Bin %2d (%6.2g - %6.2g): %.0g\n", 0, (double)xmin, (double)xmax, (double)bins[0]));
526:   } else {
527:     numBins    = hist->numBins;
528:     numBinsOld = hist->numBins;
529:     if (hist->integerBins && (((int)xmax - xmin) + 1.0e-05 > xmax - xmin)) {
530:       initSize = (int)((int)xmax - xmin) / numBins;
531:       while (initSize * numBins != (int)xmax - xmin) {
532:         initSize = PetscMax(initSize - 1, 1);
533:         numBins  = (int)((int)xmax - xmin) / initSize;
534:         PetscCall(PetscCIntCast(numBins, &inumBins));
535:         PetscCall(PetscDrawHGSetNumberBins(hist, inumBins));
536:       }
537:     }
538:     binSize = (xmax - xmin) / numBins;
539:     bins    = hist->bins;

541:     /* Calculate number of points in each bin */
542:     PetscCall(PetscArrayzero(bins, numBins));
543:     for (i = 0; i < numBins; i++) {
544:       binLeft  = xmin + binSize * i;
545:       binRight = xmin + binSize * (i + 1);
546:       for (p = 0; p < numValues; p++) {
547:         if (values[p] >= binLeft && values[p] < binRight) bins[i] += weights[p];
548:         /* Handle last bin separately */
549:         if (i == numBins - 1 && values[p] == binRight) bins[i] += weights[p];
550:         if (!i) {
551:           mean += values[p] * weights[p];
552:           var += values[p] * values[p] * weights[p];
553:           totwt += weights[p];
554:           if (weights[p] != 1.) usewt = PETSC_TRUE;
555:         }
556:       }
557:     }
558:     /* Draw bins */
559:     for (i = 0; i < numBins; i++) {
560:       binLeft  = xmin + binSize * i;
561:       binRight = xmin + binSize * (i + 1);
562:       PetscCall(PetscViewerASCIIPrintf(viewer, "Bin %2" PetscInt_FMT " (%6.2g - %6.2g): %.0g\n", i, (double)binLeft, (double)binRight, (double)bins[i]));
563:     }
564:     PetscCall(PetscCIntCast(numBinsOld, &inumBins));
565:     PetscCall(PetscDrawHGSetNumberBins(hist, inumBins));
566:   }

568:   if (hist->calcStats) {
569:     if (usewt) {
570:       mean /= totwt;
571:       var = (var - totwt * mean * mean) / totwt;

573:       PetscCall(PetscViewerASCIIPrintf(viewer, "Total Weight: %g\n", (double)totwt));
574:     } else {
575:       mean /= numValues;
576:       if (numValues > 1) var = (var - numValues * mean * mean) / (PetscReal)(numValues - 1);
577:       else var = 0.0;

579:       PetscCall(PetscViewerASCIIPrintf(viewer, "Total: %" PetscInt_FMT "\n", numValues));
580:     }
581:     PetscCall(PetscViewerASCIIPrintf(viewer, "Mean: %g  Var: %g\n", (double)mean, (double)var));
582:   }
583:   PetscFunctionReturn(PETSC_SUCCESS);
584: }

586: /*@
587:   PetscDrawHGSetColor - Sets the color the bars will be drawn with.

589:   Logically Collective

591:   Input Parameters:
592: + hist  - The histogram context
593: - color - one of the colors defined in petscdraw.h or `PETSC_DRAW_ROTATE` to make each bar a different color

595:   Level: intermediate

597: .seealso: `PetscDrawHG`, `PetscDrawHGCreate()`, `PetscDrawHGGetDraw()`, `PetscDrawSetSave()`, `PetscDrawSave()`, `PetscDrawHGDraw()`, `PetscDrawHGGetAxis()`
598: @*/
599: PetscErrorCode PetscDrawHGSetColor(PetscDrawHG hist, int color)
600: {
601:   PetscFunctionBegin;

604:   hist->color = color;
605:   PetscFunctionReturn(PETSC_SUCCESS);
606: }

608: /*@
609:   PetscDrawHGSetLimits - Sets the axis limits for a histogram. If more
610:   points are added after this call, the limits will be adjusted to
611:   include those additional points.

613:   Logically Collective

615:   Input Parameters:
616: + hist  - The histogram context
617: . x_min - the horizontal lower limit
618: . x_max - the horizontal upper limit
619: . y_min - the vertical lower limit
620: - y_max - the vertical upper limit

622:   Level: intermediate

624: .seealso: `PetscDrawHG`, `PetscDrawHGCreate()`, `PetscDrawHGGetDraw()`, `PetscDrawSetSave()`, `PetscDrawSave()`, `PetscDrawHGDraw()`, `PetscDrawHGGetAxis()`
625: @*/
626: PetscErrorCode PetscDrawHGSetLimits(PetscDrawHG hist, PetscReal x_min, PetscReal x_max, int y_min, int y_max)
627: {
628:   PetscFunctionBegin;

631:   hist->xmin = x_min;
632:   hist->xmax = x_max;
633:   hist->ymin = y_min;
634:   hist->ymax = y_max;
635:   PetscFunctionReturn(PETSC_SUCCESS);
636: }

638: /*@
639:   PetscDrawHGCalcStats - Turns on calculation of descriptive statistics associated with the histogram

641:   Not Collective

643:   Input Parameters:
644: + hist - The histogram context
645: - calc - Flag for calculation

647:   Level: intermediate

649: .seealso: `PetscDrawHG`, `PetscDrawHGCreate()`, `PetscDrawHGAddValue()`, `PetscDrawHGView()`, `PetscDrawHGDraw()`
650: @*/
651: PetscErrorCode PetscDrawHGCalcStats(PetscDrawHG hist, PetscBool calc)
652: {
653:   PetscFunctionBegin;

656:   hist->calcStats = calc;
657:   PetscFunctionReturn(PETSC_SUCCESS);
658: }

660: /*@
661:   PetscDrawHGIntegerBins - Turns on integer width bins

663:   Not Collective

665:   Input Parameters:
666: + hist - The histogram context
667: - ints - Flag for integer width bins

669:   Level: intermediate

671: .seealso: `PetscDrawHG`, `PetscDrawHGCreate()`, `PetscDrawHGAddValue()`, `PetscDrawHGView()`, `PetscDrawHGDraw()`, `PetscDrawHGSetColor()`
672: @*/
673: PetscErrorCode PetscDrawHGIntegerBins(PetscDrawHG hist, PetscBool ints)
674: {
675:   PetscFunctionBegin;

678:   hist->integerBins = ints;
679:   PetscFunctionReturn(PETSC_SUCCESS);
680: }

682: /*@
683:   PetscDrawHGGetAxis - Gets the axis context associated with a histogram.
684:   This is useful if one wants to change some axis property, such as
685:   labels, color, etc. The axis context should not be destroyed by the
686:   application code.

688:   Not Collective, axis is parallel if hist is parallel

690:   Input Parameter:
691: . hist - The histogram context

693:   Output Parameter:
694: . axis - The axis context

696:   Level: intermediate

698: .seealso: `PetscDrawHG`, `PetscDrawAxis`, `PetscDrawHGCreate()`, `PetscDrawHGAddValue()`, `PetscDrawHGView()`, `PetscDrawHGDraw()`, `PetscDrawHGSetColor()`, `PetscDrawHGSetLimits()`
699: @*/
700: PetscErrorCode PetscDrawHGGetAxis(PetscDrawHG hist, PetscDrawAxis *axis)
701: {
702:   PetscFunctionBegin;
704:   PetscAssertPointer(axis, 2);
705:   *axis = hist->axis;
706:   PetscFunctionReturn(PETSC_SUCCESS);
707: }

709: /*@
710:   PetscDrawHGGetDraw - Gets the draw context associated with a histogram.

712:   Not Collective, draw is parallel if hist is parallel

714:   Input Parameter:
715: . hist - The histogram context

717:   Output Parameter:
718: . draw - The draw context

720:   Level: intermediate

722: .seealso: `PetscDraw`, `PetscDrawHG`, `PetscDrawHGCreate()`, `PetscDrawHGAddValue()`, `PetscDrawHGView()`, `PetscDrawHGDraw()`, `PetscDrawHGSetColor()`, `PetscDrawAxis`, `PetscDrawHGSetLimits()`
723: @*/
724: PetscErrorCode PetscDrawHGGetDraw(PetscDrawHG hist, PetscDraw *draw)
725: {
726:   PetscFunctionBegin;
728:   PetscAssertPointer(draw, 2);
729:   *draw = hist->win;
730:   PetscFunctionReturn(PETSC_SUCCESS);
731: }