Actual source code: lgc.c
2: #include <petscviewer.h>
3: #include <petsc/private/drawimpl.h>
4: PetscClassId PETSC_DRAWLG_CLASSID = 0;
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.
12: Not Collective, if lg is parallel then axis is parallel
14: Input Parameter:
15: . lg - the line graph context
17: Output Parameter:
18: . axis - the axis context
20: Level: advanced
22: .seealso: `PetscDrawLGCreate()`, `PetscDrawAxis`, `PetscDrawLG`
23: @*/
24: PetscErrorCode PetscDrawLGGetAxis(PetscDrawLG lg, PetscDrawAxis *axis)
25: {
26: PetscFunctionBegin;
29: *axis = lg->axis;
30: PetscFunctionReturn(PETSC_SUCCESS);
31: }
33: /*@
34: PetscDrawLGGetDraw - Gets the draw context associated with a line graph.
36: Not Collective, if lg is parallel then draw is parallel
38: Input Parameter:
39: . lg - the line graph context
41: Output Parameter:
42: . draw - the draw context
44: Level: intermediate
46: .seealso: `PetscDrawLGCreate()`, `PetscDraw`, `PetscDrawLG`
47: @*/
48: PetscErrorCode PetscDrawLGGetDraw(PetscDrawLG lg, PetscDraw *draw)
49: {
50: PetscFunctionBegin;
53: *draw = lg->win;
54: PetscFunctionReturn(PETSC_SUCCESS);
55: }
57: /*@
58: PetscDrawLGSPDraw - Redraws a line graph and a scatter plot on the same `PetscDraw` they must share
60: Collective
62: Input Parameters:
63: + lg - the line graph context
64: - spin - the scatter plot
66: Level: intermediate
68: Developer Note:
69: This code cheats and uses the fact that the `PetscDrawLG` and `PetscDrawSP` structs are the same
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;
81: PetscFunctionBegin;
84: PetscCall(PetscDrawIsNull(lg->win, &isnull));
85: if (isnull) PetscFunctionReturn(PETSC_SUCCESS);
86: PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)lg), &rank));
88: draw = lg->win;
89: PetscCall(PetscDrawCheckResizedWindow(draw));
90: PetscCall(PetscDrawClear(draw));
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));
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);
118: PetscCall(PetscDrawFlush(draw));
119: PetscCall(PetscDrawPause(draw));
120: PetscFunctionReturn(PETSC_SUCCESS);
121: }
123: /*@
124: PetscDrawLGCreate - Creates a line graph data structure.
126: Collective
128: Input Parameters:
129: + draw - the window where the graph will be made.
130: - dim - the number of curves which will be drawn
132: Output Parameter:
133: . outlg - the line graph context
135: Level: intermediate
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.
141: All MPI ranks in the communicator must call `PetscDrawLGDraw()` to display the updated graph.
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;
151: PetscFunctionBegin;
156: PetscCall(PetscHeaderCreate(lg, PETSC_DRAWLG_CLASSID, "DrawLG", "Line Graph", "Draw", PetscObjectComm((PetscObject)draw), PetscDrawLGDestroy, NULL));
157: PetscCall(PetscDrawLGSetOptionsPrefix(lg, ((PetscObject)draw)->prefix));
159: PetscCall(PetscObjectReference((PetscObject)draw));
160: lg->win = draw;
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;
171: PetscCall(PetscMalloc2(dim * PETSC_DRAW_LG_CHUNK_SIZE, &lg->x, dim * PETSC_DRAW_LG_CHUNK_SIZE, &lg->y));
173: lg->len = dim * PETSC_DRAW_LG_CHUNK_SIZE;
174: lg->loc = 0;
175: lg->use_markers = PETSC_FALSE;
177: PetscCall(PetscDrawAxisCreate(draw, &lg->axis));
179: *outlg = lg;
180: PetscFunctionReturn(PETSC_SUCCESS);
181: }
183: /*@
184: PetscDrawLGSetColors - Sets the color of each line graph drawn
186: Logically Collective
188: Input Parameters:
189: + lg - the line graph context.
190: - colors - the colors
192: Level: intermediate
194: .seealso: `PetscDrawLG`, `PetscDrawLGCreate()`
195: @*/
196: PetscErrorCode PetscDrawLGSetColors(PetscDrawLG lg, const int colors[])
197: {
198: PetscFunctionBegin;
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: }
208: /*@C
209: PetscDrawLGSetLegend - sets the names of each curve plotted
211: Logically Collective
213: Input Parameters:
214: + lg - the line graph context.
215: - names - the names for each curve
217: Level: intermediate
219: Note:
220: Call `PetscDrawLGGetAxis()` and then change properties of the `PetscDrawAxis` for detailed control of the plot
222: .seealso: `PetscDrawLGGetAxis()`, `PetscDrawAxis`, `PetscDrawAxisSetColors()`, `PetscDrawAxisSetLabels()`, `PetscDrawAxisSetHoldLimits()`
223: @*/
224: PetscErrorCode PetscDrawLGSetLegend(PetscDrawLG lg, const char *const *names)
225: {
226: PetscInt i;
228: PetscFunctionBegin;
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: }
243: /*@
244: PetscDrawLGGetDimension - Get the number of curves that are to be drawn.
246: Not Collective
248: Input Parameter:
249: . lg - the line graph context.
251: Output Parameter:
252: . dim - the number of curves.
254: Level: intermediate
256: .seealso: `PetscDrawLGC`, `PetscDrawLGCreate()`, `PetscDrawLGSetDimension()`
257: @*/
258: PetscErrorCode PetscDrawLGGetDimension(PetscDrawLG lg, PetscInt *dim)
259: {
260: PetscFunctionBegin;
263: *dim = lg->dim;
264: PetscFunctionReturn(PETSC_SUCCESS);
265: }
267: /*@
268: PetscDrawLGSetDimension - Change the number of curves that are to be drawn.
270: Logically Collective
272: Input Parameters:
273: + lg - the line graph context.
274: - dim - the number of curves.
276: Level: intermediate
278: .seealso: `PetscDrawLGCreate()`, `PetscDrawLGGetDimension()`
279: @*/
280: PetscErrorCode PetscDrawLGSetDimension(PetscDrawLG lg, PetscInt dim)
281: {
282: PetscInt i;
284: PetscFunctionBegin;
287: if (lg->dim == dim) PetscFunctionReturn(PETSC_SUCCESS);
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: }
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.
306: Logically Collective
308: Input Parameters:
309: + xlg - 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
315: Level: intermediate
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;
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: }
331: /*@
332: PetscDrawLGReset - Clears line graph to allow for reuse with new data.
334: Logically Collective
336: Input Parameter:
337: . lg - the line graph context.
339: Level: intermediate
341: .seealso: `PetscDrawLG`, `PetscDrawLGCreate()`
342: @*/
343: PetscErrorCode PetscDrawLGReset(PetscDrawLG lg)
344: {
345: PetscFunctionBegin;
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: }
356: /*@
357: PetscDrawLGDestroy - Frees all space taken up by line graph data structure.
359: Collective
361: Input Parameter:
362: . lg - the line graph context
364: Level: intermediate
366: .seealso: `PetscDrawLG`, `PetscDrawLGCreate()`
367: @*/
368: PetscErrorCode PetscDrawLGDestroy(PetscDrawLG *lg)
369: {
370: PetscInt i;
372: PetscFunctionBegin;
373: if (!*lg) PetscFunctionReturn(PETSC_SUCCESS);
375: if (--((PetscObject)(*lg))->refct > 0) {
376: *lg = NULL;
377: PetscFunctionReturn(PETSC_SUCCESS);
378: }
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.
394: Logically Collective
396: Input Parameters:
397: + lg - the linegraph context
398: - flg - should mark each data point
400: Options Database Key:
401: . -lg_use_markers <true,false> - true means it draws a marker for each point
403: Level: intermediate
405: .seealso: `PetscDrawLG`, `PetscDrawLGCreate()`
406: @*/
407: PetscErrorCode PetscDrawLGSetUseMarkers(PetscDrawLG lg, PetscBool flg)
408: {
409: PetscFunctionBegin;
412: lg->use_markers = flg;
413: PetscFunctionReturn(PETSC_SUCCESS);
414: }
416: /*@
417: PetscDrawLGDraw - Redraws a line graph.
419: Collective
421: Input Parameter:
422: . lg - the line graph context
424: Level: intermediate
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;
435: PetscFunctionBegin;
437: PetscCall(PetscDrawIsNull(lg->win, &isnull));
438: if (isnull) PetscFunctionReturn(PETSC_SUCCESS);
439: PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)lg), &rank));
441: draw = lg->win;
442: PetscCall(PetscDrawCheckResizedWindow(draw));
443: PetscCall(PetscDrawClear(draw));
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));
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);
495: PetscCall(PetscDrawFlush(draw));
496: PetscCall(PetscDrawPause(draw));
497: PetscFunctionReturn(PETSC_SUCCESS);
498: }
500: /*@
501: PetscDrawLGSave - Saves a drawn image
503: Collective
505: Input Parameter:
506: . lg - The line graph context
508: Level: intermediate
510: .seealso: `PetscDrawLG`, `PetscDrawSave()`, `PetscDrawLGCreate()`, `PetscDrawLGGetDraw()`, `PetscDrawSetSave()`, `PetscDrawSave()`
511: @*/
512: PetscErrorCode PetscDrawLGSave(PetscDrawLG lg)
513: {
514: PetscFunctionBegin;
516: PetscCall(PetscDrawSave(lg->win));
517: PetscFunctionReturn(PETSC_SUCCESS);
518: }
520: /*@
521: PetscDrawLGView - Prints a line graph.
523: Collective
525: Input Parameter:
526: . lg - the line graph context
528: Level: beginner
530: .seealso: `PetscDrawLG`, `PetscDrawLGCreate()`
531: @*/
532: PetscErrorCode PetscDrawLGView(PetscDrawLG lg, PetscViewer viewer)
533: {
534: PetscReal xmin = lg->xmin, xmax = lg->xmax, ymin = lg->ymin, ymax = lg->ymax;
535: PetscInt i, j, dim = lg->dim, nopts = lg->nopts;
537: PetscFunctionBegin;
540: if (nopts < 1) PetscFunctionReturn(PETSC_SUCCESS);
541: if (xmin > xmax || ymin > ymax) PetscFunctionReturn(PETSC_SUCCESS);
543: if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)lg), &viewer));
544: PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)lg, viewer));
545: for (i = 0; i < dim; i++) {
546: PetscCall(PetscViewerASCIIPrintf(viewer, "Line %" PetscInt_FMT ">\n", i));
547: 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]));
548: }
549: PetscFunctionReturn(PETSC_SUCCESS);
550: }
552: /*@C
553: PetscDrawLGSetOptionsPrefix - Sets the prefix used for searching for all
554: `PetscDrawLG` options in the database.
556: Logically Collective
558: Input Parameters:
559: + lg - the line graph context
560: - prefix - the prefix to prepend to all option names
562: Level: advanced
564: .seealso: `PetscDrawLG`, `PetscDrawLGSetFromOptions()`, `PetscDrawLGCreate()`
565: @*/
566: PetscErrorCode PetscDrawLGSetOptionsPrefix(PetscDrawLG lg, const char prefix[])
567: {
568: PetscFunctionBegin;
570: PetscCall(PetscObjectSetOptionsPrefix((PetscObject)lg, prefix));
571: PetscFunctionReturn(PETSC_SUCCESS);
572: }
574: /*@
575: PetscDrawLGSetFromOptions - Sets options related to the line graph object
577: Collective
579: Input Parameters:
580: . lg - the line graph context
582: Options Database Key:
583: . -lg_use_markers <true,false> - true means it draws a marker for each point
585: Level: intermediate
587: .seealso: `PetscDrawLG`, `PetscDrawLGDestroy()`, `PetscDrawLGCreate()`
588: @*/
589: PetscErrorCode PetscDrawLGSetFromOptions(PetscDrawLG lg)
590: {
591: PetscBool usemarkers, set;
592: PetscDrawMarkerType markertype;
594: PetscFunctionBegin;
597: PetscCall(PetscDrawGetMarkerType(lg->win, &markertype));
598: PetscCall(PetscOptionsGetEnum(((PetscObject)lg)->options, ((PetscObject)lg)->prefix, "-lg_marker_type", PetscDrawMarkerTypes, (PetscEnum *)&markertype, &set));
599: if (set) {
600: PetscCall(PetscDrawLGSetUseMarkers(lg, PETSC_TRUE));
601: PetscCall(PetscDrawSetMarkerType(lg->win, markertype));
602: }
603: usemarkers = lg->use_markers;
604: PetscCall(PetscOptionsGetBool(((PetscObject)lg)->options, ((PetscObject)lg)->prefix, "-lg_use_markers", &usemarkers, &set));
605: if (set) PetscCall(PetscDrawLGSetUseMarkers(lg, usemarkers));
606: PetscFunctionReturn(PETSC_SUCCESS);
607: }