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>
  6: #include <petscviewer.h>

  8: PetscClassId PETSC_DRAWHG_CLASSID = 0;

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

 30: #define CHUNKSIZE 100

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

 35:   Collective

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

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

 44:   Level: intermediate

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

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

 51:   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
 52:   zeroth MPI process in the communicator. All MPI processes in the communicator must call `PetscDrawHGDraw()` to display the updated graph.

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

 62:   PetscFunctionBegin;
 65:   PetscAssertPointer(hist, 3);

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

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

 93:   Logically Collective

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

 99:   Level: intermediate

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

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

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

121:   Logically Collective

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

126:   Level: intermediate

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

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

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

146:   Collective

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

151:   Level: intermediate

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

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

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

176:   Logically Collective

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

182:   Level: intermediate

184:   Note:
185:   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.

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

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

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

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

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

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

241:   Logically Collective

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

248:   Level: intermediate

250:   Notes:
251:   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.

253:   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.

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

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

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

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

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

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

295:   Collective

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

300:   Level: intermediate

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

462:   Collective

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

467:   Level: intermediate

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

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

482:   Not Collective

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

488:   Level: beginner

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

499:   PetscFunctionBegin;

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

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

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

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

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

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

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

590:   Logically Collective

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

596:   Level: intermediate

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

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

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

614:   Logically Collective

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

623:   Level: intermediate

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

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

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

642:   Not Collective

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

648:   Level: intermediate

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

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

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

664:   Not Collective

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

670:   Level: intermediate

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

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

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

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

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

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

697:   Level: intermediate

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

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

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

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

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

721:   Level: intermediate

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