Actual source code: hists.c

  1: /*$Id: hists.c,v 1.26 2001/04/10 19:34:23 bsmith Exp $*/

  3: /*
  4:   Contains the data structure for plotting a histogram in a window with an axis.
  5: */

 7:  #include petsc.h

  9: int DRAWHG_COOKIE;

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

 30: #define CHUNKSIZE 100

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

 35:    Collective over PetscDraw

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

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

 44:    Level: intermediate

 46:    Contributed by: Matthew Knepley

 48:    Concepts: histogram^creating

 50: .seealso: PetscDrawHGDestroy()

 52: @*/
 53: int PetscDrawHGCreate(PetscDraw draw, int bins, PetscDrawHG *hist) {
 54:   PetscDrawHG h;
 55:   MPI_Comm    comm;
 56:   PetscTruth  isnull;
 57:   int         ierr;

 62:   PetscObjectGetComm((PetscObject) draw, &comm);
 63:   PetscHeaderCreate(h, _p_DrawHG, int, DRAWHG_COOKIE, 0, "PetscDrawHG", comm, PetscDrawHGDestroy, PETSC_NULL);
 64:   h->view        = PETSC_NULL;
 65:   h->destroy     = PETSC_NULL;
 66:   h->win         = draw;
 67:   PetscObjectReference((PetscObject) draw);
 68:   h->color       = PETSC_DRAW_GREEN;
 69:   h->xmin        = PETSC_MAX;
 70:   h->xmax        = PETSC_MIN;
 71:   h->ymin        = 0.;
 72:   h->ymax        = 1.;
 73:   h->numBins     = bins;
 74:   h->maxBins     = bins;
 75:   PetscMalloc(h->maxBins * sizeof(PetscReal), &h->bins);
 76:   h->numValues   = 0;
 77:   h->maxValues   = CHUNKSIZE;
 78:   h->calcStats   = PETSC_FALSE;
 79:   h->integerBins = PETSC_FALSE;
 80:   PetscMalloc(h->maxValues * sizeof(PetscReal), &h->values);
 81:   PetscLogObjectMemory(h, (h->maxBins + h->maxValues)*sizeof(PetscReal));
 82:   PetscTypeCompare((PetscObject) draw, PETSC_DRAW_NULL, &isnull);
 83:   if (isnull == PETSC_FALSE) {
 84:     PetscDrawAxisCreate(draw, &h->axis);
 85:     PetscLogObjectParent(h, h->axis);
 86:   } else {
 87:     h->axis = PETSC_NULL;
 88:   }
 89:   *hist = h;
 90:   return(0);
 91: }

 93: /*@
 94:    PetscDrawHGSetNumberBins - Change the number of bins that are to be drawn.

 96:    Not Collective (ignored except on processor 0 of PetscDrawHG)

 98:    Input Parameter:
 99: +  hist - The histogram context.
100: -  dim  - The number of curves.

102:    Level: intermediate

104:   Contributed by: Matthew Knepley

106:    Concepts: histogram^setting number of bins

108: @*/
109: int PetscDrawHGSetNumberBins(PetscDrawHG hist, int bins) {

114:   if (hist->maxBins < bins) {
115:     PetscFree(hist->bins);
116:     PetscMalloc(bins * sizeof(PetscReal), &hist->bins);
117:     PetscLogObjectMemory(hist, (bins - hist->maxBins) * sizeof(PetscReal));
118:     hist->maxBins = bins;
119:   }
120:   hist->numBins = bins;
121:   return(0);
122: }

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

127:   Not Collective (ignored except on processor 0 of PetscDrawHG)

129:   Input Parameter:
130: . hist - The histogram context.

132:   Level: intermediate

134:   Contributed by: Matthew Knepley

136:   Concepts: histogram^resetting
137: @*/
138: int PetscDrawHGReset(PetscDrawHG hist)
139: {
142:   hist->xmin      = PETSC_MAX;
143:   hist->xmax      = PETSC_MIN;
144:   hist->ymin      = 0;
145:   hist->ymax      = 0;
146:   hist->numValues = 0;
147:   return(0);
148: }

150: /*@C
151:   PetscDrawHGDestroy - Frees all space taken up by histogram data structure.

153:   Collective over PetscDrawHG

155:   Input Parameter:
156: . hist - The histogram context

158:   Level: intermediate

160:   Contributed by: Matthew Knepley

162: .seealso:  PetscDrawHGCreate()
163: @*/
164: int PetscDrawHGDestroy(PetscDrawHG hist)
165: {


171:   if (--hist->refct > 0) return(0);
172:   if (hist->axis != PETSC_NULL) {
173:     PetscDrawAxisDestroy(hist->axis);
174:   }
175:   PetscDrawDestroy(hist->win);
176:   PetscFree(hist->bins);
177:   PetscFree(hist->values);
178:   PetscLogObjectDestroy(hist);
179:   PetscHeaderDestroy(hist);
180:   return(0);
181: }

183: /*@
184:   PetscDrawHGAddValue - Adds another value to the histogram.

186:   Not Collective (ignored except on processor 0 of PetscDrawHG)

188:   Input Parameters:
189: + hist  - The histogram
190: - value - The value 

192:   Level: intermediate

194:   Contributed by: Matthew Knepley

196:   Concepts: histogram^adding values

198: .seealso: PetscDrawHGAddValues()
199: @*/
200: int PetscDrawHGAddValue(PetscDrawHG hist, PetscReal value)
201: {
204:   /* Allocate more memory if necessary */
205:   if (hist->numValues >= hist->maxValues) {
206:     PetscReal *tmp;
207:     int        ierr;

209:     PetscMalloc((hist->maxValues+CHUNKSIZE) * sizeof(PetscReal), &tmp);
210:     PetscLogObjectMemory(hist, CHUNKSIZE * sizeof(PetscReal));
211:     PetscMemcpy(tmp, hist->values, hist->maxValues * sizeof(PetscReal));
212:     PetscFree(hist->values);
213:     hist->values     = tmp;
214:     hist->maxValues += CHUNKSIZE;
215:   }
216:   /* I disagree with the original Petsc implementation here. There should be no overshoot, but rather the
217:      stated convention of using half-open intervals (always the way to go) */
218:   if (!hist->numValues) {
219:     hist->xmin = value;
220:     hist->xmax = value;
221: #if 1
222:   } else {
223:     /* Update limits */
224:     if (value > hist->xmax)
225:       hist->xmax = value;
226:     if (value < hist->xmin)
227:       hist->xmin = value;
228: #else
229:   } else if (hist->numValues == 1) {
230:     /* Update limits -- We need to overshoot the largest value somewhat */
231:     if (value > hist->xmax) {
232:       hist->xmax = value + 0.001*(value - hist->xmin)/hist->numBins;
233:     }
234:     if (value < hist->xmin) {
235:       hist->xmin = value;
236:       hist->xmax = hist->xmax + 0.001*(hist->xmax - hist->xmin)/hist->numBins;
237:     }
238:   } else {
239:     /* Update limits -- We need to overshoot the largest value somewhat */
240:     if (value > hist->xmax) {
241:       hist->xmax = value + 0.001*(hist->xmax - hist->xmin)/hist->numBins;
242:     }
243:     if (value < hist->xmin) {
244:       hist->xmin = value;
245:     }
246: #endif
247:   }

249:   hist->values[hist->numValues++] = value;
250:   return(0);
251: }

253: /*@
254:   PetscDrawHGDraw - Redraws a histogram.

256:   Not Collective (ignored except on processor 0 of PetscDrawHG)

258:   Input Parameter:
259: . hist - The histogram context

261:   Level: intermediate

263:   Contributed by: Matthew Knepley
264: @*/
265: int PetscDrawHGDraw(PetscDrawHG hist)
266: {
267:   PetscDraw  draw = hist->win;
268:   PetscTruth isnull;
269:   PetscReal  xmin,xmax,ymin,ymax,*bins,*values,binSize,binLeft,binRight,maxHeight,mean,var;
270:   char       title[256];
271:   char       xlabel[256];
272:   int        numBins,numBinsOld,numValues,initSize,i,p,ierr,bcolor,color;

276:   PetscTypeCompare((PetscObject) draw, PETSC_DRAW_NULL, &isnull);
277:   if (isnull == PETSC_TRUE) return(0);
278:   if ((hist->xmin >= hist->xmax) || (hist->ymin >= hist->ymax)) return(0);
279:   if (hist->numValues < 1) return(0);

281: #if 0
282:   MPI_Comm_rank(hist->comm,&rank);
283:   if (rank) return(0);
284: #endif

286:   color     = hist->color;
287:   if (color == PETSC_DRAW_ROTATE) {bcolor = 2;} else {bcolor = color;}
288:   xmin      = hist->xmin;
289:   xmax      = hist->xmax;
290:   ymin      = hist->ymin;
291:   ymax      = hist->ymax;
292:   numValues = hist->numValues;
293:   values    = hist->values;
294:   mean      = 0.0;
295:   var       = 0.0;
296: 
297:   PetscDrawClear(draw);
298:   if (xmin == xmax) {
299:     /* Calculate number of points in each bin */
300:     bins    = hist->bins;
301:     bins[0] = 0;
302:     for(p = 0; p < numValues; p++) {
303:       if (values[p] == xmin) bins[0]++;
304:       mean += values[p];
305:       var  += values[p]*values[p];
306:     }
307:     maxHeight = bins[0];
308:     if (maxHeight > ymax) ymax = hist->ymax = maxHeight;
309:     xmax = xmin + 1;
310:     PetscDrawAxisSetLimits(hist->axis, xmin, xmax, ymin, ymax);
311:     if (hist->calcStats) {
312:       mean /= numValues;
313:       if (numValues > 1) {
314:         var = (var - numValues*mean*mean) / (numValues-1);
315:       } else {
316:         var = 0.0;
317:       }
318:       sprintf(title,  "Mean: %g  Var: %g", mean, var);
319:       sprintf(xlabel, "Total: %d", numValues);
320:       ierr  = PetscDrawAxisSetLabels(hist->axis, title, xlabel, PETSC_NULL);
321:     }
322:     PetscDrawAxisDraw(hist->axis);
323:     /* Draw bins */
324:     binLeft   = xmin;
325:     binRight  = xmax;
326:     PetscDrawRectangle(draw,binLeft,ymin,binRight,bins[0],bcolor,bcolor,bcolor,bcolor);
327:     if (color == PETSC_DRAW_ROTATE && bins[0]) bcolor++; if (bcolor > 31) bcolor = 2;
328:     PetscDrawLine(draw,binLeft,ymin,binLeft,bins[0],PETSC_DRAW_BLACK);
329:     PetscDrawLine(draw,binRight,ymin,binRight,bins[0],PETSC_DRAW_BLACK);
330:     PetscDrawLine(draw,binLeft,bins[0],binRight,bins[0],PETSC_DRAW_BLACK);
331:   } else {
332:     numBins    = hist->numBins;
333:     numBinsOld = hist->numBins;
334:     if ((hist->integerBins == PETSC_TRUE) && (((int) xmax - xmin) + 1.0e-05 > xmax - xmin)) {
335:       initSize = (int) ((int) xmax - xmin)/numBins;
336:       while (initSize*numBins != (int) xmax - xmin) {
337:         initSize = PetscMax(initSize - 1, 1);
338:         numBins  = (int) ((int) xmax - xmin)/initSize;
339:         ierr     = PetscDrawHGSetNumberBins(hist, numBins);
340:       }
341:     }
342:     binSize = (xmax - xmin)/numBins;
343:     bins    = hist->bins;

345:     PetscMemzero(bins, numBins * sizeof(PetscReal));
346:     maxHeight = 0;
347:     for (i = 0; i < numBins; i++) {
348:       binLeft   = xmin + binSize*i;
349:       binRight  = xmin + binSize*(i+1);
350:       for(p = 0; p < numValues; p++) {
351:         if ((values[p] >= binLeft) && (values[p] < binRight)) bins[i]++;
352:         /* Handle last bin separately */
353:         if ((i == numBins-1) && (values[p] == binRight)) bins[i]++;
354:         if (i == 0) {
355:           mean += values[p];
356:           var  += values[p]*values[p];
357:         }
358:       }
359:       maxHeight = PetscMax(maxHeight, bins[i]);
360:     }
361:     if (maxHeight > ymax) ymax = hist->ymax = maxHeight;

363:     PetscDrawAxisSetLimits(hist->axis, xmin, xmax, ymin, ymax);
364:     if (hist->calcStats) {
365:       mean /= numValues;
366:       if (numValues > 1) {
367:         var = (var - numValues*mean*mean) / (numValues-1);
368:       } else {
369:         var = 0.0;
370:       }
371:       sprintf(title, "Mean: %g  Var: %g", mean, var);
372:       sprintf(xlabel, "Total: %d", numValues);
373:       ierr  = PetscDrawAxisSetLabels(hist->axis, title, xlabel, PETSC_NULL);
374:     }
375:     PetscDrawAxisDraw(hist->axis);
376:     /* Draw bins */
377:     for (i = 0; i < numBins; i++) {
378:       binLeft   = xmin + binSize*i;
379:       binRight  = xmin + binSize*(i+1);
380:       PetscDrawRectangle(draw,binLeft,ymin,binRight,bins[i],bcolor,bcolor,bcolor,bcolor);
381:       if (color == PETSC_DRAW_ROTATE && bins[i]) bcolor++; if (bcolor > 31) bcolor = 2;
382:       PetscDrawLine(draw,binLeft,ymin,binLeft,bins[i],PETSC_DRAW_BLACK);
383:       PetscDrawLine(draw,binRight,ymin,binRight,bins[i],PETSC_DRAW_BLACK);
384:       PetscDrawLine(draw,binLeft,bins[i],binRight,bins[i],PETSC_DRAW_BLACK);
385:     }
386:     PetscDrawHGSetNumberBins(hist, numBinsOld);
387:   }
388:   PetscDrawSynchronizedFlush(draw);
389:   PetscDrawPause(draw);
390:   return(0);
391: }

393: /*@
394:   PetscDrawHGPrint - Prints the histogram information.

396:   Not collective

398:   Input Parameter:
399: . hist - The histogram context

401:   Level: beginner

403:   Contributed by: Matthew Knepley

405: .keywords:  draw, histogram
406: @*/
407: int PetscDrawHGPrint(PetscDrawHG hist)
408: {
409:   PetscReal xmax,xmin,*bins,*values,binSize,binLeft,binRight,mean,var;
410:   int       numBins,numBinsOld,numValues,initSize,i,p,ierr;

414:   if ((hist->xmin > hist->xmax) || (hist->ymin >= hist->ymax)) return(0);
415:   if (hist->numValues < 1) return(0);

417:   xmax      = hist->xmax;
418:   xmin      = hist->xmin;
419:   numValues = hist->numValues;
420:   values    = hist->values;
421:   mean      = 0.0;
422:   var       = 0.0;
423:   if (xmax == xmin) {
424:     /* Calculate number of points in the bin */
425:     bins    = hist->bins;
426:     bins[0] = 0;
427:     for(p = 0; p < numValues; p++) {
428:       if (values[p] == xmin) bins[0]++;
429:       mean += values[p];
430:       var  += values[p]*values[p];
431:     }
432:     /* Draw bins */
433:     PetscPrintf(hist->comm, "Bin %2d (%6.2g - %6.2g): %.0gn", 0, xmin, xmax, bins[0]);
434:   } else {
435:     numBins    = hist->numBins;
436:     numBinsOld = hist->numBins;
437:     if ((hist->integerBins == PETSC_TRUE) && (((int) xmax - xmin) + 1.0e-05 > xmax - xmin)) {
438:       initSize = (int) ((int) xmax - xmin)/numBins;
439:       while (initSize*numBins != (int) xmax - xmin) {
440:         initSize = PetscMax(initSize - 1, 1);
441:         numBins  = (int) ((int) xmax - xmin)/initSize;
442:         ierr     = PetscDrawHGSetNumberBins(hist, numBins);
443:       }
444:     }
445:     binSize = (xmax - xmin)/numBins;
446:     bins    = hist->bins;

448:     /* Calculate number of points in each bin */
449:     PetscMemzero(bins, numBins * sizeof(PetscReal));
450:     for (i = 0; i < numBins; i++) {
451:       binLeft   = xmin + binSize*i;
452:       binRight  = xmin + binSize*(i+1);
453:       for(p = 0; p < numValues; p++) {
454:         if ((values[p] >= binLeft) && (values[p] < binRight)) bins[i]++;
455:         /* Handle last bin separately */
456:         if ((i == numBins-1) && (values[p] == binRight)) bins[i]++;
457:         if (i == 0) {
458:           mean += values[p];
459:           var  += values[p]*values[p];
460:         }
461:       }
462:     }
463:     /* Draw bins */
464:     for (i = 0; i < numBins; i++) {
465:       binLeft   = xmin + binSize*i;
466:       binRight  = xmin + binSize*(i+1);
467:       PetscPrintf(hist->comm, "Bin %2d (%6.2g - %6.2g): %.0gn", i, binLeft, binRight, bins[i]);
468:     }
469:     PetscDrawHGSetNumberBins(hist, numBinsOld);
470:   }

472:   if (hist->calcStats) {
473:     mean /= numValues;
474:     if (numValues > 1) {
475:       var = (var - numValues*mean*mean) / (numValues-1);
476:     } else {
477:       var = 0.0;
478:     }
479:     PetscPrintf(hist->comm, "Mean: %g  Var: %gn", mean, var);
480:     PetscPrintf(hist->comm, "Total: %dn", numValues);
481:   }
482:   return(0);
483: }
484: 
485: /*@
486:   PetscDrawHGSetColor - Sets the color the bars will be drawn with.

488:   Not Collective (ignored except on processor 0 of PetscDrawHG)

490:   Input Parameters:
491: + hist - The histogram context
492: - color - one of the colors defined in petscdraw.h or PETSC_DRAW_ROTATE to make each bar a 
493:           different color

495:   Level: intermediate

497: @*/
498: int PetscDrawHGSetColor(PetscDrawHG hist, int color)
499: {
502:   hist->color = color;
503:   return(0);
504: }

506: /*@
507:   PetscDrawHGSetLimits - Sets the axis limits for a histogram. If more
508:   points are added after this call, the limits will be adjusted to
509:   include those additional points.

511:   Not Collective (ignored except on processor 0 of PetscDrawHG)

513:   Input Parameters:
514: + hist - The histogram context
515: - x_min,x_max,y_min,y_max - The limits

517:   Level: intermediate

519:   Contributed by: Matthew Knepley

521:   Concepts: histogram^setting axis
522: @*/
523: int PetscDrawHGSetLimits(PetscDrawHG hist, PetscReal x_min, PetscReal x_max, int y_min, int y_max)
524: {
527:   hist->xmin = x_min;
528:   hist->xmax = x_max;
529:   hist->ymin = y_min;
530:   hist->ymax = y_max;
531:   return(0);
532: }

534: /*@
535:   PetscDrawHGCalcStats - Turns on calculation of descriptive statistics

537:   Not collective

539:   Input Parameters:
540: + hist - The histogram context
541: - calc - Flag for calculation

543:   Level: intermediate

545:   Contributed by: Matthew Knepley

547: .keywords:  draw, histogram, statistics

549: @*/
550: int PetscDrawHGCalcStats(PetscDrawHG hist, PetscTruth calc)
551: {
554:   hist->calcStats = calc;
555:   return(0);
556: }

558: /*@
559:   PetscDrawHGIntegerBins - Turns on integer width bins

561:   Not collective

563:   Input Parameters:
564: + hist - The histogram context
565: - ints - Flag for integer width bins

567:   Level: intermediate

569:   Contributed by: Matthew Knepley

571: .keywords:  draw, histogram, statistics
572: @*/
573: int PetscDrawHGIntegerBins(PetscDrawHG hist, PetscTruth ints)
574: {
577:   hist->integerBins = ints;
578:   return(0);
579: }

581: /*@C
582:   PetscDrawHGGetAxis - Gets the axis context associated with a histogram.
583:   This is useful if one wants to change some axis property, such as
584:   labels, color, etc. The axis context should not be destroyed by the
585:   application code.

587:   Not Collective (ignored except on processor 0 of PetscDrawHG)

589:   Input Parameter:
590: . hist - The histogram context

592:   Output Parameter:
593: . axis - The axis context

595:   Level: intermediate

597:   Contributed by: Matthew Knepley
598: @*/
599: int PetscDrawHGGetAxis(PetscDrawHG hist, PetscDrawAxis *axis)
600: {
603:   *axis = hist->axis;
604:   return(0);
605: }

607: /*@C
608:   PetscDrawHGGetDraw - Gets the draw context associated with a histogram.

610:   Not Collective, PetscDraw is parallel if PetscDrawHG is parallel

612:   Input Parameter:
613: . hist - The histogram context

615:   Output Parameter:
616: . win  - The draw context

618:   Level: intermediate

620:   Contributed by: Matthew Knepley
621: @*/
622: int PetscDrawHGGetDraw(PetscDrawHG hist, PetscDraw *win)
623: {
626:   *win = hist->win;
627:   return(0);
628: }