xref: /petsc/src/sys/classes/draw/utils/lgc.c (revision 2d30e087755efd99e28fdfe792ffbeb2ee1ea928)
1 
2 #include <petscviewer.h>
3 #include <petsc/private/drawimpl.h> /*I   "petscdraw.h"  I*/
4 PetscClassId PETSC_DRAWLG_CLASSID = 0;
5 
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.
11 
12    Not Collective, if lg is parallel then axis is parallel
13 
14    Input Parameter:
15 .  lg - the line graph context
16 
17    Output Parameter:
18 .  axis - the axis context
19 
20    Level: advanced
21 
22 .seealso: `PetscDrawLGCreate()`, `PetscDrawAxis`, `PetscDrawLG`
23 @*/
24 PetscErrorCode PetscDrawLGGetAxis(PetscDrawLG lg, PetscDrawAxis *axis) {
25   PetscFunctionBegin;
26   PetscValidHeaderSpecific(lg, PETSC_DRAWLG_CLASSID, 1);
27   PetscValidPointer(axis, 2);
28   *axis = lg->axis;
29   PetscFunctionReturn(0);
30 }
31 
32 /*@
33    PetscDrawLGGetDraw - Gets the draw context associated with a line graph.
34 
35    Not Collective, if lg is parallel then draw is parallel
36 
37    Input Parameter:
38 .  lg - the line graph context
39 
40    Output Parameter:
41 .  draw - the draw context
42 
43    Level: intermediate
44 
45 .seealso: `PetscDrawLGCreate()`, `PetscDraw`, `PetscDrawLG`
46 @*/
47 PetscErrorCode PetscDrawLGGetDraw(PetscDrawLG lg, PetscDraw *draw) {
48   PetscFunctionBegin;
49   PetscValidHeaderSpecific(lg, PETSC_DRAWLG_CLASSID, 1);
50   PetscValidPointer(draw, 2);
51   *draw = lg->win;
52   PetscFunctionReturn(0);
53 }
54 
55 /*@
56   PetscDrawLGSPDraw - Redraws a line graph and a scatter plot on the same `PetscDraw` they must share
57 
58    Collective on lg
59 
60    Input Parameters:
61 +  lg - the line graph context
62 -  spin - the scatter plot
63 
64    Level: intermediate
65 
66    Developer Note:
67     This code cheats and uses the fact that the `PetscDrawLG` and `PetscDrawSP` structs are the same
68 
69 .seealso: `PetscDrawLGDraw()`, `PetscDrawSPDraw()`
70 @*/
71 PetscErrorCode PetscDrawLGSPDraw(PetscDrawLG lg, PetscDrawSP spin) {
72   PetscDrawLG sp = (PetscDrawLG)spin;
73   PetscReal   xmin, xmax, ymin, ymax;
74   PetscBool   isnull;
75   PetscMPIInt rank;
76   PetscDraw   draw;
77 
78   PetscFunctionBegin;
79   PetscValidHeaderSpecific(lg, PETSC_DRAWLG_CLASSID, 1);
80   PetscValidHeaderSpecific(sp, PETSC_DRAWLG_CLASSID, 2);
81   PetscCall(PetscDrawIsNull(lg->win, &isnull));
82   if (isnull) PetscFunctionReturn(0);
83   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)lg), &rank));
84 
85   draw = lg->win;
86   PetscCall(PetscDrawCheckResizedWindow(draw));
87   PetscCall(PetscDrawClear(draw));
88 
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   PetscCall(PetscDrawAxisSetLimits(lg->axis, xmin, xmax, ymin, ymax));
94   PetscCall(PetscDrawAxisDraw(lg->axis));
95 
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         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));
104         if (lg->use_markers) PetscCall(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++) PetscCall(PetscDrawMarker(draw, sp->x[j * dim + i], sp->y[j * dim + i], PETSC_DRAW_RED));
111     }
112   }
113   PetscDrawCollectiveEnd(draw);
114 
115   PetscCall(PetscDrawFlush(draw));
116   PetscCall(PetscDrawPause(draw));
117   PetscFunctionReturn(0);
118 }
119 
120 /*@
121     PetscDrawLGCreate - Creates a line graph data structure.
122 
123     Collective on draw
124 
125     Input Parameters:
126 +   draw - the window where the graph will be made.
127 -   dim - the number of curves which will be drawn
128 
129     Output Parameters:
130 .   outlg - the line graph context
131 
132     Level: intermediate
133 
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.
137 
138     All MPI ranks in the communicator must call `PetscDrawLGDraw()` to display the updated graph.
139 
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   PetscDrawLG lg;
146 
147   PetscFunctionBegin;
148   PetscValidHeaderSpecific(draw, PETSC_DRAW_CLASSID, 1);
149   PetscValidLogicalCollectiveInt(draw, dim, 2);
150   PetscValidPointer(outlg, 3);
151 
152   PetscCall(PetscHeaderCreate(lg, PETSC_DRAWLG_CLASSID, "DrawLG", "Line Graph", "Draw", PetscObjectComm((PetscObject)draw), PetscDrawLGDestroy, NULL));
153   PetscCall(PetscLogObjectParent((PetscObject)draw, (PetscObject)lg));
154   PetscCall(PetscDrawLGSetOptionsPrefix(lg, ((PetscObject)draw)->prefix));
155 
156   PetscCall(PetscObjectReference((PetscObject)draw));
157   lg->win = draw;
158 
159   lg->view    = NULL;
160   lg->destroy = NULL;
161   lg->nopts   = 0;
162   lg->dim     = dim;
163   lg->xmin    = 1.e20;
164   lg->ymin    = 1.e20;
165   lg->xmax    = -1.e20;
166   lg->ymax    = -1.e20;
167 
168   PetscCall(PetscMalloc2(dim * PETSC_DRAW_LG_CHUNK_SIZE, &lg->x, dim * PETSC_DRAW_LG_CHUNK_SIZE, &lg->y));
169   PetscCall(PetscLogObjectMemory((PetscObject)lg, 2 * dim * PETSC_DRAW_LG_CHUNK_SIZE * sizeof(PetscReal)));
170 
171   lg->len         = dim * PETSC_DRAW_LG_CHUNK_SIZE;
172   lg->loc         = 0;
173   lg->use_markers = PETSC_FALSE;
174 
175   PetscCall(PetscDrawAxisCreate(draw, &lg->axis));
176   PetscCall(PetscLogObjectParent((PetscObject)lg, (PetscObject)lg->axis));
177 
178   *outlg = lg;
179   PetscFunctionReturn(0);
180 }
181 
182 /*@
183    PetscDrawLGSetColors - Sets the color of each line graph drawn
184 
185    Logically Collective on lg
186 
187    Input Parameters:
188 +  lg - the line graph context.
189 -  colors - the colors
190 
191    Level: intermediate
192 
193 .seealso: `PetscDrawLG`, `PetscDrawLGCreate()`
194 @*/
195 PetscErrorCode PetscDrawLGSetColors(PetscDrawLG lg, const int colors[]) {
196   PetscFunctionBegin;
197   PetscValidHeaderSpecific(lg, PETSC_DRAWLG_CLASSID, 1);
198   if (lg->dim) PetscValidIntPointer(colors, 2);
199 
200   PetscCall(PetscFree(lg->colors));
201   PetscCall(PetscMalloc1(lg->dim, &lg->colors));
202   PetscCall(PetscArraycpy(lg->colors, colors, lg->dim));
203   PetscFunctionReturn(0);
204 }
205 
206 /*@C
207    PetscDrawLGSetLegend - sets the names of each curve plotted
208 
209    Logically Collective on lg
210 
211    Input Parameters:
212 +  lg - the line graph context.
213 -  names - the names for each curve
214 
215    Level: intermediate
216 
217    Note:
218     Call `PetscDrawLGGetAxis()` and then change properties of the `PetscDrawAxis` for detailed control of the plot
219 
220 .seealso: `PetscDrawLGGetAxis()`, `PetscDrawAxis`, `PetscDrawAxisSetColors()`, `PetscDrawAxisSetLabels()`, `PetscDrawAxisSetHoldLimits()`
221 @*/
222 PetscErrorCode PetscDrawLGSetLegend(PetscDrawLG lg, const char *const *names) {
223   PetscInt i;
224 
225   PetscFunctionBegin;
226   PetscValidHeaderSpecific(lg, PETSC_DRAWLG_CLASSID, 1);
227   if (names) PetscValidPointer(names, 2);
228 
229   if (lg->legend) {
230     for (i = 0; i < lg->dim; i++) PetscCall(PetscFree(lg->legend[i]));
231     PetscCall(PetscFree(lg->legend));
232   }
233   if (names) {
234     PetscCall(PetscMalloc1(lg->dim, &lg->legend));
235     for (i = 0; i < lg->dim; i++) PetscCall(PetscStrallocpy(names[i], &lg->legend[i]));
236   }
237   PetscFunctionReturn(0);
238 }
239 
240 /*@
241    PetscDrawLGGetDimension - Get the number of curves that are to be drawn.
242 
243    Not Collective
244 
245    Input Parameter:
246 .  lg - the line graph context.
247 
248    Output Parameter:
249 .  dim - the number of curves.
250 
251    Level: intermediate
252 
253 .seealso: `PetscDrawLGC`, `PetscDrawLGCreate()`, `PetscDrawLGSetDimension()`
254 @*/
255 PetscErrorCode PetscDrawLGGetDimension(PetscDrawLG lg, PetscInt *dim) {
256   PetscFunctionBegin;
257   PetscValidHeaderSpecific(lg, PETSC_DRAWLG_CLASSID, 1);
258   PetscValidIntPointer(dim, 2);
259   *dim = lg->dim;
260   PetscFunctionReturn(0);
261 }
262 
263 /*@
264    PetscDrawLGSetDimension - Change the number of curves that are to be drawn.
265 
266    Logically Collective on lg
267 
268    Input Parameters:
269 +  lg - the line graph context.
270 -  dim - the number of curves.
271 
272    Level: intermediate
273 
274 .seealso: `PetscDrawLGCreate()`, `PetscDrawLGGetDimension()`
275 @*/
276 PetscErrorCode PetscDrawLGSetDimension(PetscDrawLG lg, PetscInt dim) {
277   PetscInt i;
278 
279   PetscFunctionBegin;
280   PetscValidHeaderSpecific(lg, PETSC_DRAWLG_CLASSID, 1);
281   PetscValidLogicalCollectiveInt(lg, dim, 2);
282   if (lg->dim == dim) PetscFunctionReturn(0);
283 
284   PetscCall(PetscFree2(lg->x, lg->y));
285   if (lg->legend) {
286     for (i = 0; i < lg->dim; i++) PetscCall(PetscFree(lg->legend[i]));
287     PetscCall(PetscFree(lg->legend));
288   }
289   PetscCall(PetscFree(lg->colors));
290   lg->dim = dim;
291   PetscCall(PetscMalloc2(dim * PETSC_DRAW_LG_CHUNK_SIZE, &lg->x, dim * PETSC_DRAW_LG_CHUNK_SIZE, &lg->y));
292   PetscCall(PetscLogObjectMemory((PetscObject)lg, 2 * dim * PETSC_DRAW_LG_CHUNK_SIZE * sizeof(PetscReal)));
293   lg->len = dim * PETSC_DRAW_LG_CHUNK_SIZE;
294   PetscFunctionReturn(0);
295 }
296 
297 /*@
298    PetscDrawLGSetLimits - Sets the axis limits for a line graph. If more
299    points are added after this call, the limits will be adjusted to
300    include those additional points.
301 
302    Logically Collective on lg
303 
304    Input Parameters:
305 +  xlg - the line graph context
306 -  x_min,x_max,y_min,y_max - the limits
307 
308    Level: intermediate
309 
310 .seealso: `PetscDrawLGCreate()`, `PetscDrawLG`, `PetscDrawAxis`
311 @*/
312 PetscErrorCode PetscDrawLGSetLimits(PetscDrawLG lg, PetscReal x_min, PetscReal x_max, PetscReal y_min, PetscReal y_max) {
313   PetscFunctionBegin;
314   PetscValidHeaderSpecific(lg, PETSC_DRAWLG_CLASSID, 1);
315 
316   (lg)->xmin = x_min;
317   (lg)->xmax = x_max;
318   (lg)->ymin = y_min;
319   (lg)->ymax = y_max;
320   PetscFunctionReturn(0);
321 }
322 
323 /*@
324    PetscDrawLGReset - Clears line graph to allow for reuse with new data.
325 
326    Logically Collective on lg
327 
328    Input Parameter:
329 .  lg - the line graph context.
330 
331    Level: intermediate
332 
333 .seealso: `PetscDrawLG`, `PetscDrawLGCreate()`
334 @*/
335 PetscErrorCode PetscDrawLGReset(PetscDrawLG lg) {
336   PetscFunctionBegin;
337   PetscValidHeaderSpecific(lg, PETSC_DRAWLG_CLASSID, 1);
338   lg->xmin  = 1.e20;
339   lg->ymin  = 1.e20;
340   lg->xmax  = -1.e20;
341   lg->ymax  = -1.e20;
342   lg->loc   = 0;
343   lg->nopts = 0;
344   PetscFunctionReturn(0);
345 }
346 
347 /*@
348    PetscDrawLGDestroy - Frees all space taken up by line graph data structure.
349 
350    Collective on lg
351 
352    Input Parameter:
353 .  lg - the line graph context
354 
355    Level: intermediate
356 
357 .seealso: `PetscDrawLG`, `PetscDrawLGCreate()`
358 @*/
359 PetscErrorCode PetscDrawLGDestroy(PetscDrawLG *lg) {
360   PetscInt i;
361 
362   PetscFunctionBegin;
363   if (!*lg) PetscFunctionReturn(0);
364   PetscValidHeaderSpecific(*lg, PETSC_DRAWLG_CLASSID, 1);
365   if (--((PetscObject)(*lg))->refct > 0) {
366     *lg = NULL;
367     PetscFunctionReturn(0);
368   }
369 
370   if ((*lg)->legend) {
371     for (i = 0; i < (*lg)->dim; i++) PetscCall(PetscFree((*lg)->legend[i]));
372     PetscCall(PetscFree((*lg)->legend));
373   }
374   PetscCall(PetscFree((*lg)->colors));
375   PetscCall(PetscFree2((*lg)->x, (*lg)->y));
376   PetscCall(PetscDrawAxisDestroy(&(*lg)->axis));
377   PetscCall(PetscDrawDestroy(&(*lg)->win));
378   PetscCall(PetscHeaderDestroy(lg));
379   PetscFunctionReturn(0);
380 }
381 /*@
382    PetscDrawLGSetUseMarkers - Causes the line graph object to draw a marker for each data-point.
383 
384    Logically Collective on lg
385 
386    Input Parameters:
387 +  lg - the linegraph context
388 -  flg - should mark each data point
389 
390    Options Database Key:
391 .  -lg_use_markers  <true,false> - true means it draws a marker for each point
392 
393    Level: intermediate
394 
395 .seealso: `PetscDrawLG`, `PetscDrawLGCreate()`
396 @*/
397 PetscErrorCode PetscDrawLGSetUseMarkers(PetscDrawLG lg, PetscBool flg) {
398   PetscFunctionBegin;
399   PetscValidHeaderSpecific(lg, PETSC_DRAWLG_CLASSID, 1);
400   PetscValidLogicalCollectiveBool(lg, flg, 2);
401   lg->use_markers = flg;
402   PetscFunctionReturn(0);
403 }
404 
405 /*@
406    PetscDrawLGDraw - Redraws a line graph.
407 
408    Collective on lg
409 
410    Input Parameter:
411 .  lg - the line graph context
412 
413    Level: intermediate
414 
415 .seealso: `PetscDrawLG`, `PetscDrawSPDraw()`, `PetscDrawLGSPDraw()`, `PetscDrawLGReset()`
416 @*/
417 PetscErrorCode PetscDrawLGDraw(PetscDrawLG lg) {
418   PetscReal   xmin, xmax, ymin, ymax;
419   PetscMPIInt rank;
420   PetscDraw   draw;
421   PetscBool   isnull;
422 
423   PetscFunctionBegin;
424   PetscValidHeaderSpecific(lg, PETSC_DRAWLG_CLASSID, 1);
425   PetscCall(PetscDrawIsNull(lg->win, &isnull));
426   if (isnull) PetscFunctionReturn(0);
427   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)lg), &rank));
428 
429   draw = lg->win;
430   PetscCall(PetscDrawCheckResizedWindow(draw));
431   PetscCall(PetscDrawClear(draw));
432 
433   xmin = lg->xmin;
434   xmax = lg->xmax;
435   ymin = lg->ymin;
436   ymax = lg->ymax;
437   PetscCall(PetscDrawAxisSetLimits(lg->axis, xmin, xmax, ymin, ymax));
438   PetscCall(PetscDrawAxisDraw(lg->axis));
439 
440   PetscDrawCollectiveBegin(draw);
441   if (rank == 0) {
442     int i, j, dim = lg->dim, nopts = lg->nopts, cl;
443     for (i = 0; i < dim; i++) {
444       for (j = 1; j < nopts; j++) {
445         cl = lg->colors ? lg->colors[i] : ((PETSC_DRAW_BLACK + i) % PETSC_DRAW_MAXCOLOR);
446         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));
447         if (lg->use_markers) PetscCall(PetscDrawMarker(draw, lg->x[j * dim + i], lg->y[j * dim + i], cl));
448       }
449     }
450   }
451   if (rank == 0 && lg->legend) {
452     PetscBool right = PETSC_FALSE;
453     int       i, dim = lg->dim, cl;
454     PetscReal xl, yl, xr, yr, tw, th;
455     size_t    slen, len = 0;
456     PetscCall(PetscDrawAxisGetLimits(lg->axis, &xl, &xr, &yl, &yr));
457     PetscCall(PetscDrawStringGetSize(draw, &tw, &th));
458     for (i = 0; i < dim; i++) {
459       PetscCall(PetscStrlen(lg->legend[i], &slen));
460       len = PetscMax(len, slen);
461     }
462     if (right) {
463       xr = xr - 1.5 * tw;
464       xl = xr - (len + 7) * tw;
465     } else {
466       xl = xl + 1.5 * tw;
467       xr = xl + (len + 7) * tw;
468     }
469     yr = yr - 1.0 * th;
470     yl = yr - (dim + 1) * th;
471     PetscCall(PetscDrawLine(draw, xl, yl, xr, yl, PETSC_DRAW_BLACK));
472     PetscCall(PetscDrawLine(draw, xr, yl, xr, yr, PETSC_DRAW_BLACK));
473     PetscCall(PetscDrawLine(draw, xr, yr, xl, yr, PETSC_DRAW_BLACK));
474     PetscCall(PetscDrawLine(draw, xl, yr, xl, yl, PETSC_DRAW_BLACK));
475     for (i = 0; i < dim; i++) {
476       cl = lg->colors ? lg->colors[i] : (PETSC_DRAW_BLACK + i);
477       PetscCall(PetscDrawLine(draw, xl + 1 * tw, yr - (i + 1) * th, xl + 5 * tw, yr - (i + 1) * th, cl));
478       PetscCall(PetscDrawString(draw, xl + 6 * tw, yr - (i + 1.5) * th, PETSC_DRAW_BLACK, lg->legend[i]));
479     }
480   }
481   PetscDrawCollectiveEnd(draw);
482 
483   PetscCall(PetscDrawFlush(draw));
484   PetscCall(PetscDrawPause(draw));
485   PetscFunctionReturn(0);
486 }
487 
488 /*@
489   PetscDrawLGSave - Saves a drawn image
490 
491   Collective on lg
492 
493   Input Parameter:
494 . lg - The line graph context
495 
496   Level: intermediate
497 
498 .seealso: `PetscDrawLG`, `PetscDrawSave()`, `PetscDrawLGCreate()`, `PetscDrawLGGetDraw()`, `PetscDrawSetSave()`, `PetscDrawSave()`
499 @*/
500 PetscErrorCode PetscDrawLGSave(PetscDrawLG lg) {
501   PetscFunctionBegin;
502   PetscValidHeaderSpecific(lg, PETSC_DRAWLG_CLASSID, 1);
503   PetscCall(PetscDrawSave(lg->win));
504   PetscFunctionReturn(0);
505 }
506 
507 /*@
508   PetscDrawLGView - Prints a line graph.
509 
510   Collective on lg
511 
512   Input Parameter:
513 . lg - the line graph context
514 
515   Level: beginner
516 
517 .seealso: `PetscDrawLG`, `PetscDrawLGCreate()`
518 @*/
519 PetscErrorCode PetscDrawLGView(PetscDrawLG lg, PetscViewer viewer) {
520   PetscReal xmin = lg->xmin, xmax = lg->xmax, ymin = lg->ymin, ymax = lg->ymax;
521   PetscInt  i, j, dim = lg->dim, nopts = lg->nopts;
522 
523   PetscFunctionBegin;
524   PetscValidHeaderSpecific(lg, PETSC_DRAWLG_CLASSID, 1);
525 
526   if (nopts < 1) PetscFunctionReturn(0);
527   if (xmin > xmax || ymin > ymax) PetscFunctionReturn(0);
528 
529   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)lg), &viewer));
530   PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)lg, viewer));
531   for (i = 0; i < dim; i++) {
532     PetscCall(PetscViewerASCIIPrintf(viewer, "Line %" PetscInt_FMT ">\n", i));
533     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]));
534   }
535   PetscFunctionReturn(0);
536 }
537 
538 /*@C
539    PetscDrawLGSetOptionsPrefix - Sets the prefix used for searching for all
540    `PetscDrawLG` options in the database.
541 
542    Logically Collective on lg
543 
544    Input Parameters:
545 +  lg - the line graph context
546 -  prefix - the prefix to prepend to all option names
547 
548    Level: advanced
549 
550 .seealso: `PetscDrawLG`, `PetscDrawLGSetFromOptions()`, `PetscDrawLGCreate()`
551 @*/
552 PetscErrorCode PetscDrawLGSetOptionsPrefix(PetscDrawLG lg, const char prefix[]) {
553   PetscFunctionBegin;
554   PetscValidHeaderSpecific(lg, PETSC_DRAWLG_CLASSID, 1);
555   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)lg, prefix));
556   PetscFunctionReturn(0);
557 }
558 
559 /*@
560     PetscDrawLGSetFromOptions - Sets options related to the line graph object
561 
562     Collective on lg
563 
564     Input Parameters:
565 .   lg - the line graph context
566 
567     Options Database Key:
568 .  -lg_use_markers  <true,false> - true means it draws a marker for each point
569 
570     Level: intermediate
571 
572 .seealso: `PetscDrawLG`, `PetscDrawLGDestroy()`, `PetscDrawLGCreate()`
573 @*/
574 PetscErrorCode PetscDrawLGSetFromOptions(PetscDrawLG lg) {
575   PetscBool           usemarkers, set;
576   PetscDrawMarkerType markertype;
577 
578   PetscFunctionBegin;
579   PetscValidHeaderSpecific(lg, PETSC_DRAWLG_CLASSID, 1);
580 
581   PetscCall(PetscDrawGetMarkerType(lg->win, &markertype));
582   PetscCall(PetscOptionsGetEnum(((PetscObject)lg)->options, ((PetscObject)lg)->prefix, "-lg_marker_type", PetscDrawMarkerTypes, (PetscEnum *)&markertype, &set));
583   if (set) {
584     PetscCall(PetscDrawLGSetUseMarkers(lg, PETSC_TRUE));
585     PetscCall(PetscDrawSetMarkerType(lg->win, markertype));
586   }
587   usemarkers = lg->use_markers;
588   PetscCall(PetscOptionsGetBool(((PetscObject)lg)->options, ((PetscObject)lg)->prefix, "-lg_use_markers", &usemarkers, &set));
589   if (set) PetscCall(PetscDrawLGSetUseMarkers(lg, usemarkers));
590   PetscFunctionReturn(0);
591 }
592