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