Actual source code: lgc.c


  2: #include <petscviewer.h>
  3: #include <petsc/private/drawimpl.h>
  4: PetscClassId PETSC_DRAWLG_CLASSID = 0;

  6: /*@
  7:    PetscDrawLGGetAxis - Gets the axis context associated with a line graph.
  8:    This is useful if one wants to change some axis property, such as
  9:    labels, color, etc. The axis context should not be destroyed by the
 10:    application code.

 12:    Not Collective, if lg is parallel then axis is parallel

 14:    Input Parameter:
 15: .  lg - the line graph context

 17:    Output Parameter:
 18: .  axis - the axis context

 20:    Level: advanced

 22: .seealso: `PetscDrawLGCreate()`, `PetscDrawAxis`, `PetscDrawLG`
 23: @*/
 24: PetscErrorCode PetscDrawLGGetAxis(PetscDrawLG lg, PetscDrawAxis *axis)
 25: {
 28:   *axis = lg->axis;
 29:   return 0;
 30: }

 32: /*@
 33:    PetscDrawLGGetDraw - Gets the draw context associated with a line graph.

 35:    Not Collective, if lg is parallel then draw is parallel

 37:    Input Parameter:
 38: .  lg - the line graph context

 40:    Output Parameter:
 41: .  draw - the draw context

 43:    Level: intermediate

 45: .seealso: `PetscDrawLGCreate()`, `PetscDraw`, `PetscDrawLG`
 46: @*/
 47: PetscErrorCode PetscDrawLGGetDraw(PetscDrawLG lg, PetscDraw *draw)
 48: {
 51:   *draw = lg->win;
 52:   return 0;
 53: }

 55: /*@
 56:   PetscDrawLGSPDraw - Redraws a line graph and a scatter plot on the same `PetscDraw` they must share

 58:    Collective

 60:    Input Parameters:
 61: +  lg - the line graph context
 62: -  spin - the scatter plot

 64:    Level: intermediate

 66:    Developer Note:
 67:     This code cheats and uses the fact that the `PetscDrawLG` and `PetscDrawSP` structs are the same

 69: .seealso: `PetscDrawLGDraw()`, `PetscDrawSPDraw()`
 70: @*/
 71: PetscErrorCode PetscDrawLGSPDraw(PetscDrawLG lg, PetscDrawSP spin)
 72: {
 73:   PetscDrawLG sp = (PetscDrawLG)spin;
 74:   PetscReal   xmin, xmax, ymin, ymax;
 75:   PetscBool   isnull;
 76:   PetscMPIInt rank;
 77:   PetscDraw   draw;

 81:   PetscDrawIsNull(lg->win, &isnull);
 82:   if (isnull) return 0;
 83:   MPI_Comm_rank(PetscObjectComm((PetscObject)lg), &rank);

 85:   draw = lg->win;
 86:   PetscDrawCheckResizedWindow(draw);
 87:   PetscDrawClear(draw);

 89:   xmin = PetscMin(lg->xmin, sp->xmin);
 90:   ymin = PetscMin(lg->ymin, sp->ymin);
 91:   xmax = PetscMax(lg->xmax, sp->xmax);
 92:   ymax = PetscMax(lg->ymax, sp->ymax);
 93:   PetscDrawAxisSetLimits(lg->axis, xmin, xmax, ymin, ymax);
 94:   PetscDrawAxisDraw(lg->axis);

 96:   PetscDrawCollectiveBegin(draw);
 97:   if (rank == 0) {
 98:     int i, j, dim, nopts;
 99:     dim   = lg->dim;
100:     nopts = lg->nopts;
101:     for (i = 0; i < dim; i++) {
102:       for (j = 1; j < nopts; j++) {
103:         PetscDrawLine(draw, lg->x[(j - 1) * dim + i], lg->y[(j - 1) * dim + i], lg->x[j * dim + i], lg->y[j * dim + i], PETSC_DRAW_BLACK + i);
104:         if (lg->use_markers) PetscDrawMarker(draw, lg->x[j * dim + i], lg->y[j * dim + i], PETSC_DRAW_RED);
105:       }
106:     }
107:     dim   = sp->dim;
108:     nopts = sp->nopts;
109:     for (i = 0; i < dim; i++) {
110:       for (j = 0; j < nopts; j++) PetscDrawMarker(draw, sp->x[j * dim + i], sp->y[j * dim + i], PETSC_DRAW_RED);
111:     }
112:   }
113:   PetscDrawCollectiveEnd(draw);

115:   PetscDrawFlush(draw);
116:   PetscDrawPause(draw);
117:   return 0;
118: }

120: /*@
121:     PetscDrawLGCreate - Creates a line graph data structure.

123:     Collective

125:     Input Parameters:
126: +   draw - the window where the graph will be made.
127: -   dim - the number of curves which will be drawn

129:     Output Parameters:
130: .   outlg - the line graph context

132:     Level: intermediate

134:     Notes:
135:     The MPI communicator that owns the `PetscDraw` owns this `PetscDrawLG`, but the calls to set options and add points are ignored on all processes except the
136:            zeroth MPI process in the communicator.

138:     All MPI ranks in the communicator must call `PetscDrawLGDraw()` to display the updated graph.

140: .seealso: `PetscDrawLGCreate`, `PetscDrawLGDestroy()`, `PetscDrawLGAddPoint()`, `PetscDrawLGAddCommonPoint()`, `PetscDrawLGAddPoints()`, `PetscDrawLGDraw()`, `PetscDrawLGSave()`,
141:           `PetscDrawLGView()`, `PetscDrawLGReset()`, `PetscDrawLGSetDimension()`, `PetscDrawLGGetDimension()`, `PetscDrawLGSetLegend()`, `PetscDrawLGGetAxis()`,
142:           `PetscDrawLGGetDraw()`, `PetscDrawLGSetUseMarkers()`, `PetscDrawLGSetLimits()`, `PetscDrawLGSetColors()`, `PetscDrawLGSetOptionsPrefix()`, `PetscDrawLGSetFromOptions()`
143: @*/
144: PetscErrorCode PetscDrawLGCreate(PetscDraw draw, PetscInt dim, PetscDrawLG *outlg)
145: {
146:   PetscDrawLG lg;


152:   PetscHeaderCreate(lg, PETSC_DRAWLG_CLASSID, "DrawLG", "Line Graph", "Draw", PetscObjectComm((PetscObject)draw), PetscDrawLGDestroy, NULL);
153:   PetscDrawLGSetOptionsPrefix(lg, ((PetscObject)draw)->prefix);

155:   PetscObjectReference((PetscObject)draw);
156:   lg->win = draw;

158:   lg->view    = NULL;
159:   lg->destroy = NULL;
160:   lg->nopts   = 0;
161:   lg->dim     = dim;
162:   lg->xmin    = 1.e20;
163:   lg->ymin    = 1.e20;
164:   lg->xmax    = -1.e20;
165:   lg->ymax    = -1.e20;

167:   PetscMalloc2(dim * PETSC_DRAW_LG_CHUNK_SIZE, &lg->x, dim * PETSC_DRAW_LG_CHUNK_SIZE, &lg->y);

169:   lg->len         = dim * PETSC_DRAW_LG_CHUNK_SIZE;
170:   lg->loc         = 0;
171:   lg->use_markers = PETSC_FALSE;

173:   PetscDrawAxisCreate(draw, &lg->axis);

175:   *outlg = lg;
176:   return 0;
177: }

179: /*@
180:    PetscDrawLGSetColors - Sets the color of each line graph drawn

182:    Logically Collective

184:    Input Parameters:
185: +  lg - the line graph context.
186: -  colors - the colors

188:    Level: intermediate

190: .seealso: `PetscDrawLG`, `PetscDrawLGCreate()`
191: @*/
192: PetscErrorCode PetscDrawLGSetColors(PetscDrawLG lg, const int colors[])
193: {

197:   PetscFree(lg->colors);
198:   PetscMalloc1(lg->dim, &lg->colors);
199:   PetscArraycpy(lg->colors, colors, lg->dim);
200:   return 0;
201: }

203: /*@C
204:    PetscDrawLGSetLegend - sets the names of each curve plotted

206:    Logically Collective

208:    Input Parameters:
209: +  lg - the line graph context.
210: -  names - the names for each curve

212:    Level: intermediate

214:    Note:
215:     Call `PetscDrawLGGetAxis()` and then change properties of the `PetscDrawAxis` for detailed control of the plot

217: .seealso: `PetscDrawLGGetAxis()`, `PetscDrawAxis`, `PetscDrawAxisSetColors()`, `PetscDrawAxisSetLabels()`, `PetscDrawAxisSetHoldLimits()`
218: @*/
219: PetscErrorCode PetscDrawLGSetLegend(PetscDrawLG lg, const char *const *names)
220: {
221:   PetscInt i;


226:   if (lg->legend) {
227:     for (i = 0; i < lg->dim; i++) PetscFree(lg->legend[i]);
228:     PetscFree(lg->legend);
229:   }
230:   if (names) {
231:     PetscMalloc1(lg->dim, &lg->legend);
232:     for (i = 0; i < lg->dim; i++) PetscStrallocpy(names[i], &lg->legend[i]);
233:   }
234:   return 0;
235: }

237: /*@
238:    PetscDrawLGGetDimension - Get the number of curves that are to be drawn.

240:    Not Collective

242:    Input Parameter:
243: .  lg - the line graph context.

245:    Output Parameter:
246: .  dim - the number of curves.

248:    Level: intermediate

250: .seealso: `PetscDrawLGC`, `PetscDrawLGCreate()`, `PetscDrawLGSetDimension()`
251: @*/
252: PetscErrorCode PetscDrawLGGetDimension(PetscDrawLG lg, PetscInt *dim)
253: {
256:   *dim = lg->dim;
257:   return 0;
258: }

260: /*@
261:    PetscDrawLGSetDimension - Change the number of curves that are to be drawn.

263:    Logically Collective

265:    Input Parameters:
266: +  lg - the line graph context.
267: -  dim - the number of curves.

269:    Level: intermediate

271: .seealso: `PetscDrawLGCreate()`, `PetscDrawLGGetDimension()`
272: @*/
273: PetscErrorCode PetscDrawLGSetDimension(PetscDrawLG lg, PetscInt dim)
274: {
275:   PetscInt i;

279:   if (lg->dim == dim) return 0;

281:   PetscFree2(lg->x, lg->y);
282:   if (lg->legend) {
283:     for (i = 0; i < lg->dim; i++) PetscFree(lg->legend[i]);
284:     PetscFree(lg->legend);
285:   }
286:   PetscFree(lg->colors);
287:   lg->dim = dim;
288:   PetscMalloc2(dim * PETSC_DRAW_LG_CHUNK_SIZE, &lg->x, dim * PETSC_DRAW_LG_CHUNK_SIZE, &lg->y);
289:   lg->len = dim * PETSC_DRAW_LG_CHUNK_SIZE;
290:   return 0;
291: }

293: /*@
294:    PetscDrawLGSetLimits - Sets the axis limits for a line graph. If more
295:    points are added after this call, the limits will be adjusted to
296:    include those additional points.

298:    Logically Collective

300:    Input Parameters:
301: +  xlg - the line graph context
302: -  x_min,x_max,y_min,y_max - the limits

304:    Level: intermediate

306: .seealso: `PetscDrawLGCreate()`, `PetscDrawLG`, `PetscDrawAxis`
307: @*/
308: PetscErrorCode PetscDrawLGSetLimits(PetscDrawLG lg, PetscReal x_min, PetscReal x_max, PetscReal y_min, PetscReal y_max)
309: {

312:   (lg)->xmin = x_min;
313:   (lg)->xmax = x_max;
314:   (lg)->ymin = y_min;
315:   (lg)->ymax = y_max;
316:   return 0;
317: }

319: /*@
320:    PetscDrawLGReset - Clears line graph to allow for reuse with new data.

322:    Logically Collective

324:    Input Parameter:
325: .  lg - the line graph context.

327:    Level: intermediate

329: .seealso: `PetscDrawLG`, `PetscDrawLGCreate()`
330: @*/
331: PetscErrorCode PetscDrawLGReset(PetscDrawLG lg)
332: {
334:   lg->xmin  = 1.e20;
335:   lg->ymin  = 1.e20;
336:   lg->xmax  = -1.e20;
337:   lg->ymax  = -1.e20;
338:   lg->loc   = 0;
339:   lg->nopts = 0;
340:   return 0;
341: }

343: /*@
344:    PetscDrawLGDestroy - Frees all space taken up by line graph data structure.

346:    Collective

348:    Input Parameter:
349: .  lg - the line graph context

351:    Level: intermediate

353: .seealso: `PetscDrawLG`, `PetscDrawLGCreate()`
354: @*/
355: PetscErrorCode PetscDrawLGDestroy(PetscDrawLG *lg)
356: {
357:   PetscInt i;

359:   if (!*lg) return 0;
361:   if (--((PetscObject)(*lg))->refct > 0) {
362:     *lg = NULL;
363:     return 0;
364:   }

366:   if ((*lg)->legend) {
367:     for (i = 0; i < (*lg)->dim; i++) PetscFree((*lg)->legend[i]);
368:     PetscFree((*lg)->legend);
369:   }
370:   PetscFree((*lg)->colors);
371:   PetscFree2((*lg)->x, (*lg)->y);
372:   PetscDrawAxisDestroy(&(*lg)->axis);
373:   PetscDrawDestroy(&(*lg)->win);
374:   PetscHeaderDestroy(lg);
375:   return 0;
376: }
377: /*@
378:    PetscDrawLGSetUseMarkers - Causes the line graph object to draw a marker for each data-point.

380:    Logically Collective

382:    Input Parameters:
383: +  lg - the linegraph context
384: -  flg - should mark each data point

386:    Options Database Key:
387: .  -lg_use_markers  <true,false> - true means it draws a marker for each point

389:    Level: intermediate

391: .seealso: `PetscDrawLG`, `PetscDrawLGCreate()`
392: @*/
393: PetscErrorCode PetscDrawLGSetUseMarkers(PetscDrawLG lg, PetscBool flg)
394: {
397:   lg->use_markers = flg;
398:   return 0;
399: }

401: /*@
402:    PetscDrawLGDraw - Redraws a line graph.

404:    Collective

406:    Input Parameter:
407: .  lg - the line graph context

409:    Level: intermediate

411: .seealso: `PetscDrawLG`, `PetscDrawSPDraw()`, `PetscDrawLGSPDraw()`, `PetscDrawLGReset()`
412: @*/
413: PetscErrorCode PetscDrawLGDraw(PetscDrawLG lg)
414: {
415:   PetscReal   xmin, xmax, ymin, ymax;
416:   PetscMPIInt rank;
417:   PetscDraw   draw;
418:   PetscBool   isnull;

421:   PetscDrawIsNull(lg->win, &isnull);
422:   if (isnull) return 0;
423:   MPI_Comm_rank(PetscObjectComm((PetscObject)lg), &rank);

425:   draw = lg->win;
426:   PetscDrawCheckResizedWindow(draw);
427:   PetscDrawClear(draw);

429:   xmin = lg->xmin;
430:   xmax = lg->xmax;
431:   ymin = lg->ymin;
432:   ymax = lg->ymax;
433:   PetscDrawAxisSetLimits(lg->axis, xmin, xmax, ymin, ymax);
434:   PetscDrawAxisDraw(lg->axis);

436:   PetscDrawCollectiveBegin(draw);
437:   if (rank == 0) {
438:     int i, j, dim = lg->dim, nopts = lg->nopts, cl;
439:     for (i = 0; i < dim; i++) {
440:       for (j = 1; j < nopts; j++) {
441:         cl = lg->colors ? lg->colors[i] : ((PETSC_DRAW_BLACK + i) % PETSC_DRAW_MAXCOLOR);
442:         PetscDrawLine(draw, lg->x[(j - 1) * dim + i], lg->y[(j - 1) * dim + i], lg->x[j * dim + i], lg->y[j * dim + i], cl);
443:         if (lg->use_markers) PetscDrawMarker(draw, lg->x[j * dim + i], lg->y[j * dim + i], cl);
444:       }
445:     }
446:   }
447:   if (rank == 0 && lg->legend) {
448:     PetscBool right = PETSC_FALSE;
449:     int       i, dim = lg->dim, cl;
450:     PetscReal xl, yl, xr, yr, tw, th;
451:     size_t    slen, len = 0;
452:     PetscDrawAxisGetLimits(lg->axis, &xl, &xr, &yl, &yr);
453:     PetscDrawStringGetSize(draw, &tw, &th);
454:     for (i = 0; i < dim; i++) {
455:       PetscStrlen(lg->legend[i], &slen);
456:       len = PetscMax(len, slen);
457:     }
458:     if (right) {
459:       xr = xr - 1.5 * tw;
460:       xl = xr - (len + 7) * tw;
461:     } else {
462:       xl = xl + 1.5 * tw;
463:       xr = xl + (len + 7) * tw;
464:     }
465:     yr = yr - 1.0 * th;
466:     yl = yr - (dim + 1) * th;
467:     PetscDrawLine(draw, xl, yl, xr, yl, PETSC_DRAW_BLACK);
468:     PetscDrawLine(draw, xr, yl, xr, yr, PETSC_DRAW_BLACK);
469:     PetscDrawLine(draw, xr, yr, xl, yr, PETSC_DRAW_BLACK);
470:     PetscDrawLine(draw, xl, yr, xl, yl, PETSC_DRAW_BLACK);
471:     for (i = 0; i < dim; i++) {
472:       cl = lg->colors ? lg->colors[i] : (PETSC_DRAW_BLACK + i);
473:       PetscDrawLine(draw, xl + 1 * tw, yr - (i + 1) * th, xl + 5 * tw, yr - (i + 1) * th, cl);
474:       PetscDrawString(draw, xl + 6 * tw, yr - (i + 1.5) * th, PETSC_DRAW_BLACK, lg->legend[i]);
475:     }
476:   }
477:   PetscDrawCollectiveEnd(draw);

479:   PetscDrawFlush(draw);
480:   PetscDrawPause(draw);
481:   return 0;
482: }

484: /*@
485:   PetscDrawLGSave - Saves a drawn image

487:   Collective

489:   Input Parameter:
490: . lg - The line graph context

492:   Level: intermediate

494: .seealso: `PetscDrawLG`, `PetscDrawSave()`, `PetscDrawLGCreate()`, `PetscDrawLGGetDraw()`, `PetscDrawSetSave()`, `PetscDrawSave()`
495: @*/
496: PetscErrorCode PetscDrawLGSave(PetscDrawLG lg)
497: {
499:   PetscDrawSave(lg->win);
500:   return 0;
501: }

503: /*@
504:   PetscDrawLGView - Prints a line graph.

506:   Collective

508:   Input Parameter:
509: . lg - the line graph context

511:   Level: beginner

513: .seealso: `PetscDrawLG`, `PetscDrawLGCreate()`
514: @*/
515: PetscErrorCode PetscDrawLGView(PetscDrawLG lg, PetscViewer viewer)
516: {
517:   PetscReal xmin = lg->xmin, xmax = lg->xmax, ymin = lg->ymin, ymax = lg->ymax;
518:   PetscInt  i, j, dim = lg->dim, nopts = lg->nopts;


522:   if (nopts < 1) return 0;
523:   if (xmin > xmax || ymin > ymax) return 0;

525:   if (!viewer) PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)lg), &viewer);
526:   PetscObjectPrintClassNamePrefixType((PetscObject)lg, viewer);
527:   for (i = 0; i < dim; i++) {
528:     PetscViewerASCIIPrintf(viewer, "Line %" PetscInt_FMT ">\n", i);
529:     for (j = 0; j < nopts; j++) PetscViewerASCIIPrintf(viewer, "  X: %g Y: %g\n", (double)lg->x[j * dim + i], (double)lg->y[j * dim + i]);
530:   }
531:   return 0;
532: }

534: /*@C
535:    PetscDrawLGSetOptionsPrefix - Sets the prefix used for searching for all
536:    `PetscDrawLG` options in the database.

538:    Logically Collective

540:    Input Parameters:
541: +  lg - the line graph context
542: -  prefix - the prefix to prepend to all option names

544:    Level: advanced

546: .seealso: `PetscDrawLG`, `PetscDrawLGSetFromOptions()`, `PetscDrawLGCreate()`
547: @*/
548: PetscErrorCode PetscDrawLGSetOptionsPrefix(PetscDrawLG lg, const char prefix[])
549: {
551:   PetscObjectSetOptionsPrefix((PetscObject)lg, prefix);
552:   return 0;
553: }

555: /*@
556:     PetscDrawLGSetFromOptions - Sets options related to the line graph object

558:     Collective

560:     Input Parameters:
561: .   lg - the line graph context

563:     Options Database Key:
564: .  -lg_use_markers  <true,false> - true means it draws a marker for each point

566:     Level: intermediate

568: .seealso: `PetscDrawLG`, `PetscDrawLGDestroy()`, `PetscDrawLGCreate()`
569: @*/
570: PetscErrorCode PetscDrawLGSetFromOptions(PetscDrawLG lg)
571: {
572:   PetscBool           usemarkers, set;
573:   PetscDrawMarkerType markertype;


577:   PetscDrawGetMarkerType(lg->win, &markertype);
578:   PetscOptionsGetEnum(((PetscObject)lg)->options, ((PetscObject)lg)->prefix, "-lg_marker_type", PetscDrawMarkerTypes, (PetscEnum *)&markertype, &set);
579:   if (set) {
580:     PetscDrawLGSetUseMarkers(lg, PETSC_TRUE);
581:     PetscDrawSetMarkerType(lg->win, markertype);
582:   }
583:   usemarkers = lg->use_markers;
584:   PetscOptionsGetBool(((PetscObject)lg)->options, ((PetscObject)lg)->prefix, "-lg_use_markers", &usemarkers, &set);
585:   if (set) PetscDrawLGSetUseMarkers(lg, usemarkers);
586:   return 0;
587: }