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: {
28: *axis = lg->axis;
29: return 0;
30: }
32: /*@
33: PetscDrawLGGetDraw - Gets the draw context associated with a line graph.
35: Not Collective, if lg is parallel then draw is parallel
37: Input Parameter:
38: . lg - the line graph context
40: Output Parameter:
41: . draw - the draw context
43: Level: intermediate
45: .seealso: `PetscDrawLGCreate()`, `PetscDraw`, `PetscDrawLG`
46: @*/
47: PetscErrorCode PetscDrawLGGetDraw(PetscDrawLG lg, PetscDraw *draw)
48: {
51: *draw = lg->win;
52: return 0;
53: }
55: /*@
56: PetscDrawLGSPDraw - Redraws a line graph and a scatter plot on the same `PetscDraw` they must share
58: Collective
60: Input Parameters:
61: + lg - the line graph context
62: - spin - the scatter plot
64: Level: intermediate
66: Developer Note:
67: This code cheats and uses the fact that the `PetscDrawLG` and `PetscDrawSP` structs are the same
69: .seealso: `PetscDrawLGDraw()`, `PetscDrawSPDraw()`
70: @*/
71: PetscErrorCode PetscDrawLGSPDraw(PetscDrawLG lg, PetscDrawSP spin)
72: {
73: PetscDrawLG sp = (PetscDrawLG)spin;
74: PetscReal xmin, xmax, ymin, ymax;
75: PetscBool isnull;
76: PetscMPIInt rank;
77: PetscDraw draw;
81: PetscDrawIsNull(lg->win, &isnull);
82: if (isnull) return 0;
83: MPI_Comm_rank(PetscObjectComm((PetscObject)lg), &rank);
85: draw = lg->win;
86: PetscDrawCheckResizedWindow(draw);
87: PetscDrawClear(draw);
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: PetscDrawAxisSetLimits(lg->axis, xmin, xmax, ymin, ymax);
94: PetscDrawAxisDraw(lg->axis);
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: 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) 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++) PetscDrawMarker(draw, sp->x[j * dim + i], sp->y[j * dim + i], PETSC_DRAW_RED);
111: }
112: }
113: PetscDrawCollectiveEnd(draw);
115: PetscDrawFlush(draw);
116: PetscDrawPause(draw);
117: return 0;
118: }
120: /*@
121: PetscDrawLGCreate - Creates a line graph data structure.
123: Collective
125: Input Parameters:
126: + draw - the window where the graph will be made.
127: - dim - the number of curves which will be drawn
129: Output Parameters:
130: . outlg - the line graph context
132: Level: intermediate
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.
138: All MPI ranks in the communicator must call `PetscDrawLGDraw()` to display the updated graph.
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: {
146: PetscDrawLG lg;
152: PetscHeaderCreate(lg, PETSC_DRAWLG_CLASSID, "DrawLG", "Line Graph", "Draw", PetscObjectComm((PetscObject)draw), PetscDrawLGDestroy, NULL);
153: PetscDrawLGSetOptionsPrefix(lg, ((PetscObject)draw)->prefix);
155: PetscObjectReference((PetscObject)draw);
156: lg->win = draw;
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;
167: PetscMalloc2(dim * PETSC_DRAW_LG_CHUNK_SIZE, &lg->x, dim * PETSC_DRAW_LG_CHUNK_SIZE, &lg->y);
169: lg->len = dim * PETSC_DRAW_LG_CHUNK_SIZE;
170: lg->loc = 0;
171: lg->use_markers = PETSC_FALSE;
173: PetscDrawAxisCreate(draw, &lg->axis);
175: *outlg = lg;
176: return 0;
177: }
179: /*@
180: PetscDrawLGSetColors - Sets the color of each line graph drawn
182: Logically Collective
184: Input Parameters:
185: + lg - the line graph context.
186: - colors - the colors
188: Level: intermediate
190: .seealso: `PetscDrawLG`, `PetscDrawLGCreate()`
191: @*/
192: PetscErrorCode PetscDrawLGSetColors(PetscDrawLG lg, const int colors[])
193: {
197: PetscFree(lg->colors);
198: PetscMalloc1(lg->dim, &lg->colors);
199: PetscArraycpy(lg->colors, colors, lg->dim);
200: return 0;
201: }
203: /*@C
204: PetscDrawLGSetLegend - sets the names of each curve plotted
206: Logically Collective
208: Input Parameters:
209: + lg - the line graph context.
210: - names - the names for each curve
212: Level: intermediate
214: Note:
215: Call `PetscDrawLGGetAxis()` and then change properties of the `PetscDrawAxis` for detailed control of the plot
217: .seealso: `PetscDrawLGGetAxis()`, `PetscDrawAxis`, `PetscDrawAxisSetColors()`, `PetscDrawAxisSetLabels()`, `PetscDrawAxisSetHoldLimits()`
218: @*/
219: PetscErrorCode PetscDrawLGSetLegend(PetscDrawLG lg, const char *const *names)
220: {
221: PetscInt i;
226: if (lg->legend) {
227: for (i = 0; i < lg->dim; i++) PetscFree(lg->legend[i]);
228: PetscFree(lg->legend);
229: }
230: if (names) {
231: PetscMalloc1(lg->dim, &lg->legend);
232: for (i = 0; i < lg->dim; i++) PetscStrallocpy(names[i], &lg->legend[i]);
233: }
234: return 0;
235: }
237: /*@
238: PetscDrawLGGetDimension - Get the number of curves that are to be drawn.
240: Not Collective
242: Input Parameter:
243: . lg - the line graph context.
245: Output Parameter:
246: . dim - the number of curves.
248: Level: intermediate
250: .seealso: `PetscDrawLGC`, `PetscDrawLGCreate()`, `PetscDrawLGSetDimension()`
251: @*/
252: PetscErrorCode PetscDrawLGGetDimension(PetscDrawLG lg, PetscInt *dim)
253: {
256: *dim = lg->dim;
257: return 0;
258: }
260: /*@
261: PetscDrawLGSetDimension - Change the number of curves that are to be drawn.
263: Logically Collective
265: Input Parameters:
266: + lg - the line graph context.
267: - dim - the number of curves.
269: Level: intermediate
271: .seealso: `PetscDrawLGCreate()`, `PetscDrawLGGetDimension()`
272: @*/
273: PetscErrorCode PetscDrawLGSetDimension(PetscDrawLG lg, PetscInt dim)
274: {
275: PetscInt i;
279: if (lg->dim == dim) return 0;
281: PetscFree2(lg->x, lg->y);
282: if (lg->legend) {
283: for (i = 0; i < lg->dim; i++) PetscFree(lg->legend[i]);
284: PetscFree(lg->legend);
285: }
286: PetscFree(lg->colors);
287: lg->dim = dim;
288: 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: return 0;
291: }
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.
298: Logically Collective
300: Input Parameters:
301: + xlg - the line graph context
302: - x_min,x_max,y_min,y_max - the limits
304: Level: intermediate
306: .seealso: `PetscDrawLGCreate()`, `PetscDrawLG`, `PetscDrawAxis`
307: @*/
308: PetscErrorCode PetscDrawLGSetLimits(PetscDrawLG lg, PetscReal x_min, PetscReal x_max, PetscReal y_min, PetscReal y_max)
309: {
312: (lg)->xmin = x_min;
313: (lg)->xmax = x_max;
314: (lg)->ymin = y_min;
315: (lg)->ymax = y_max;
316: return 0;
317: }
319: /*@
320: PetscDrawLGReset - Clears line graph to allow for reuse with new data.
322: Logically Collective
324: Input Parameter:
325: . lg - the line graph context.
327: Level: intermediate
329: .seealso: `PetscDrawLG`, `PetscDrawLGCreate()`
330: @*/
331: PetscErrorCode PetscDrawLGReset(PetscDrawLG lg)
332: {
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: return 0;
341: }
343: /*@
344: PetscDrawLGDestroy - Frees all space taken up by line graph data structure.
346: Collective
348: Input Parameter:
349: . lg - the line graph context
351: Level: intermediate
353: .seealso: `PetscDrawLG`, `PetscDrawLGCreate()`
354: @*/
355: PetscErrorCode PetscDrawLGDestroy(PetscDrawLG *lg)
356: {
357: PetscInt i;
359: if (!*lg) return 0;
361: if (--((PetscObject)(*lg))->refct > 0) {
362: *lg = NULL;
363: return 0;
364: }
366: if ((*lg)->legend) {
367: for (i = 0; i < (*lg)->dim; i++) PetscFree((*lg)->legend[i]);
368: PetscFree((*lg)->legend);
369: }
370: PetscFree((*lg)->colors);
371: PetscFree2((*lg)->x, (*lg)->y);
372: PetscDrawAxisDestroy(&(*lg)->axis);
373: PetscDrawDestroy(&(*lg)->win);
374: PetscHeaderDestroy(lg);
375: return 0;
376: }
377: /*@
378: PetscDrawLGSetUseMarkers - Causes the line graph object to draw a marker for each data-point.
380: Logically Collective
382: Input Parameters:
383: + lg - the linegraph context
384: - flg - should mark each data point
386: Options Database Key:
387: . -lg_use_markers <true,false> - true means it draws a marker for each point
389: Level: intermediate
391: .seealso: `PetscDrawLG`, `PetscDrawLGCreate()`
392: @*/
393: PetscErrorCode PetscDrawLGSetUseMarkers(PetscDrawLG lg, PetscBool flg)
394: {
397: lg->use_markers = flg;
398: return 0;
399: }
401: /*@
402: PetscDrawLGDraw - Redraws a line graph.
404: Collective
406: Input Parameter:
407: . lg - the line graph context
409: Level: intermediate
411: .seealso: `PetscDrawLG`, `PetscDrawSPDraw()`, `PetscDrawLGSPDraw()`, `PetscDrawLGReset()`
412: @*/
413: PetscErrorCode PetscDrawLGDraw(PetscDrawLG lg)
414: {
415: PetscReal xmin, xmax, ymin, ymax;
416: PetscMPIInt rank;
417: PetscDraw draw;
418: PetscBool isnull;
421: PetscDrawIsNull(lg->win, &isnull);
422: if (isnull) return 0;
423: MPI_Comm_rank(PetscObjectComm((PetscObject)lg), &rank);
425: draw = lg->win;
426: PetscDrawCheckResizedWindow(draw);
427: PetscDrawClear(draw);
429: xmin = lg->xmin;
430: xmax = lg->xmax;
431: ymin = lg->ymin;
432: ymax = lg->ymax;
433: PetscDrawAxisSetLimits(lg->axis, xmin, xmax, ymin, ymax);
434: PetscDrawAxisDraw(lg->axis);
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: 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) 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: PetscDrawAxisGetLimits(lg->axis, &xl, &xr, &yl, &yr);
453: PetscDrawStringGetSize(draw, &tw, &th);
454: for (i = 0; i < dim; i++) {
455: 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: PetscDrawLine(draw, xl, yl, xr, yl, PETSC_DRAW_BLACK);
468: PetscDrawLine(draw, xr, yl, xr, yr, PETSC_DRAW_BLACK);
469: PetscDrawLine(draw, xr, yr, xl, yr, PETSC_DRAW_BLACK);
470: 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: PetscDrawLine(draw, xl + 1 * tw, yr - (i + 1) * th, xl + 5 * tw, yr - (i + 1) * th, cl);
474: PetscDrawString(draw, xl + 6 * tw, yr - (i + 1.5) * th, PETSC_DRAW_BLACK, lg->legend[i]);
475: }
476: }
477: PetscDrawCollectiveEnd(draw);
479: PetscDrawFlush(draw);
480: PetscDrawPause(draw);
481: return 0;
482: }
484: /*@
485: PetscDrawLGSave - Saves a drawn image
487: Collective
489: Input Parameter:
490: . lg - The line graph context
492: Level: intermediate
494: .seealso: `PetscDrawLG`, `PetscDrawSave()`, `PetscDrawLGCreate()`, `PetscDrawLGGetDraw()`, `PetscDrawSetSave()`, `PetscDrawSave()`
495: @*/
496: PetscErrorCode PetscDrawLGSave(PetscDrawLG lg)
497: {
499: PetscDrawSave(lg->win);
500: return 0;
501: }
503: /*@
504: PetscDrawLGView - Prints a line graph.
506: Collective
508: Input Parameter:
509: . lg - the line graph context
511: Level: beginner
513: .seealso: `PetscDrawLG`, `PetscDrawLGCreate()`
514: @*/
515: PetscErrorCode PetscDrawLGView(PetscDrawLG lg, PetscViewer viewer)
516: {
517: PetscReal xmin = lg->xmin, xmax = lg->xmax, ymin = lg->ymin, ymax = lg->ymax;
518: PetscInt i, j, dim = lg->dim, nopts = lg->nopts;
522: if (nopts < 1) return 0;
523: if (xmin > xmax || ymin > ymax) return 0;
525: if (!viewer) PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)lg), &viewer);
526: PetscObjectPrintClassNamePrefixType((PetscObject)lg, viewer);
527: for (i = 0; i < dim; i++) {
528: PetscViewerASCIIPrintf(viewer, "Line %" PetscInt_FMT ">\n", i);
529: for (j = 0; j < nopts; j++) PetscViewerASCIIPrintf(viewer, " X: %g Y: %g\n", (double)lg->x[j * dim + i], (double)lg->y[j * dim + i]);
530: }
531: return 0;
532: }
534: /*@C
535: PetscDrawLGSetOptionsPrefix - Sets the prefix used for searching for all
536: `PetscDrawLG` options in the database.
538: Logically Collective
540: Input Parameters:
541: + lg - the line graph context
542: - prefix - the prefix to prepend to all option names
544: Level: advanced
546: .seealso: `PetscDrawLG`, `PetscDrawLGSetFromOptions()`, `PetscDrawLGCreate()`
547: @*/
548: PetscErrorCode PetscDrawLGSetOptionsPrefix(PetscDrawLG lg, const char prefix[])
549: {
551: PetscObjectSetOptionsPrefix((PetscObject)lg, prefix);
552: return 0;
553: }
555: /*@
556: PetscDrawLGSetFromOptions - Sets options related to the line graph object
558: Collective
560: Input Parameters:
561: . lg - the line graph context
563: Options Database Key:
564: . -lg_use_markers <true,false> - true means it draws a marker for each point
566: Level: intermediate
568: .seealso: `PetscDrawLG`, `PetscDrawLGDestroy()`, `PetscDrawLGCreate()`
569: @*/
570: PetscErrorCode PetscDrawLGSetFromOptions(PetscDrawLG lg)
571: {
572: PetscBool usemarkers, set;
573: PetscDrawMarkerType markertype;
577: PetscDrawGetMarkerType(lg->win, &markertype);
578: PetscOptionsGetEnum(((PetscObject)lg)->options, ((PetscObject)lg)->prefix, "-lg_marker_type", PetscDrawMarkerTypes, (PetscEnum *)&markertype, &set);
579: if (set) {
580: PetscDrawLGSetUseMarkers(lg, PETSC_TRUE);
581: PetscDrawSetMarkerType(lg->win, markertype);
582: }
583: usemarkers = lg->use_markers;
584: PetscOptionsGetBool(((PetscObject)lg)->options, ((PetscObject)lg)->prefix, "-lg_use_markers", &usemarkers, &set);
585: if (set) PetscDrawLGSetUseMarkers(lg, usemarkers);
586: return 0;
587: }