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