xref: /petsc/src/sys/classes/draw/utils/lgc.c (revision 0619917b5a674bb687c64e7daba2ab22be99af31)
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 {
26   PetscFunctionBegin;
27   PetscValidHeaderSpecific(lg, PETSC_DRAWLG_CLASSID, 1);
28   PetscAssertPointer(axis, 2);
29   *axis = lg->axis;
30   PetscFunctionReturn(PETSC_SUCCESS);
31 }
32 
33 /*@
34   PetscDrawLGGetDraw - Gets the draw context associated with a line graph.
35 
36   Not Collective, if lg is parallel then draw is parallel
37 
38   Input Parameter:
39 . lg - the line graph context
40 
41   Output Parameter:
42 . draw - the draw context
43 
44   Level: intermediate
45 
46 .seealso: `PetscDrawLGCreate()`, `PetscDraw`, `PetscDrawLG`
47 @*/
48 PetscErrorCode PetscDrawLGGetDraw(PetscDrawLG lg, PetscDraw *draw)
49 {
50   PetscFunctionBegin;
51   PetscValidHeaderSpecific(lg, PETSC_DRAWLG_CLASSID, 1);
52   PetscAssertPointer(draw, 2);
53   *draw = lg->win;
54   PetscFunctionReturn(PETSC_SUCCESS);
55 }
56 
57 /*@
58   PetscDrawLGSPDraw - Redraws a line graph and a scatter plot on the same `PetscDraw` they must share
59 
60   Collective
61 
62   Input Parameters:
63 + lg   - the line graph context
64 - spin - the scatter plot
65 
66   Level: intermediate
67 
68   Developer Notes:
69   This code cheats and uses the fact that the `PetscDrawLG` and `PetscDrawSP` structs are the same
70 
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;
80 
81   PetscFunctionBegin;
82   PetscValidHeaderSpecific(lg, PETSC_DRAWLG_CLASSID, 1);
83   PetscValidHeaderSpecific(sp, PETSC_DRAWLG_CLASSID, 2);
84   PetscCall(PetscDrawIsNull(lg->win, &isnull));
85   if (isnull) PetscFunctionReturn(PETSC_SUCCESS);
86   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)lg), &rank));
87 
88   draw = lg->win;
89   PetscCall(PetscDrawCheckResizedWindow(draw));
90   PetscCall(PetscDrawClear(draw));
91 
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));
98 
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);
117 
118   PetscCall(PetscDrawFlush(draw));
119   PetscCall(PetscDrawPause(draw));
120   PetscFunctionReturn(PETSC_SUCCESS);
121 }
122 
123 /*@
124   PetscDrawLGCreate - Creates a line graph data structure.
125 
126   Collective
127 
128   Input Parameters:
129 + draw - the window where the graph will be made.
130 - dim  - the number of curves which will be drawn
131 
132   Output Parameter:
133 . outlg - the line graph context
134 
135   Level: intermediate
136 
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.
140 
141   All MPI ranks in the communicator must call `PetscDrawLGDraw()` to display the updated graph.
142 
143 .seealso: `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;
150 
151   PetscFunctionBegin;
152   PetscValidHeaderSpecific(draw, PETSC_DRAW_CLASSID, 1);
153   PetscValidLogicalCollectiveInt(draw, dim, 2);
154   PetscAssertPointer(outlg, 3);
155 
156   PetscCall(PetscHeaderCreate(lg, PETSC_DRAWLG_CLASSID, "DrawLG", "Line Graph", "Draw", PetscObjectComm((PetscObject)draw), PetscDrawLGDestroy, NULL));
157   PetscCall(PetscDrawLGSetOptionsPrefix(lg, ((PetscObject)draw)->prefix));
158 
159   PetscCall(PetscObjectReference((PetscObject)draw));
160   lg->win = draw;
161 
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;
170 
171   PetscCall(PetscMalloc2(dim * PETSC_DRAW_LG_CHUNK_SIZE, &lg->x, dim * PETSC_DRAW_LG_CHUNK_SIZE, &lg->y));
172 
173   lg->len         = dim * PETSC_DRAW_LG_CHUNK_SIZE;
174   lg->loc         = 0;
175   lg->use_markers = PETSC_FALSE;
176 
177   PetscCall(PetscDrawAxisCreate(draw, &lg->axis));
178 
179   *outlg = lg;
180   PetscFunctionReturn(PETSC_SUCCESS);
181 }
182 
183 /*@
184   PetscDrawLGSetColors - Sets the color of each line graph drawn
185 
186   Logically Collective
187 
188   Input Parameters:
189 + lg     - the line graph context.
190 - colors - the colors
191 
192   Level: intermediate
193 
194 .seealso: `PetscDrawLG`, `PetscDrawLGCreate()`
195 @*/
196 PetscErrorCode PetscDrawLGSetColors(PetscDrawLG lg, const int colors[])
197 {
198   PetscFunctionBegin;
199   PetscValidHeaderSpecific(lg, PETSC_DRAWLG_CLASSID, 1);
200   if (lg->dim) PetscAssertPointer(colors, 2);
201 
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 }
207 
208 /*@C
209   PetscDrawLGSetLegend - sets the names of each curve plotted
210 
211   Logically Collective
212 
213   Input Parameters:
214 + lg    - the line graph context.
215 - names - the names for each curve
216 
217   Level: intermediate
218 
219   Note:
220   Call `PetscDrawLGGetAxis()` and then change properties of the `PetscDrawAxis` for detailed control of the plot
221 
222 .seealso: `PetscDrawLGGetAxis()`, `PetscDrawAxis`, `PetscDrawAxisSetColors()`, `PetscDrawAxisSetLabels()`, `PetscDrawAxisSetHoldLimits()`
223 @*/
224 PetscErrorCode PetscDrawLGSetLegend(PetscDrawLG lg, const char *const *names)
225 {
226   PetscInt i;
227 
228   PetscFunctionBegin;
229   PetscValidHeaderSpecific(lg, PETSC_DRAWLG_CLASSID, 1);
230   if (names) PetscAssertPointer(names, 2);
231 
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 }
242 
243 /*@
244   PetscDrawLGGetDimension - Get the number of curves that are to be drawn.
245 
246   Not Collective
247 
248   Input Parameter:
249 . lg - the line graph context.
250 
251   Output Parameter:
252 . dim - the number of curves.
253 
254   Level: intermediate
255 
256 .seealso: `PetscDrawLGC`, `PetscDrawLGCreate()`, `PetscDrawLGSetDimension()`
257 @*/
258 PetscErrorCode PetscDrawLGGetDimension(PetscDrawLG lg, PetscInt *dim)
259 {
260   PetscFunctionBegin;
261   PetscValidHeaderSpecific(lg, PETSC_DRAWLG_CLASSID, 1);
262   PetscAssertPointer(dim, 2);
263   *dim = lg->dim;
264   PetscFunctionReturn(PETSC_SUCCESS);
265 }
266 
267 /*@
268   PetscDrawLGSetDimension - Change the number of curves that are to be drawn.
269 
270   Logically Collective
271 
272   Input Parameters:
273 + lg  - the line graph context.
274 - dim - the number of curves.
275 
276   Level: intermediate
277 
278 .seealso: `PetscDrawLGCreate()`, `PetscDrawLGGetDimension()`
279 @*/
280 PetscErrorCode PetscDrawLGSetDimension(PetscDrawLG lg, PetscInt dim)
281 {
282   PetscInt i;
283 
284   PetscFunctionBegin;
285   PetscValidHeaderSpecific(lg, PETSC_DRAWLG_CLASSID, 1);
286   PetscValidLogicalCollectiveInt(lg, dim, 2);
287   if (lg->dim == dim) PetscFunctionReturn(PETSC_SUCCESS);
288 
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 }
300 
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.
305 
306   Logically Collective
307 
308   Input Parameters:
309 + lg    - 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
314 
315   Level: intermediate
316 
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;
322   PetscValidHeaderSpecific(lg, PETSC_DRAWLG_CLASSID, 1);
323 
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 }
330 
331 /*@
332   PetscDrawLGReset - Clears line graph to allow for reuse with new data.
333 
334   Logically Collective
335 
336   Input Parameter:
337 . lg - the line graph context.
338 
339   Level: intermediate
340 
341 .seealso: `PetscDrawLG`, `PetscDrawLGCreate()`
342 @*/
343 PetscErrorCode PetscDrawLGReset(PetscDrawLG lg)
344 {
345   PetscFunctionBegin;
346   PetscValidHeaderSpecific(lg, PETSC_DRAWLG_CLASSID, 1);
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 }
355 
356 /*@
357   PetscDrawLGDestroy - Frees all space taken up by line graph data structure.
358 
359   Collective
360 
361   Input Parameter:
362 . lg - the line graph context
363 
364   Level: intermediate
365 
366 .seealso: `PetscDrawLG`, `PetscDrawLGCreate()`
367 @*/
368 PetscErrorCode PetscDrawLGDestroy(PetscDrawLG *lg)
369 {
370   PetscInt i;
371 
372   PetscFunctionBegin;
373   if (!*lg) PetscFunctionReturn(PETSC_SUCCESS);
374   PetscValidHeaderSpecific(*lg, PETSC_DRAWLG_CLASSID, 1);
375   if (--((PetscObject)(*lg))->refct > 0) {
376     *lg = NULL;
377     PetscFunctionReturn(PETSC_SUCCESS);
378   }
379 
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.
393 
394   Logically Collective
395 
396   Input Parameters:
397 + lg  - the linegraph context
398 - flg - should mark each data point
399 
400   Options Database Key:
401 . -lg_use_markers  <true,false> - true means it draws a marker for each point
402 
403   Level: intermediate
404 
405 .seealso: `PetscDrawLG`, `PetscDrawLGCreate()`
406 @*/
407 PetscErrorCode PetscDrawLGSetUseMarkers(PetscDrawLG lg, PetscBool flg)
408 {
409   PetscFunctionBegin;
410   PetscValidHeaderSpecific(lg, PETSC_DRAWLG_CLASSID, 1);
411   PetscValidLogicalCollectiveBool(lg, flg, 2);
412   lg->use_markers = flg;
413   PetscFunctionReturn(PETSC_SUCCESS);
414 }
415 
416 /*@
417   PetscDrawLGDraw - Redraws a line graph.
418 
419   Collective
420 
421   Input Parameter:
422 . lg - the line graph context
423 
424   Level: intermediate
425 
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;
434 
435   PetscFunctionBegin;
436   PetscValidHeaderSpecific(lg, PETSC_DRAWLG_CLASSID, 1);
437   PetscCall(PetscDrawIsNull(lg->win, &isnull));
438   if (isnull) PetscFunctionReturn(PETSC_SUCCESS);
439   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)lg), &rank));
440 
441   draw = lg->win;
442   PetscCall(PetscDrawCheckResizedWindow(draw));
443   PetscCall(PetscDrawClear(draw));
444 
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));
451 
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);
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 /*@C
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