xref: /petsc/src/sys/classes/draw/utils/lgc.c (revision d5b43468fb8780a8feea140ccd6fa3e6a50411cc)
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   PetscValidPointer(axis, 2);
29   *axis = lg->axis;
30   PetscFunctionReturn(0);
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   PetscValidPointer(draw, 2);
53   *draw = lg->win;
54   PetscFunctionReturn(0);
55 }
56 
57 /*@
58   PetscDrawLGSPDraw - Redraws a line graph and a scatter plot on the same `PetscDraw` they must share
59 
60    Collective on lg
61 
62    Input Parameters:
63 +  lg - the line graph context
64 -  spin - the scatter plot
65 
66    Level: intermediate
67 
68    Developer Note:
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(0);
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(0);
121 }
122 
123 /*@
124     PetscDrawLGCreate - Creates a line graph data structure.
125 
126     Collective on draw
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 Parameters:
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: `PetscDrawLGCreate`, `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   PetscValidPointer(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(0);
181 }
182 
183 /*@
184    PetscDrawLGSetColors - Sets the color of each line graph drawn
185 
186    Logically Collective on lg
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) PetscValidIntPointer(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(0);
206 }
207 
208 /*@C
209    PetscDrawLGSetLegend - sets the names of each curve plotted
210 
211    Logically Collective on lg
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) PetscValidPointer(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(0);
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   PetscValidIntPointer(dim, 2);
263   *dim = lg->dim;
264   PetscFunctionReturn(0);
265 }
266 
267 /*@
268    PetscDrawLGSetDimension - Change the number of curves that are to be drawn.
269 
270    Logically Collective on lg
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(0);
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(0);
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 on lg
307 
308    Input Parameters:
309 +  xlg - the line graph context
310 -  x_min,x_max,y_min,y_max - the limits
311 
312    Level: intermediate
313 
314 .seealso: `PetscDrawLGCreate()`, `PetscDrawLG`, `PetscDrawAxis`
315 @*/
316 PetscErrorCode PetscDrawLGSetLimits(PetscDrawLG lg, PetscReal x_min, PetscReal x_max, PetscReal y_min, PetscReal y_max)
317 {
318   PetscFunctionBegin;
319   PetscValidHeaderSpecific(lg, PETSC_DRAWLG_CLASSID, 1);
320 
321   (lg)->xmin = x_min;
322   (lg)->xmax = x_max;
323   (lg)->ymin = y_min;
324   (lg)->ymax = y_max;
325   PetscFunctionReturn(0);
326 }
327 
328 /*@
329    PetscDrawLGReset - Clears line graph to allow for reuse with new data.
330 
331    Logically Collective on lg
332 
333    Input Parameter:
334 .  lg - the line graph context.
335 
336    Level: intermediate
337 
338 .seealso: `PetscDrawLG`, `PetscDrawLGCreate()`
339 @*/
340 PetscErrorCode PetscDrawLGReset(PetscDrawLG lg)
341 {
342   PetscFunctionBegin;
343   PetscValidHeaderSpecific(lg, PETSC_DRAWLG_CLASSID, 1);
344   lg->xmin  = 1.e20;
345   lg->ymin  = 1.e20;
346   lg->xmax  = -1.e20;
347   lg->ymax  = -1.e20;
348   lg->loc   = 0;
349   lg->nopts = 0;
350   PetscFunctionReturn(0);
351 }
352 
353 /*@
354    PetscDrawLGDestroy - Frees all space taken up by line graph data structure.
355 
356    Collective on lg
357 
358    Input Parameter:
359 .  lg - the line graph context
360 
361    Level: intermediate
362 
363 .seealso: `PetscDrawLG`, `PetscDrawLGCreate()`
364 @*/
365 PetscErrorCode PetscDrawLGDestroy(PetscDrawLG *lg)
366 {
367   PetscInt i;
368 
369   PetscFunctionBegin;
370   if (!*lg) PetscFunctionReturn(0);
371   PetscValidHeaderSpecific(*lg, PETSC_DRAWLG_CLASSID, 1);
372   if (--((PetscObject)(*lg))->refct > 0) {
373     *lg = NULL;
374     PetscFunctionReturn(0);
375   }
376 
377   if ((*lg)->legend) {
378     for (i = 0; i < (*lg)->dim; i++) PetscCall(PetscFree((*lg)->legend[i]));
379     PetscCall(PetscFree((*lg)->legend));
380   }
381   PetscCall(PetscFree((*lg)->colors));
382   PetscCall(PetscFree2((*lg)->x, (*lg)->y));
383   PetscCall(PetscDrawAxisDestroy(&(*lg)->axis));
384   PetscCall(PetscDrawDestroy(&(*lg)->win));
385   PetscCall(PetscHeaderDestroy(lg));
386   PetscFunctionReturn(0);
387 }
388 /*@
389    PetscDrawLGSetUseMarkers - Causes the line graph object to draw a marker for each data-point.
390 
391    Logically Collective on lg
392 
393    Input Parameters:
394 +  lg - the linegraph context
395 -  flg - should mark each data point
396 
397    Options Database Key:
398 .  -lg_use_markers  <true,false> - true means it draws a marker for each point
399 
400    Level: intermediate
401 
402 .seealso: `PetscDrawLG`, `PetscDrawLGCreate()`
403 @*/
404 PetscErrorCode PetscDrawLGSetUseMarkers(PetscDrawLG lg, PetscBool flg)
405 {
406   PetscFunctionBegin;
407   PetscValidHeaderSpecific(lg, PETSC_DRAWLG_CLASSID, 1);
408   PetscValidLogicalCollectiveBool(lg, flg, 2);
409   lg->use_markers = flg;
410   PetscFunctionReturn(0);
411 }
412 
413 /*@
414    PetscDrawLGDraw - Redraws a line graph.
415 
416    Collective on lg
417 
418    Input Parameter:
419 .  lg - the line graph context
420 
421    Level: intermediate
422 
423 .seealso: `PetscDrawLG`, `PetscDrawSPDraw()`, `PetscDrawLGSPDraw()`, `PetscDrawLGReset()`
424 @*/
425 PetscErrorCode PetscDrawLGDraw(PetscDrawLG lg)
426 {
427   PetscReal   xmin, xmax, ymin, ymax;
428   PetscMPIInt rank;
429   PetscDraw   draw;
430   PetscBool   isnull;
431 
432   PetscFunctionBegin;
433   PetscValidHeaderSpecific(lg, PETSC_DRAWLG_CLASSID, 1);
434   PetscCall(PetscDrawIsNull(lg->win, &isnull));
435   if (isnull) PetscFunctionReturn(0);
436   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)lg), &rank));
437 
438   draw = lg->win;
439   PetscCall(PetscDrawCheckResizedWindow(draw));
440   PetscCall(PetscDrawClear(draw));
441 
442   xmin = lg->xmin;
443   xmax = lg->xmax;
444   ymin = lg->ymin;
445   ymax = lg->ymax;
446   PetscCall(PetscDrawAxisSetLimits(lg->axis, xmin, xmax, ymin, ymax));
447   PetscCall(PetscDrawAxisDraw(lg->axis));
448 
449   PetscDrawCollectiveBegin(draw);
450   if (rank == 0) {
451     int i, j, dim = lg->dim, nopts = lg->nopts, cl;
452     for (i = 0; i < dim; i++) {
453       for (j = 1; j < nopts; j++) {
454         cl = lg->colors ? lg->colors[i] : ((PETSC_DRAW_BLACK + i) % PETSC_DRAW_MAXCOLOR);
455         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));
456         if (lg->use_markers) PetscCall(PetscDrawMarker(draw, lg->x[j * dim + i], lg->y[j * dim + i], cl));
457       }
458     }
459   }
460   if (rank == 0 && lg->legend) {
461     PetscBool right = PETSC_FALSE;
462     int       i, dim = lg->dim, cl;
463     PetscReal xl, yl, xr, yr, tw, th;
464     size_t    slen, len = 0;
465     PetscCall(PetscDrawAxisGetLimits(lg->axis, &xl, &xr, &yl, &yr));
466     PetscCall(PetscDrawStringGetSize(draw, &tw, &th));
467     for (i = 0; i < dim; i++) {
468       PetscCall(PetscStrlen(lg->legend[i], &slen));
469       len = PetscMax(len, slen);
470     }
471     if (right) {
472       xr = xr - 1.5 * tw;
473       xl = xr - (len + 7) * tw;
474     } else {
475       xl = xl + 1.5 * tw;
476       xr = xl + (len + 7) * tw;
477     }
478     yr = yr - 1.0 * th;
479     yl = yr - (dim + 1) * th;
480     PetscCall(PetscDrawLine(draw, xl, yl, xr, yl, PETSC_DRAW_BLACK));
481     PetscCall(PetscDrawLine(draw, xr, yl, xr, yr, PETSC_DRAW_BLACK));
482     PetscCall(PetscDrawLine(draw, xr, yr, xl, yr, PETSC_DRAW_BLACK));
483     PetscCall(PetscDrawLine(draw, xl, yr, xl, yl, PETSC_DRAW_BLACK));
484     for (i = 0; i < dim; i++) {
485       cl = lg->colors ? lg->colors[i] : (PETSC_DRAW_BLACK + i);
486       PetscCall(PetscDrawLine(draw, xl + 1 * tw, yr - (i + 1) * th, xl + 5 * tw, yr - (i + 1) * th, cl));
487       PetscCall(PetscDrawString(draw, xl + 6 * tw, yr - (i + 1.5) * th, PETSC_DRAW_BLACK, lg->legend[i]));
488     }
489   }
490   PetscDrawCollectiveEnd(draw);
491 
492   PetscCall(PetscDrawFlush(draw));
493   PetscCall(PetscDrawPause(draw));
494   PetscFunctionReturn(0);
495 }
496 
497 /*@
498   PetscDrawLGSave - Saves a drawn image
499 
500   Collective on lg
501 
502   Input Parameter:
503 . lg - The line graph context
504 
505   Level: intermediate
506 
507 .seealso: `PetscDrawLG`, `PetscDrawSave()`, `PetscDrawLGCreate()`, `PetscDrawLGGetDraw()`, `PetscDrawSetSave()`, `PetscDrawSave()`
508 @*/
509 PetscErrorCode PetscDrawLGSave(PetscDrawLG lg)
510 {
511   PetscFunctionBegin;
512   PetscValidHeaderSpecific(lg, PETSC_DRAWLG_CLASSID, 1);
513   PetscCall(PetscDrawSave(lg->win));
514   PetscFunctionReturn(0);
515 }
516 
517 /*@
518   PetscDrawLGView - Prints a line graph.
519 
520   Collective on lg
521 
522   Input Parameter:
523 . lg - the line graph context
524 
525   Level: beginner
526 
527 .seealso: `PetscDrawLG`, `PetscDrawLGCreate()`
528 @*/
529 PetscErrorCode PetscDrawLGView(PetscDrawLG lg, PetscViewer viewer)
530 {
531   PetscReal xmin = lg->xmin, xmax = lg->xmax, ymin = lg->ymin, ymax = lg->ymax;
532   PetscInt  i, j, dim = lg->dim, nopts = lg->nopts;
533 
534   PetscFunctionBegin;
535   PetscValidHeaderSpecific(lg, PETSC_DRAWLG_CLASSID, 1);
536 
537   if (nopts < 1) PetscFunctionReturn(0);
538   if (xmin > xmax || ymin > ymax) PetscFunctionReturn(0);
539 
540   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)lg), &viewer));
541   PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)lg, viewer));
542   for (i = 0; i < dim; i++) {
543     PetscCall(PetscViewerASCIIPrintf(viewer, "Line %" PetscInt_FMT ">\n", i));
544     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]));
545   }
546   PetscFunctionReturn(0);
547 }
548 
549 /*@C
550    PetscDrawLGSetOptionsPrefix - Sets the prefix used for searching for all
551    `PetscDrawLG` options in the database.
552 
553    Logically Collective on lg
554 
555    Input Parameters:
556 +  lg - the line graph context
557 -  prefix - the prefix to prepend to all option names
558 
559    Level: advanced
560 
561 .seealso: `PetscDrawLG`, `PetscDrawLGSetFromOptions()`, `PetscDrawLGCreate()`
562 @*/
563 PetscErrorCode PetscDrawLGSetOptionsPrefix(PetscDrawLG lg, const char prefix[])
564 {
565   PetscFunctionBegin;
566   PetscValidHeaderSpecific(lg, PETSC_DRAWLG_CLASSID, 1);
567   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)lg, prefix));
568   PetscFunctionReturn(0);
569 }
570 
571 /*@
572     PetscDrawLGSetFromOptions - Sets options related to the line graph object
573 
574     Collective on lg
575 
576     Input Parameters:
577 .   lg - the line graph context
578 
579     Options Database Key:
580 .  -lg_use_markers  <true,false> - true means it draws a marker for each point
581 
582     Level: intermediate
583 
584 .seealso: `PetscDrawLG`, `PetscDrawLGDestroy()`, `PetscDrawLGCreate()`
585 @*/
586 PetscErrorCode PetscDrawLGSetFromOptions(PetscDrawLG lg)
587 {
588   PetscBool           usemarkers, set;
589   PetscDrawMarkerType markertype;
590 
591   PetscFunctionBegin;
592   PetscValidHeaderSpecific(lg, PETSC_DRAWLG_CLASSID, 1);
593 
594   PetscCall(PetscDrawGetMarkerType(lg->win, &markertype));
595   PetscCall(PetscOptionsGetEnum(((PetscObject)lg)->options, ((PetscObject)lg)->prefix, "-lg_marker_type", PetscDrawMarkerTypes, (PetscEnum *)&markertype, &set));
596   if (set) {
597     PetscCall(PetscDrawLGSetUseMarkers(lg, PETSC_TRUE));
598     PetscCall(PetscDrawSetMarkerType(lg->win, markertype));
599   }
600   usemarkers = lg->use_markers;
601   PetscCall(PetscOptionsGetBool(((PetscObject)lg)->options, ((PetscObject)lg)->prefix, "-lg_use_markers", &usemarkers, &set));
602   if (set) PetscCall(PetscDrawLGSetUseMarkers(lg, usemarkers));
603   PetscFunctionReturn(0);
604 }
605