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: {
 26:   PetscFunctionBegin;
 29:   *axis = lg->axis;
 30:   PetscFunctionReturn(PETSC_SUCCESS);
 31: }

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

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

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

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

 44:    Level: intermediate

 46: .seealso: `PetscDrawLGCreate()`, `PetscDraw`, `PetscDrawLG`
 47: @*/
 48: PetscErrorCode PetscDrawLGGetDraw(PetscDrawLG lg, PetscDraw *draw)
 49: {
 50:   PetscFunctionBegin;
 53:   *draw = lg->win;
 54:   PetscFunctionReturn(PETSC_SUCCESS);
 55: }

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

 60:    Collective

 62:    Input Parameters:
 63: +  lg - the line graph context
 64: -  spin - the scatter plot

 66:    Level: intermediate

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

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

 81:   PetscFunctionBegin;
 84:   PetscCall(PetscDrawIsNull(lg->win, &isnull));
 85:   if (isnull) PetscFunctionReturn(PETSC_SUCCESS);
 86:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)lg), &rank));

 88:   draw = lg->win;
 89:   PetscCall(PetscDrawCheckResizedWindow(draw));
 90:   PetscCall(PetscDrawClear(draw));

 92:   xmin = PetscMin(lg->xmin, sp->xmin);
 93:   ymin = PetscMin(lg->ymin, sp->ymin);
 94:   xmax = PetscMax(lg->xmax, sp->xmax);
 95:   ymax = PetscMax(lg->ymax, sp->ymax);
 96:   PetscCall(PetscDrawAxisSetLimits(lg->axis, xmin, xmax, ymin, ymax));
 97:   PetscCall(PetscDrawAxisDraw(lg->axis));

 99:   PetscDrawCollectiveBegin(draw);
100:   if (rank == 0) {
101:     int i, j, dim, nopts;
102:     dim   = lg->dim;
103:     nopts = lg->nopts;
104:     for (i = 0; i < dim; i++) {
105:       for (j = 1; j < nopts; j++) {
106:         PetscCall(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));
107:         if (lg->use_markers) PetscCall(PetscDrawMarker(draw, lg->x[j * dim + i], lg->y[j * dim + i], PETSC_DRAW_RED));
108:       }
109:     }
110:     dim   = sp->dim;
111:     nopts = sp->nopts;
112:     for (i = 0; i < dim; i++) {
113:       for (j = 0; j < nopts; j++) PetscCall(PetscDrawMarker(draw, sp->x[j * dim + i], sp->y[j * dim + i], PETSC_DRAW_RED));
114:     }
115:   }
116:   PetscDrawCollectiveEnd(draw);

118:   PetscCall(PetscDrawFlush(draw));
119:   PetscCall(PetscDrawPause(draw));
120:   PetscFunctionReturn(PETSC_SUCCESS);
121: }

123: /*@
124:     PetscDrawLGCreate - Creates a line graph data structure.

126:     Collective

128:     Input Parameters:
129: +   draw - the window where the graph will be made.
130: -   dim - the number of curves which will be drawn

132:     Output Parameters:
133: .   outlg - the line graph context

135:     Level: intermediate

137:     Notes:
138:     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
139:            zeroth MPI process in the communicator.

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

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

151:   PetscFunctionBegin;

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

159:   PetscCall(PetscObjectReference((PetscObject)draw));
160:   lg->win = draw;

162:   lg->view    = NULL;
163:   lg->destroy = NULL;
164:   lg->nopts   = 0;
165:   lg->dim     = dim;
166:   lg->xmin    = 1.e20;
167:   lg->ymin    = 1.e20;
168:   lg->xmax    = -1.e20;
169:   lg->ymax    = -1.e20;

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

173:   lg->len         = dim * PETSC_DRAW_LG_CHUNK_SIZE;
174:   lg->loc         = 0;
175:   lg->use_markers = PETSC_FALSE;

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

179:   *outlg = lg;
180:   PetscFunctionReturn(PETSC_SUCCESS);
181: }

183: /*@
184:    PetscDrawLGSetColors - Sets the color of each line graph drawn

186:    Logically Collective

188:    Input Parameters:
189: +  lg - the line graph context.
190: -  colors - the colors

192:    Level: intermediate

194: .seealso: `PetscDrawLG`, `PetscDrawLGCreate()`
195: @*/
196: PetscErrorCode PetscDrawLGSetColors(PetscDrawLG lg, const int colors[])
197: {
198:   PetscFunctionBegin;

202:   PetscCall(PetscFree(lg->colors));
203:   PetscCall(PetscMalloc1(lg->dim, &lg->colors));
204:   PetscCall(PetscArraycpy(lg->colors, colors, lg->dim));
205:   PetscFunctionReturn(PETSC_SUCCESS);
206: }

208: /*@C
209:    PetscDrawLGSetLegend - sets the names of each curve plotted

211:    Logically Collective

213:    Input Parameters:
214: +  lg - the line graph context.
215: -  names - the names for each curve

217:    Level: intermediate

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

222: .seealso: `PetscDrawLGGetAxis()`, `PetscDrawAxis`, `PetscDrawAxisSetColors()`, `PetscDrawAxisSetLabels()`, `PetscDrawAxisSetHoldLimits()`
223: @*/
224: PetscErrorCode PetscDrawLGSetLegend(PetscDrawLG lg, const char *const *names)
225: {
226:   PetscInt i;

228:   PetscFunctionBegin;

232:   if (lg->legend) {
233:     for (i = 0; i < lg->dim; i++) PetscCall(PetscFree(lg->legend[i]));
234:     PetscCall(PetscFree(lg->legend));
235:   }
236:   if (names) {
237:     PetscCall(PetscMalloc1(lg->dim, &lg->legend));
238:     for (i = 0; i < lg->dim; i++) PetscCall(PetscStrallocpy(names[i], &lg->legend[i]));
239:   }
240:   PetscFunctionReturn(PETSC_SUCCESS);
241: }

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

246:    Not Collective

248:    Input Parameter:
249: .  lg - the line graph context.

251:    Output Parameter:
252: .  dim - the number of curves.

254:    Level: intermediate

256: .seealso: `PetscDrawLGC`, `PetscDrawLGCreate()`, `PetscDrawLGSetDimension()`
257: @*/
258: PetscErrorCode PetscDrawLGGetDimension(PetscDrawLG lg, PetscInt *dim)
259: {
260:   PetscFunctionBegin;
263:   *dim = lg->dim;
264:   PetscFunctionReturn(PETSC_SUCCESS);
265: }

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

270:    Logically Collective

272:    Input Parameters:
273: +  lg - the line graph context.
274: -  dim - the number of curves.

276:    Level: intermediate

278: .seealso: `PetscDrawLGCreate()`, `PetscDrawLGGetDimension()`
279: @*/
280: PetscErrorCode PetscDrawLGSetDimension(PetscDrawLG lg, PetscInt dim)
281: {
282:   PetscInt i;

284:   PetscFunctionBegin;
287:   if (lg->dim == dim) PetscFunctionReturn(PETSC_SUCCESS);

289:   PetscCall(PetscFree2(lg->x, lg->y));
290:   if (lg->legend) {
291:     for (i = 0; i < lg->dim; i++) PetscCall(PetscFree(lg->legend[i]));
292:     PetscCall(PetscFree(lg->legend));
293:   }
294:   PetscCall(PetscFree(lg->colors));
295:   lg->dim = dim;
296:   PetscCall(PetscMalloc2(dim * PETSC_DRAW_LG_CHUNK_SIZE, &lg->x, dim * PETSC_DRAW_LG_CHUNK_SIZE, &lg->y));
297:   lg->len = dim * PETSC_DRAW_LG_CHUNK_SIZE;
298:   PetscFunctionReturn(PETSC_SUCCESS);
299: }

301: /*@
302:    PetscDrawLGSetLimits - Sets the axis limits for a line graph. If more
303:    points are added after this call, the limits will be adjusted to
304:    include those additional points.

306:    Logically Collective

308:    Input Parameters:
309: +  xlg - the line graph context
310: -  x_min,x_max,y_min,y_max - the limits

312:    Level: intermediate

314: .seealso: `PetscDrawLGCreate()`, `PetscDrawLG`, `PetscDrawAxis`
315: @*/
316: PetscErrorCode PetscDrawLGSetLimits(PetscDrawLG lg, PetscReal x_min, PetscReal x_max, PetscReal y_min, PetscReal y_max)
317: {
318:   PetscFunctionBegin;

321:   (lg)->xmin = x_min;
322:   (lg)->xmax = x_max;
323:   (lg)->ymin = y_min;
324:   (lg)->ymax = y_max;
325:   PetscFunctionReturn(PETSC_SUCCESS);
326: }

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

331:    Logically Collective

333:    Input Parameter:
334: .  lg - the line graph context.

336:    Level: intermediate

338: .seealso: `PetscDrawLG`, `PetscDrawLGCreate()`
339: @*/
340: PetscErrorCode PetscDrawLGReset(PetscDrawLG lg)
341: {
342:   PetscFunctionBegin;
344:   lg->xmin  = 1.e20;
345:   lg->ymin  = 1.e20;
346:   lg->xmax  = -1.e20;
347:   lg->ymax  = -1.e20;
348:   lg->loc   = 0;
349:   lg->nopts = 0;
350:   PetscFunctionReturn(PETSC_SUCCESS);
351: }

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

356:    Collective

358:    Input Parameter:
359: .  lg - the line graph context

361:    Level: intermediate

363: .seealso: `PetscDrawLG`, `PetscDrawLGCreate()`
364: @*/
365: PetscErrorCode PetscDrawLGDestroy(PetscDrawLG *lg)
366: {
367:   PetscInt i;

369:   PetscFunctionBegin;
370:   if (!*lg) PetscFunctionReturn(PETSC_SUCCESS);
372:   if (--((PetscObject)(*lg))->refct > 0) {
373:     *lg = NULL;
374:     PetscFunctionReturn(PETSC_SUCCESS);
375:   }

377:   if ((*lg)->legend) {
378:     for (i = 0; i < (*lg)->dim; i++) PetscCall(PetscFree((*lg)->legend[i]));
379:     PetscCall(PetscFree((*lg)->legend));
380:   }
381:   PetscCall(PetscFree((*lg)->colors));
382:   PetscCall(PetscFree2((*lg)->x, (*lg)->y));
383:   PetscCall(PetscDrawAxisDestroy(&(*lg)->axis));
384:   PetscCall(PetscDrawDestroy(&(*lg)->win));
385:   PetscCall(PetscHeaderDestroy(lg));
386:   PetscFunctionReturn(PETSC_SUCCESS);
387: }
388: /*@
389:    PetscDrawLGSetUseMarkers - Causes the line graph object to draw a marker for each data-point.

391:    Logically Collective

393:    Input Parameters:
394: +  lg - the linegraph context
395: -  flg - should mark each data point

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

400:    Level: intermediate

402: .seealso: `PetscDrawLG`, `PetscDrawLGCreate()`
403: @*/
404: PetscErrorCode PetscDrawLGSetUseMarkers(PetscDrawLG lg, PetscBool flg)
405: {
406:   PetscFunctionBegin;
409:   lg->use_markers = flg;
410:   PetscFunctionReturn(PETSC_SUCCESS);
411: }

413: /*@
414:    PetscDrawLGDraw - Redraws a line graph.

416:    Collective

418:    Input Parameter:
419: .  lg - the line graph context

421:    Level: intermediate

423: .seealso: `PetscDrawLG`, `PetscDrawSPDraw()`, `PetscDrawLGSPDraw()`, `PetscDrawLGReset()`
424: @*/
425: PetscErrorCode PetscDrawLGDraw(PetscDrawLG lg)
426: {
427:   PetscReal   xmin, xmax, ymin, ymax;
428:   PetscMPIInt rank;
429:   PetscDraw   draw;
430:   PetscBool   isnull;

432:   PetscFunctionBegin;
434:   PetscCall(PetscDrawIsNull(lg->win, &isnull));
435:   if (isnull) PetscFunctionReturn(PETSC_SUCCESS);
436:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)lg), &rank));

438:   draw = lg->win;
439:   PetscCall(PetscDrawCheckResizedWindow(draw));
440:   PetscCall(PetscDrawClear(draw));

442:   xmin = lg->xmin;
443:   xmax = lg->xmax;
444:   ymin = lg->ymin;
445:   ymax = lg->ymax;
446:   PetscCall(PetscDrawAxisSetLimits(lg->axis, xmin, xmax, ymin, ymax));
447:   PetscCall(PetscDrawAxisDraw(lg->axis));

449:   PetscDrawCollectiveBegin(draw);
450:   if (rank == 0) {
451:     int i, j, dim = lg->dim, nopts = lg->nopts, cl;
452:     for (i = 0; i < dim; i++) {
453:       for (j = 1; j < nopts; j++) {
454:         cl = lg->colors ? lg->colors[i] : ((PETSC_DRAW_BLACK + i) % PETSC_DRAW_MAXCOLOR);
455:         PetscCall(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));
456:         if (lg->use_markers) PetscCall(PetscDrawMarker(draw, lg->x[j * dim + i], lg->y[j * dim + i], cl));
457:       }
458:     }
459:   }
460:   if (rank == 0 && lg->legend) {
461:     PetscBool right = PETSC_FALSE;
462:     int       i, dim = lg->dim, cl;
463:     PetscReal xl, yl, xr, yr, tw, th;
464:     size_t    slen, len = 0;
465:     PetscCall(PetscDrawAxisGetLimits(lg->axis, &xl, &xr, &yl, &yr));
466:     PetscCall(PetscDrawStringGetSize(draw, &tw, &th));
467:     for (i = 0; i < dim; i++) {
468:       PetscCall(PetscStrlen(lg->legend[i], &slen));
469:       len = PetscMax(len, slen);
470:     }
471:     if (right) {
472:       xr = xr - 1.5 * tw;
473:       xl = xr - (len + 7) * tw;
474:     } else {
475:       xl = xl + 1.5 * tw;
476:       xr = xl + (len + 7) * tw;
477:     }
478:     yr = yr - 1.0 * th;
479:     yl = yr - (dim + 1) * th;
480:     PetscCall(PetscDrawLine(draw, xl, yl, xr, yl, PETSC_DRAW_BLACK));
481:     PetscCall(PetscDrawLine(draw, xr, yl, xr, yr, PETSC_DRAW_BLACK));
482:     PetscCall(PetscDrawLine(draw, xr, yr, xl, yr, PETSC_DRAW_BLACK));
483:     PetscCall(PetscDrawLine(draw, xl, yr, xl, yl, PETSC_DRAW_BLACK));
484:     for (i = 0; i < dim; i++) {
485:       cl = lg->colors ? lg->colors[i] : (PETSC_DRAW_BLACK + i);
486:       PetscCall(PetscDrawLine(draw, xl + 1 * tw, yr - (i + 1) * th, xl + 5 * tw, yr - (i + 1) * th, cl));
487:       PetscCall(PetscDrawString(draw, xl + 6 * tw, yr - (i + 1.5) * th, PETSC_DRAW_BLACK, lg->legend[i]));
488:     }
489:   }
490:   PetscDrawCollectiveEnd(draw);

492:   PetscCall(PetscDrawFlush(draw));
493:   PetscCall(PetscDrawPause(draw));
494:   PetscFunctionReturn(PETSC_SUCCESS);
495: }

497: /*@
498:   PetscDrawLGSave - Saves a drawn image

500:   Collective

502:   Input Parameter:
503: . lg - The line graph context

505:   Level: intermediate

507: .seealso: `PetscDrawLG`, `PetscDrawSave()`, `PetscDrawLGCreate()`, `PetscDrawLGGetDraw()`, `PetscDrawSetSave()`, `PetscDrawSave()`
508: @*/
509: PetscErrorCode PetscDrawLGSave(PetscDrawLG lg)
510: {
511:   PetscFunctionBegin;
513:   PetscCall(PetscDrawSave(lg->win));
514:   PetscFunctionReturn(PETSC_SUCCESS);
515: }

517: /*@
518:   PetscDrawLGView - Prints a line graph.

520:   Collective

522:   Input Parameter:
523: . lg - the line graph context

525:   Level: beginner

527: .seealso: `PetscDrawLG`, `PetscDrawLGCreate()`
528: @*/
529: PetscErrorCode PetscDrawLGView(PetscDrawLG lg, PetscViewer viewer)
530: {
531:   PetscReal xmin = lg->xmin, xmax = lg->xmax, ymin = lg->ymin, ymax = lg->ymax;
532:   PetscInt  i, j, dim = lg->dim, nopts = lg->nopts;

534:   PetscFunctionBegin;

537:   if (nopts < 1) PetscFunctionReturn(PETSC_SUCCESS);
538:   if (xmin > xmax || ymin > ymax) PetscFunctionReturn(PETSC_SUCCESS);

540:   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)lg), &viewer));
541:   PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)lg, viewer));
542:   for (i = 0; i < dim; i++) {
543:     PetscCall(PetscViewerASCIIPrintf(viewer, "Line %" PetscInt_FMT ">\n", i));
544:     for (j = 0; j < nopts; j++) PetscCall(PetscViewerASCIIPrintf(viewer, "  X: %g Y: %g\n", (double)lg->x[j * dim + i], (double)lg->y[j * dim + i]));
545:   }
546:   PetscFunctionReturn(PETSC_SUCCESS);
547: }

549: /*@C
550:    PetscDrawLGSetOptionsPrefix - Sets the prefix used for searching for all
551:    `PetscDrawLG` options in the database.

553:    Logically Collective

555:    Input Parameters:
556: +  lg - the line graph context
557: -  prefix - the prefix to prepend to all option names

559:    Level: advanced

561: .seealso: `PetscDrawLG`, `PetscDrawLGSetFromOptions()`, `PetscDrawLGCreate()`
562: @*/
563: PetscErrorCode PetscDrawLGSetOptionsPrefix(PetscDrawLG lg, const char prefix[])
564: {
565:   PetscFunctionBegin;
567:   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)lg, prefix));
568:   PetscFunctionReturn(PETSC_SUCCESS);
569: }

571: /*@
572:     PetscDrawLGSetFromOptions - Sets options related to the line graph object

574:     Collective

576:     Input Parameters:
577: .   lg - the line graph context

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

582:     Level: intermediate

584: .seealso: `PetscDrawLG`, `PetscDrawLGDestroy()`, `PetscDrawLGCreate()`
585: @*/
586: PetscErrorCode PetscDrawLGSetFromOptions(PetscDrawLG lg)
587: {
588:   PetscBool           usemarkers, set;
589:   PetscDrawMarkerType markertype;

591:   PetscFunctionBegin;

594:   PetscCall(PetscDrawGetMarkerType(lg->win, &markertype));
595:   PetscCall(PetscOptionsGetEnum(((PetscObject)lg)->options, ((PetscObject)lg)->prefix, "-lg_marker_type", PetscDrawMarkerTypes, (PetscEnum *)&markertype, &set));
596:   if (set) {
597:     PetscCall(PetscDrawLGSetUseMarkers(lg, PETSC_TRUE));
598:     PetscCall(PetscDrawSetMarkerType(lg->win, markertype));
599:   }
600:   usemarkers = lg->use_markers;
601:   PetscCall(PetscOptionsGetBool(((PetscObject)lg)->options, ((PetscObject)lg)->prefix, "-lg_use_markers", &usemarkers, &set));
602:   if (set) PetscCall(PetscDrawLGSetUseMarkers(lg, usemarkers));
603:   PetscFunctionReturn(PETSC_SUCCESS);
604: }