xref: /petsc/src/sys/classes/draw/utils/lgc.c (revision 1690c2ae071c7584458d4e437df7b47bc4686b3c)
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     = (int)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         = (int)(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 = (int)dim;
295   PetscCall(PetscMalloc2(dim * PETSC_DRAW_LG_CHUNK_SIZE, &lg->x, dim * PETSC_DRAW_LG_CHUNK_SIZE, &lg->y));
296   lg->len = (int)(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 
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 - ((PetscReal)len + 7) * tw;
477     } else {
478       xl = xl + 1.5 * tw;
479       xr = xl + ((PetscReal)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);
494 
495   PetscCall(PetscDrawFlush(draw));
496   PetscCall(PetscDrawPause(draw));
497   PetscFunctionReturn(PETSC_SUCCESS);
498 }
499 
500 /*@
501   PetscDrawLGSave - Saves a drawn image
502 
503   Collective
504 
505   Input Parameter:
506 . lg - The line graph context
507 
508   Level: intermediate
509 
510 .seealso: `PetscDrawLG`, `PetscDrawSave()`, `PetscDrawLGCreate()`, `PetscDrawLGGetDraw()`, `PetscDrawSetSave()`
511 @*/
512 PetscErrorCode PetscDrawLGSave(PetscDrawLG lg)
513 {
514   PetscFunctionBegin;
515   PetscValidHeaderSpecific(lg, PETSC_DRAWLG_CLASSID, 1);
516   PetscCall(PetscDrawSave(lg->win));
517   PetscFunctionReturn(PETSC_SUCCESS);
518 }
519 
520 /*@
521   PetscDrawLGView - Prints a line graph.
522 
523   Collective
524 
525   Input Parameters:
526 + lg     - the line graph context
527 - viewer - the viewer to view it with
528 
529   Level: beginner
530 
531 .seealso: `PetscDrawLG`, `PetscDrawLGCreate()`
532 @*/
533 PetscErrorCode PetscDrawLGView(PetscDrawLG lg, PetscViewer viewer)
534 {
535   PetscReal xmin = lg->xmin, xmax = lg->xmax, ymin = lg->ymin, ymax = lg->ymax;
536   PetscInt  i, j, dim = lg->dim, nopts = lg->nopts;
537 
538   PetscFunctionBegin;
539   PetscValidHeaderSpecific(lg, PETSC_DRAWLG_CLASSID, 1);
540 
541   if (nopts < 1) PetscFunctionReturn(PETSC_SUCCESS);
542   if (xmin > xmax || ymin > ymax) PetscFunctionReturn(PETSC_SUCCESS);
543 
544   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)lg), &viewer));
545   PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)lg, viewer));
546   for (i = 0; i < dim; i++) {
547     PetscCall(PetscViewerASCIIPrintf(viewer, "Line %" PetscInt_FMT ">\n", i));
548     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]));
549   }
550   PetscFunctionReturn(PETSC_SUCCESS);
551 }
552 
553 /*@
554   PetscDrawLGSetOptionsPrefix - Sets the prefix used for searching for all
555   `PetscDrawLG` options in the database.
556 
557   Logically Collective
558 
559   Input Parameters:
560 + lg     - the line graph context
561 - prefix - the prefix to prepend to all option names
562 
563   Level: advanced
564 
565 .seealso: `PetscDrawLG`, `PetscDrawLGSetFromOptions()`, `PetscDrawLGCreate()`
566 @*/
567 PetscErrorCode PetscDrawLGSetOptionsPrefix(PetscDrawLG lg, const char prefix[])
568 {
569   PetscFunctionBegin;
570   PetscValidHeaderSpecific(lg, PETSC_DRAWLG_CLASSID, 1);
571   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)lg, prefix));
572   PetscFunctionReturn(PETSC_SUCCESS);
573 }
574 
575 /*@
576   PetscDrawLGSetFromOptions - Sets options related to the line graph object
577 
578   Collective
579 
580   Input Parameters:
581 . lg - the line graph context
582 
583   Options Database Key:
584 . -lg_use_markers  <true,false> - true means it draws a marker for each point
585 
586   Level: intermediate
587 
588 .seealso: `PetscDrawLG`, `PetscDrawLGDestroy()`, `PetscDrawLGCreate()`
589 @*/
590 PetscErrorCode PetscDrawLGSetFromOptions(PetscDrawLG lg)
591 {
592   PetscBool           usemarkers, set;
593   PetscDrawMarkerType markertype;
594 
595   PetscFunctionBegin;
596   PetscValidHeaderSpecific(lg, PETSC_DRAWLG_CLASSID, 1);
597 
598   PetscCall(PetscDrawGetMarkerType(lg->win, &markertype));
599   PetscCall(PetscOptionsGetEnum(((PetscObject)lg)->options, ((PetscObject)lg)->prefix, "-lg_marker_type", PetscDrawMarkerTypes, (PetscEnum *)&markertype, &set));
600   if (set) {
601     PetscCall(PetscDrawLGSetUseMarkers(lg, PETSC_TRUE));
602     PetscCall(PetscDrawSetMarkerType(lg->win, markertype));
603   }
604   usemarkers = lg->use_markers;
605   PetscCall(PetscOptionsGetBool(((PetscObject)lg)->options, ((PetscObject)lg)->prefix, "-lg_use_markers", &usemarkers, &set));
606   if (set) PetscCall(PetscDrawLGSetUseMarkers(lg, usemarkers));
607   PetscFunctionReturn(PETSC_SUCCESS);
608 }
609