xref: /petsc/src/sys/classes/draw/utils/lgc.c (revision 0baf8eba40dbc839082666f9f7396a225d6f663c)
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->xmin    = 1.e20;
165   lg->ymin    = 1.e20;
166   lg->xmax    = -1.e20;
167   lg->ymax    = -1.e20;
168   PetscCall(PetscCIntCast(dim, &lg->dim));
169   PetscCall(PetscMalloc2(dim * PETSC_DRAW_LG_CHUNK_SIZE, &lg->x, dim * PETSC_DRAW_LG_CHUNK_SIZE, &lg->y));
170 
171   lg->len         = lg->dim * PETSC_DRAW_LG_CHUNK_SIZE;
172   lg->loc         = 0;
173   lg->use_markers = PETSC_FALSE;
174 
175   PetscCall(PetscDrawAxisCreate(draw, &lg->axis));
176 
177   *outlg = lg;
178   PetscFunctionReturn(PETSC_SUCCESS);
179 }
180 
181 /*@
182   PetscDrawLGSetColors - Sets the color of each line graph drawn
183 
184   Logically Collective
185 
186   Input Parameters:
187 + lg     - the line graph context.
188 - colors - the colors, an array of length the value set with `PetscDrawLGSetDimension()`
189 
190   Level: intermediate
191 
192 .seealso: `PetscDrawLG`, `PetscDrawLGCreate()`, `PetscDrawLGSetDimension()`, `PetscDrawLGGetDimension()`
193 @*/
194 PetscErrorCode PetscDrawLGSetColors(PetscDrawLG lg, const int colors[])
195 {
196   PetscFunctionBegin;
197   PetscValidHeaderSpecific(lg, PETSC_DRAWLG_CLASSID, 1);
198   if (lg->dim) PetscAssertPointer(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(PETSC_SUCCESS);
204 }
205 
206 /*@C
207   PetscDrawLGSetLegend - sets the names of each curve plotted
208 
209   Logically Collective
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 {
224   PetscInt i;
225 
226   PetscFunctionBegin;
227   PetscValidHeaderSpecific(lg, PETSC_DRAWLG_CLASSID, 1);
228   if (names) PetscAssertPointer(names, 2);
229 
230   if (lg->legend) {
231     for (i = 0; i < lg->dim; i++) PetscCall(PetscFree(lg->legend[i]));
232     PetscCall(PetscFree(lg->legend));
233   }
234   if (names) {
235     PetscCall(PetscMalloc1(lg->dim, &lg->legend));
236     for (i = 0; i < lg->dim; i++) PetscCall(PetscStrallocpy(names[i], &lg->legend[i]));
237   }
238   PetscFunctionReturn(PETSC_SUCCESS);
239 }
240 
241 /*@
242   PetscDrawLGGetDimension - Get the number of curves that are to be drawn.
243 
244   Not Collective
245 
246   Input Parameter:
247 . lg - the line graph context.
248 
249   Output Parameter:
250 . dim - the number of curves.
251 
252   Level: intermediate
253 
254 .seealso: `PetscDrawLGC`, `PetscDrawLGCreate()`, `PetscDrawLGSetDimension()`
255 @*/
256 PetscErrorCode PetscDrawLGGetDimension(PetscDrawLG lg, PetscInt *dim)
257 {
258   PetscFunctionBegin;
259   PetscValidHeaderSpecific(lg, PETSC_DRAWLG_CLASSID, 1);
260   PetscAssertPointer(dim, 2);
261   *dim = lg->dim;
262   PetscFunctionReturn(PETSC_SUCCESS);
263 }
264 
265 /*@
266   PetscDrawLGSetDimension - Change the number of curves that are to be drawn.
267 
268   Logically Collective
269 
270   Input Parameters:
271 + lg  - the line graph context.
272 - dim - the number of curves.
273 
274   Level: intermediate
275 
276 .seealso: `PetscDrawLGCreate()`, `PetscDrawLGGetDimension()`
277 @*/
278 PetscErrorCode PetscDrawLGSetDimension(PetscDrawLG lg, PetscInt dim)
279 {
280   PetscInt i;
281 
282   PetscFunctionBegin;
283   PetscValidHeaderSpecific(lg, PETSC_DRAWLG_CLASSID, 1);
284   PetscValidLogicalCollectiveInt(lg, dim, 2);
285   if (lg->dim == dim) PetscFunctionReturn(PETSC_SUCCESS);
286 
287   PetscCall(PetscFree2(lg->x, lg->y));
288   if (lg->legend) {
289     for (i = 0; i < lg->dim; i++) PetscCall(PetscFree(lg->legend[i]));
290     PetscCall(PetscFree(lg->legend));
291   }
292   PetscCall(PetscFree(lg->colors));
293   PetscCall(PetscCIntCast(dim, &lg->dim));
294   PetscCall(PetscMalloc2(dim * PETSC_DRAW_LG_CHUNK_SIZE, &lg->x, dim * PETSC_DRAW_LG_CHUNK_SIZE, &lg->y));
295   lg->len = lg->dim * PETSC_DRAW_LG_CHUNK_SIZE;
296   PetscFunctionReturn(PETSC_SUCCESS);
297 }
298 
299 /*@
300   PetscDrawLGSetLimits - Sets the axis limits for a line graph. If more
301   points are added after this call, the limits will be adjusted to
302   include those additional points.
303 
304   Logically Collective
305 
306   Input Parameters:
307 + lg    - the line graph context
308 . x_min - the horizontal lower limit
309 . x_max - the horizontal upper limit
310 . y_min - the vertical lower limit
311 - y_max - the vertical upper limit
312 
313   Level: intermediate
314 
315 .seealso: `PetscDrawLGCreate()`, `PetscDrawLG`, `PetscDrawAxis`
316 @*/
317 PetscErrorCode PetscDrawLGSetLimits(PetscDrawLG lg, PetscReal x_min, PetscReal x_max, PetscReal y_min, PetscReal y_max)
318 {
319   PetscFunctionBegin;
320   PetscValidHeaderSpecific(lg, PETSC_DRAWLG_CLASSID, 1);
321 
322   (lg)->xmin = x_min;
323   (lg)->xmax = x_max;
324   (lg)->ymin = y_min;
325   (lg)->ymax = y_max;
326   PetscFunctionReturn(PETSC_SUCCESS);
327 }
328 
329 /*@
330   PetscDrawLGReset - Clears line graph to allow for reuse with new data.
331 
332   Logically Collective
333 
334   Input Parameter:
335 . lg - the line graph context.
336 
337   Level: intermediate
338 
339 .seealso: `PetscDrawLG`, `PetscDrawLGCreate()`
340 @*/
341 PetscErrorCode PetscDrawLGReset(PetscDrawLG lg)
342 {
343   PetscFunctionBegin;
344   PetscValidHeaderSpecific(lg, PETSC_DRAWLG_CLASSID, 1);
345   lg->xmin  = 1.e20;
346   lg->ymin  = 1.e20;
347   lg->xmax  = -1.e20;
348   lg->ymax  = -1.e20;
349   lg->loc   = 0;
350   lg->nopts = 0;
351   PetscFunctionReturn(PETSC_SUCCESS);
352 }
353 
354 /*@
355   PetscDrawLGDestroy - Frees all space taken up by line graph data structure.
356 
357   Collective
358 
359   Input Parameter:
360 . lg - the line graph context
361 
362   Level: intermediate
363 
364 .seealso: `PetscDrawLG`, `PetscDrawLGCreate()`
365 @*/
366 PetscErrorCode PetscDrawLGDestroy(PetscDrawLG *lg)
367 {
368   PetscInt i;
369 
370   PetscFunctionBegin;
371   if (!*lg) PetscFunctionReturn(PETSC_SUCCESS);
372   PetscValidHeaderSpecific(*lg, PETSC_DRAWLG_CLASSID, 1);
373   if (--((PetscObject)*lg)->refct > 0) {
374     *lg = NULL;
375     PetscFunctionReturn(PETSC_SUCCESS);
376   }
377 
378   if ((*lg)->legend) {
379     for (i = 0; i < (*lg)->dim; i++) PetscCall(PetscFree((*lg)->legend[i]));
380     PetscCall(PetscFree((*lg)->legend));
381   }
382   PetscCall(PetscFree((*lg)->colors));
383   PetscCall(PetscFree2((*lg)->x, (*lg)->y));
384   PetscCall(PetscDrawAxisDestroy(&(*lg)->axis));
385   PetscCall(PetscDrawDestroy(&(*lg)->win));
386   PetscCall(PetscHeaderDestroy(lg));
387   PetscFunctionReturn(PETSC_SUCCESS);
388 }
389 /*@
390   PetscDrawLGSetUseMarkers - Causes the line graph object to draw a marker for each data-point.
391 
392   Logically Collective
393 
394   Input Parameters:
395 + lg  - the linegraph context
396 - flg - should mark each data point
397 
398   Options Database Key:
399 . -lg_use_markers  <true,false> - true means it draws a marker for each point
400 
401   Level: intermediate
402 
403 .seealso: `PetscDrawLG`, `PetscDrawLGCreate()`
404 @*/
405 PetscErrorCode PetscDrawLGSetUseMarkers(PetscDrawLG lg, PetscBool flg)
406 {
407   PetscFunctionBegin;
408   PetscValidHeaderSpecific(lg, PETSC_DRAWLG_CLASSID, 1);
409   PetscValidLogicalCollectiveBool(lg, flg, 2);
410   lg->use_markers = flg;
411   PetscFunctionReturn(PETSC_SUCCESS);
412 }
413 
414 /*@
415   PetscDrawLGDraw - Redraws a line graph.
416 
417   Collective
418 
419   Input Parameter:
420 . lg - the line graph context
421 
422   Level: intermediate
423 
424 .seealso: `PetscDrawLG`, `PetscDrawSPDraw()`, `PetscDrawLGSPDraw()`, `PetscDrawLGReset()`
425 @*/
426 PetscErrorCode PetscDrawLGDraw(PetscDrawLG lg)
427 {
428   PetscReal   xmin, xmax, ymin, ymax;
429   PetscMPIInt rank;
430   PetscDraw   draw;
431   PetscBool   isnull;
432 
433   PetscFunctionBegin;
434   PetscValidHeaderSpecific(lg, PETSC_DRAWLG_CLASSID, 1);
435   PetscCall(PetscDrawIsNull(lg->win, &isnull));
436   if (isnull) PetscFunctionReturn(PETSC_SUCCESS);
437   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)lg), &rank));
438 
439   draw = lg->win;
440   PetscCall(PetscDrawCheckResizedWindow(draw));
441   PetscCall(PetscDrawClear(draw));
442 
443   xmin = lg->xmin;
444   xmax = lg->xmax;
445   ymin = lg->ymin;
446   ymax = lg->ymax;
447   // Try not to freak out the axis
448   if (ymax - ymin < PETSC_SMALL) {
449     ymin -= 0.1 * ymax;
450     ymax += 0.1 * ymax;
451   }
452   PetscCall(PetscDrawAxisSetLimits(lg->axis, xmin, xmax, ymin, ymax));
453   PetscCall(PetscDrawAxisDraw(lg->axis));
454 
455   PetscDrawCollectiveBegin(draw);
456   if (rank == 0) {
457     int i, j, dim = lg->dim, nopts = lg->nopts, cl;
458     for (i = 0; i < dim; i++) {
459       for (j = 1; j < nopts; j++) {
460         cl = lg->colors ? lg->colors[i] : ((PETSC_DRAW_BLACK + i) % PETSC_DRAW_MAXCOLOR);
461         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));
462         if (lg->use_markers) PetscCall(PetscDrawMarker(draw, lg->x[j * dim + i], lg->y[j * dim + i], cl));
463       }
464     }
465   }
466   if (rank == 0 && lg->legend) {
467     PetscBool right = PETSC_FALSE;
468     int       i, dim = lg->dim, cl;
469     PetscReal xl, yl, xr, yr, tw, th;
470     size_t    slen, len = 0;
471 
472     PetscCall(PetscDrawAxisGetLimits(lg->axis, &xl, &xr, &yl, &yr));
473     PetscCall(PetscDrawStringGetSize(draw, &tw, &th));
474     for (i = 0; i < dim; i++) {
475       PetscCall(PetscStrlen(lg->legend[i], &slen));
476       len = PetscMax(len, slen);
477     }
478     if (right) {
479       xr = xr - 1.5 * tw;
480       xl = xr - ((PetscReal)len + 7) * tw;
481     } else {
482       xl = xl + 1.5 * tw;
483       xr = xl + ((PetscReal)len + 7) * tw;
484     }
485     yr = yr - 1.0 * th;
486     yl = yr - (dim + 1) * th;
487     PetscCall(PetscDrawLine(draw, xl, yl, xr, yl, PETSC_DRAW_BLACK));
488     PetscCall(PetscDrawLine(draw, xr, yl, xr, yr, PETSC_DRAW_BLACK));
489     PetscCall(PetscDrawLine(draw, xr, yr, xl, yr, PETSC_DRAW_BLACK));
490     PetscCall(PetscDrawLine(draw, xl, yr, xl, yl, PETSC_DRAW_BLACK));
491     for (i = 0; i < dim; i++) {
492       cl = lg->colors ? lg->colors[i] : (PETSC_DRAW_BLACK + i);
493       PetscCall(PetscDrawLine(draw, xl + 1 * tw, yr - (i + 1) * th, xl + 5 * tw, yr - (i + 1) * th, cl));
494       PetscCall(PetscDrawString(draw, xl + 6 * tw, yr - (i + 1.5) * th, PETSC_DRAW_BLACK, lg->legend[i]));
495     }
496   }
497   PetscDrawCollectiveEnd(draw);
498 
499   PetscCall(PetscDrawFlush(draw));
500   PetscCall(PetscDrawPause(draw));
501   PetscFunctionReturn(PETSC_SUCCESS);
502 }
503 
504 /*@
505   PetscDrawLGSave - Saves a drawn image
506 
507   Collective
508 
509   Input Parameter:
510 . lg - The line graph context
511 
512   Level: intermediate
513 
514 .seealso: `PetscDrawLG`, `PetscDrawSave()`, `PetscDrawLGCreate()`, `PetscDrawLGGetDraw()`, `PetscDrawSetSave()`
515 @*/
516 PetscErrorCode PetscDrawLGSave(PetscDrawLG lg)
517 {
518   PetscFunctionBegin;
519   PetscValidHeaderSpecific(lg, PETSC_DRAWLG_CLASSID, 1);
520   PetscCall(PetscDrawSave(lg->win));
521   PetscFunctionReturn(PETSC_SUCCESS);
522 }
523 
524 /*@
525   PetscDrawLGView - Prints a line graph.
526 
527   Collective
528 
529   Input Parameters:
530 + lg     - the line graph context
531 - viewer - the viewer to view it with
532 
533   Level: beginner
534 
535 .seealso: `PetscDrawLG`, `PetscDrawLGCreate()`
536 @*/
537 PetscErrorCode PetscDrawLGView(PetscDrawLG lg, PetscViewer viewer)
538 {
539   PetscReal xmin = lg->xmin, xmax = lg->xmax, ymin = lg->ymin, ymax = lg->ymax;
540   PetscInt  i, j, dim = lg->dim, nopts = lg->nopts;
541 
542   PetscFunctionBegin;
543   PetscValidHeaderSpecific(lg, PETSC_DRAWLG_CLASSID, 1);
544 
545   if (nopts < 1) PetscFunctionReturn(PETSC_SUCCESS);
546   if (xmin > xmax || ymin > ymax) PetscFunctionReturn(PETSC_SUCCESS);
547 
548   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)lg), &viewer));
549   PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)lg, viewer));
550   for (i = 0; i < dim; i++) {
551     PetscCall(PetscViewerASCIIPrintf(viewer, "Line %" PetscInt_FMT ">\n", i));
552     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]));
553   }
554   PetscFunctionReturn(PETSC_SUCCESS);
555 }
556 
557 /*@
558   PetscDrawLGSetOptionsPrefix - Sets the prefix used for searching for all
559   `PetscDrawLG` options in the database.
560 
561   Logically Collective
562 
563   Input Parameters:
564 + lg     - the line graph context
565 - prefix - the prefix to prepend to all option names
566 
567   Level: advanced
568 
569 .seealso: `PetscDrawLG`, `PetscDrawLGSetFromOptions()`, `PetscDrawLGCreate()`
570 @*/
571 PetscErrorCode PetscDrawLGSetOptionsPrefix(PetscDrawLG lg, const char prefix[])
572 {
573   PetscFunctionBegin;
574   PetscValidHeaderSpecific(lg, PETSC_DRAWLG_CLASSID, 1);
575   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)lg, prefix));
576   PetscFunctionReturn(PETSC_SUCCESS);
577 }
578 
579 /*@
580   PetscDrawLGSetFromOptions - Sets options related to the line graph object
581 
582   Collective
583 
584   Input Parameters:
585 . lg - the line graph context
586 
587   Options Database Key:
588 . -lg_use_markers  <true,false> - true means it draws a marker for each point
589 
590   Level: intermediate
591 
592 .seealso: `PetscDrawLG`, `PetscDrawLGDestroy()`, `PetscDrawLGCreate()`
593 @*/
594 PetscErrorCode PetscDrawLGSetFromOptions(PetscDrawLG lg)
595 {
596   PetscBool           usemarkers, set;
597   PetscDrawMarkerType markertype;
598 
599   PetscFunctionBegin;
600   PetscValidHeaderSpecific(lg, PETSC_DRAWLG_CLASSID, 1);
601 
602   PetscCall(PetscDrawGetMarkerType(lg->win, &markertype));
603   PetscCall(PetscOptionsGetEnum(((PetscObject)lg)->options, ((PetscObject)lg)->prefix, "-lg_marker_type", PetscDrawMarkerTypes, (PetscEnum *)&markertype, &set));
604   if (set) {
605     PetscCall(PetscDrawLGSetUseMarkers(lg, PETSC_TRUE));
606     PetscCall(PetscDrawSetMarkerType(lg->win, markertype));
607   }
608   usemarkers = lg->use_markers;
609   PetscCall(PetscOptionsGetBool(((PetscObject)lg)->options, ((PetscObject)lg)->prefix, "-lg_use_markers", &usemarkers, &set));
610   if (set) PetscCall(PetscDrawLGSetUseMarkers(lg, usemarkers));
611   PetscFunctionReturn(PETSC_SUCCESS);
612 }
613