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