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 Parameter:
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 - the horizontal lower limit
311: .  x_max - the horizontal upper limit
312: .  y_min - the vertical lower limit
313: -  y_max - the vertical upper limit

315:    Level: intermediate

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

324:   (lg)->xmin = x_min;
325:   (lg)->xmax = x_max;
326:   (lg)->ymin = y_min;
327:   (lg)->ymax = y_max;
328:   PetscFunctionReturn(PETSC_SUCCESS);
329: }

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

334:    Logically Collective

336:    Input Parameter:
337: .  lg - the line graph context.

339:    Level: intermediate

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

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

359:    Collective

361:    Input Parameter:
362: .  lg - the line graph context

364:    Level: intermediate

366: .seealso: `PetscDrawLG`, `PetscDrawLGCreate()`
367: @*/
368: PetscErrorCode PetscDrawLGDestroy(PetscDrawLG *lg)
369: {
370:   PetscInt i;

372:   PetscFunctionBegin;
373:   if (!*lg) PetscFunctionReturn(PETSC_SUCCESS);
375:   if (--((PetscObject)(*lg))->refct > 0) {
376:     *lg = NULL;
377:     PetscFunctionReturn(PETSC_SUCCESS);
378:   }

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

394:    Logically Collective

396:    Input Parameters:
397: +  lg - the linegraph context
398: -  flg - should mark each data point

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

403:    Level: intermediate

405: .seealso: `PetscDrawLG`, `PetscDrawLGCreate()`
406: @*/
407: PetscErrorCode PetscDrawLGSetUseMarkers(PetscDrawLG lg, PetscBool flg)
408: {
409:   PetscFunctionBegin;
412:   lg->use_markers = flg;
413:   PetscFunctionReturn(PETSC_SUCCESS);
414: }

416: /*@
417:    PetscDrawLGDraw - Redraws a line graph.

419:    Collective

421:    Input Parameter:
422: .  lg - the line graph context

424:    Level: intermediate

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

435:   PetscFunctionBegin;
437:   PetscCall(PetscDrawIsNull(lg->win, &isnull));
438:   if (isnull) PetscFunctionReturn(PETSC_SUCCESS);
439:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)lg), &rank));

441:   draw = lg->win;
442:   PetscCall(PetscDrawCheckResizedWindow(draw));
443:   PetscCall(PetscDrawClear(draw));

445:   xmin = lg->xmin;
446:   xmax = lg->xmax;
447:   ymin = lg->ymin;
448:   ymax = lg->ymax;
449:   PetscCall(PetscDrawAxisSetLimits(lg->axis, xmin, xmax, ymin, ymax));
450:   PetscCall(PetscDrawAxisDraw(lg->axis));

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

495:   PetscCall(PetscDrawFlush(draw));
496:   PetscCall(PetscDrawPause(draw));
497:   PetscFunctionReturn(PETSC_SUCCESS);
498: }

500: /*@
501:   PetscDrawLGSave - Saves a drawn image

503:   Collective

505:   Input Parameter:
506: . lg - The line graph context

508:   Level: intermediate

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

520: /*@
521:   PetscDrawLGView - Prints a line graph.

523:   Collective

525:   Input Parameter:
526: . lg - the line graph context

528:   Level: beginner

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

537:   PetscFunctionBegin;

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

543:   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)lg), &viewer));
544:   PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)lg, viewer));
545:   for (i = 0; i < dim; i++) {
546:     PetscCall(PetscViewerASCIIPrintf(viewer, "Line %" PetscInt_FMT ">\n", i));
547:     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]));
548:   }
549:   PetscFunctionReturn(PETSC_SUCCESS);
550: }

552: /*@C
553:    PetscDrawLGSetOptionsPrefix - Sets the prefix used for searching for all
554:    `PetscDrawLG` options in the database.

556:    Logically Collective

558:    Input Parameters:
559: +  lg - the line graph context
560: -  prefix - the prefix to prepend to all option names

562:    Level: advanced

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

574: /*@
575:     PetscDrawLGSetFromOptions - Sets options related to the line graph object

577:     Collective

579:     Input Parameters:
580: .   lg - the line graph context

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

585:     Level: intermediate

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

594:   PetscFunctionBegin;

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