Actual source code: dscatter.c
1: /*
2: Contains the data structure for drawing scatter plots
3: graphs in a window with an axis. This is intended for scatter
4: plots that change dynamically.
5: */
7: #include <petsc/private/drawimpl.h>
9: PetscClassId PETSC_DRAWSP_CLASSID = 0;
11: /*@
12: PetscDrawSPCreate - Creates a scatter plot data structure.
14: Collective
16: Input Parameters:
17: + draw - the window where the graph will be made.
18: - dim - the number of sets of points which will be drawn
20: Output Parameter:
21: . drawsp - the scatter plot context
23: Level: intermediate
25: Notes:
26: Add points to the plot with `PetscDrawSPAddPoint()` or `PetscDrawSPAddPoints()`; the new points are not displayed until `PetscDrawSPDraw()` is called.
28: `PetscDrawSPReset()` removes all the points that have been added
30: `PetscDrawSPSetDimension()` determines how many point curves are being plotted.
32: The MPI communicator that owns the `PetscDraw` owns this `PetscDrawSP`, and each process can add points. All MPI ranks in the communicator must call `PetscDrawSPDraw()` to display the updated graph.
34: .seealso: `PetscDrawLGCreate()`, `PetscDrawLG`, `PetscDrawBarCreate()`, `PetscDrawBar`, `PetscDrawHGCreate()`, `PetscDrawHG`, `PetscDrawSPDestroy()`, `PetscDraw`, `PetscDrawSP`, `PetscDrawSPSetDimension()`, `PetscDrawSPReset()`,
35: `PetscDrawSPAddPoint()`, `PetscDrawSPAddPoints()`, `PetscDrawSPDraw()`, `PetscDrawSPSave()`, `PetscDrawSPSetLimits()`, `PetscDrawSPGetAxis()`, `PetscDrawAxis`, `PetscDrawSPGetDraw()`
36: @*/
37: PetscErrorCode PetscDrawSPCreate(PetscDraw draw, int dim, PetscDrawSP *drawsp)
38: {
39: PetscDrawSP sp;
41: PetscFunctionBegin;
43: PetscAssertPointer(drawsp, 3);
45: PetscCall(PetscHeaderCreate(sp, PETSC_DRAWSP_CLASSID, "DrawSP", "Scatter Plot", "Draw", PetscObjectComm((PetscObject)draw), PetscDrawSPDestroy, NULL));
46: PetscCall(PetscObjectReference((PetscObject)draw));
47: sp->win = draw;
48: sp->view = NULL;
49: sp->destroy = NULL;
50: sp->nopts = 0;
51: sp->dim = -1;
52: sp->xmin = (PetscReal)1.e20;
53: sp->ymin = (PetscReal)1.e20;
54: sp->zmin = (PetscReal)1.e20;
55: sp->xmax = (PetscReal)-1.e20;
56: sp->ymax = (PetscReal)-1.e20;
57: sp->zmax = (PetscReal)-1.e20;
58: sp->colorized = PETSC_FALSE;
59: sp->loc = 0;
61: PetscCall(PetscDrawSPSetDimension(sp, dim));
62: PetscCall(PetscDrawAxisCreate(draw, &sp->axis));
64: *drawsp = sp;
65: PetscFunctionReturn(PETSC_SUCCESS);
66: }
68: /*@
69: PetscDrawSPSetDimension - Change the number of points that are added at each `PetscDrawSPAddPoint()`
71: Not Collective
73: Input Parameters:
74: + sp - the scatter plot context.
75: - dim - the number of point curves on this process
77: Level: intermediate
79: .seealso: `PetscDrawSP`, `PetscDrawSPCreate()`, `PetscDrawSPAddPoint()`, `PetscDrawSPAddPoints()`
80: @*/
81: PetscErrorCode PetscDrawSPSetDimension(PetscDrawSP sp, int dim)
82: {
83: PetscFunctionBegin;
85: if (sp->dim == dim) PetscFunctionReturn(PETSC_SUCCESS);
86: sp->dim = dim;
87: PetscCall(PetscFree3(sp->x, sp->y, sp->z));
88: PetscCall(PetscMalloc3(dim * PETSC_DRAW_SP_CHUNK_SIZE, &sp->x, dim * PETSC_DRAW_SP_CHUNK_SIZE, &sp->y, dim * PETSC_DRAW_SP_CHUNK_SIZE, &sp->z));
89: sp->len = dim * PETSC_DRAW_SP_CHUNK_SIZE;
90: PetscFunctionReturn(PETSC_SUCCESS);
91: }
93: /*@
94: PetscDrawSPGetDimension - Get the number of sets of points that are to be drawn at each `PetscDrawSPAddPoint()`
96: Not Collective
98: Input Parameter:
99: . sp - the scatter plot context.
101: Output Parameter:
102: . dim - the number of point curves on this process
104: Level: intermediate
106: .seealso: `PetscDrawSP`, `PetscDrawSPCreate()`, `PetscDrawSPAddPoint()`, `PetscDrawSPAddPoints()`
107: @*/
108: PetscErrorCode PetscDrawSPGetDimension(PetscDrawSP sp, int *dim)
109: {
110: PetscFunctionBegin;
112: PetscAssertPointer(dim, 2);
113: *dim = sp->dim;
114: PetscFunctionReturn(PETSC_SUCCESS);
115: }
117: /*@
118: PetscDrawSPReset - Clears scatter plot to allow for reuse with new data.
120: Not Collective
122: Input Parameter:
123: . sp - the scatter plot context.
125: Level: intermediate
127: .seealso: `PetscDrawSP`, `PetscDrawSPCreate()`, `PetscDrawSPAddPoint()`, `PetscDrawSPAddPoints()`, `PetscDrawSPDraw()`
128: @*/
129: PetscErrorCode PetscDrawSPReset(PetscDrawSP sp)
130: {
131: PetscFunctionBegin;
133: sp->xmin = (PetscReal)1.e20;
134: sp->ymin = (PetscReal)1.e20;
135: sp->zmin = (PetscReal)1.e20;
136: sp->xmax = (PetscReal)-1.e20;
137: sp->ymax = (PetscReal)-1.e20;
138: sp->zmax = (PetscReal)-1.e20;
139: sp->loc = 0;
140: sp->nopts = 0;
141: PetscFunctionReturn(PETSC_SUCCESS);
142: }
144: /*@
145: PetscDrawSPDestroy - Frees all space taken up by scatter plot data structure.
147: Collective
149: Input Parameter:
150: . sp - the scatter plot context
152: Level: intermediate
154: .seealso: `PetscDrawSPCreate()`, `PetscDrawSP`, `PetscDrawSPReset()`
155: @*/
156: PetscErrorCode PetscDrawSPDestroy(PetscDrawSP *sp)
157: {
158: PetscFunctionBegin;
159: if (!*sp) PetscFunctionReturn(PETSC_SUCCESS);
161: if (--((PetscObject)*sp)->refct > 0) {
162: *sp = NULL;
163: PetscFunctionReturn(PETSC_SUCCESS);
164: }
166: PetscCall(PetscFree3((*sp)->x, (*sp)->y, (*sp)->z));
167: PetscCall(PetscDrawAxisDestroy(&(*sp)->axis));
168: PetscCall(PetscDrawDestroy(&(*sp)->win));
169: PetscCall(PetscHeaderDestroy(sp));
170: PetscFunctionReturn(PETSC_SUCCESS);
171: }
173: /*@
174: PetscDrawSPAddPoint - Adds another point to each of the scatter plot point curves.
176: Not Collective
178: Input Parameters:
179: + sp - the scatter plot data structure
180: . x - the x coordinate values (of length dim) for the points of the curve
181: - y - the y coordinate values (of length dim) for the points of the curve
183: Level: intermediate
185: Note:
186: Here dim is the number of point curves passed to `PetscDrawSPCreate()`. The new points will
187: not be displayed until a call to `PetscDrawSPDraw()` is made.
189: .seealso: `PetscDrawSPAddPoints()`, `PetscDrawSP`, `PetscDrawSPCreate()`, `PetscDrawSPReset()`, `PetscDrawSPDraw()`, `PetscDrawSPAddPointColorized()`
190: @*/
191: PetscErrorCode PetscDrawSPAddPoint(PetscDrawSP sp, PetscReal *x, PetscReal *y)
192: {
193: PetscInt i;
195: PetscFunctionBegin;
198: if (sp->loc + sp->dim >= sp->len) { /* allocate more space */
199: PetscReal *tmpx, *tmpy, *tmpz;
200: PetscCall(PetscMalloc3(sp->len + sp->dim * PETSC_DRAW_SP_CHUNK_SIZE, &tmpx, sp->len + sp->dim * PETSC_DRAW_SP_CHUNK_SIZE, &tmpy, sp->len + sp->dim * PETSC_DRAW_SP_CHUNK_SIZE, &tmpz));
201: PetscCall(PetscArraycpy(tmpx, sp->x, sp->len));
202: PetscCall(PetscArraycpy(tmpy, sp->y, sp->len));
203: PetscCall(PetscArraycpy(tmpz, sp->z, sp->len));
204: PetscCall(PetscFree3(sp->x, sp->y, sp->z));
205: sp->x = tmpx;
206: sp->y = tmpy;
207: sp->z = tmpz;
208: sp->len += sp->dim * PETSC_DRAW_SP_CHUNK_SIZE;
209: }
210: for (i = 0; i < sp->dim; ++i) {
211: if (x[i] > sp->xmax) sp->xmax = x[i];
212: if (x[i] < sp->xmin) sp->xmin = x[i];
213: if (y[i] > sp->ymax) sp->ymax = y[i];
214: if (y[i] < sp->ymin) sp->ymin = y[i];
216: sp->x[sp->loc] = x[i];
217: sp->y[sp->loc++] = y[i];
218: }
219: ++sp->nopts;
220: PetscFunctionReturn(PETSC_SUCCESS);
221: }
223: /*@
224: PetscDrawSPAddPoints - Adds several points to each of the scatter plot point curves.
226: Not Collective
228: Input Parameters:
229: + sp - the scatter plot context
230: . xx - array of pointers that point to arrays containing the new x coordinates for each curve.
231: . yy - array of pointers that point to arrays containing the new y points for each curve.
232: - n - number of points being added, each represents a subarray of length dim where dim is the value from `PetscDrawSPGetDimension()`
234: Level: intermediate
236: Note:
237: The new points will not be displayed until a call to `PetscDrawSPDraw()` is made
239: .seealso: `PetscDrawSPAddPoint()`, `PetscDrawSP`, `PetscDrawSPCreate()`, `PetscDrawSPReset()`, `PetscDrawSPDraw()`, `PetscDrawSPAddPointColorized()`
240: @*/
241: PetscErrorCode PetscDrawSPAddPoints(PetscDrawSP sp, int n, PetscReal *xx[], PetscReal *yy[])
242: {
243: PetscInt i, j, k;
244: PetscReal *x, *y;
246: PetscFunctionBegin;
249: if (sp->loc + n * sp->dim >= sp->len) { /* allocate more space */
250: PetscReal *tmpx, *tmpy, *tmpz;
251: PetscInt chunk = PETSC_DRAW_SP_CHUNK_SIZE;
252: if (n > chunk) chunk = n;
253: PetscCall(PetscMalloc3(sp->len + sp->dim * chunk, &tmpx, sp->len + sp->dim * chunk, &tmpy, sp->len + sp->dim * chunk, &tmpz));
254: PetscCall(PetscArraycpy(tmpx, sp->x, sp->len));
255: PetscCall(PetscArraycpy(tmpy, sp->y, sp->len));
256: PetscCall(PetscArraycpy(tmpz, sp->z, sp->len));
257: PetscCall(PetscFree3(sp->x, sp->y, sp->z));
259: sp->x = tmpx;
260: sp->y = tmpy;
261: sp->z = tmpz;
262: sp->len += sp->dim * PETSC_DRAW_SP_CHUNK_SIZE;
263: }
264: for (j = 0; j < sp->dim; ++j) {
265: x = xx[j];
266: y = yy[j];
267: k = sp->loc + j;
268: for (i = 0; i < n; ++i) {
269: if (x[i] > sp->xmax) sp->xmax = x[i];
270: if (x[i] < sp->xmin) sp->xmin = x[i];
271: if (y[i] > sp->ymax) sp->ymax = y[i];
272: if (y[i] < sp->ymin) sp->ymin = y[i];
274: sp->x[k] = x[i];
275: sp->y[k] = y[i];
276: k += sp->dim;
277: }
278: }
279: sp->loc += n * sp->dim;
280: sp->nopts += n;
281: PetscFunctionReturn(PETSC_SUCCESS);
282: }
284: /*@
285: PetscDrawSPAddPointColorized - Adds another point to each of the scatter plots as well as a numeric value to be used to colorize the scatter point.
287: Not Collective
289: Input Parameters:
290: + sp - the scatter plot data structure
291: . x - array of length dim containing the new x coordinate values for each of the point curves.
292: . y - array of length dim containing the new y coordinate values for each of the point curves.
293: - z - array of length dim containing the numeric values that will be mapped to [0,255] and used for scatter point colors.
295: Level: intermediate
297: Note:
298: The dimensions of the arrays is the number of point curves passed to `PetscDrawSPCreate()`.
299: The new points will not be displayed until a call to `PetscDrawSPDraw()` is made
301: .seealso: `PetscDrawSPAddPoints()`, `PetscDrawSP`, `PetscDrawSPCreate()`, `PetscDrawSPReset()`, `PetscDrawSPDraw()`, `PetscDrawSPAddPoint()`
302: @*/
303: PetscErrorCode PetscDrawSPAddPointColorized(PetscDrawSP sp, PetscReal *x, PetscReal *y, PetscReal *z)
304: {
305: PetscFunctionBegin;
307: sp->colorized = PETSC_TRUE;
308: if (sp->loc + sp->dim >= sp->len) { /* allocate more space */
309: PetscReal *tmpx, *tmpy, *tmpz;
310: PetscCall(PetscMalloc3(sp->len + sp->dim * PETSC_DRAW_SP_CHUNK_SIZE, &tmpx, sp->len + sp->dim * PETSC_DRAW_SP_CHUNK_SIZE, &tmpy, sp->len + sp->dim * PETSC_DRAW_SP_CHUNK_SIZE, &tmpz));
311: PetscCall(PetscArraycpy(tmpx, sp->x, sp->len));
312: PetscCall(PetscArraycpy(tmpy, sp->y, sp->len));
313: PetscCall(PetscArraycpy(tmpz, sp->z, sp->len));
314: PetscCall(PetscFree3(sp->x, sp->y, sp->z));
315: sp->x = tmpx;
316: sp->y = tmpy;
317: sp->z = tmpz;
318: sp->len += sp->dim * PETSC_DRAW_SP_CHUNK_SIZE;
319: }
320: for (PetscInt i = 0; i < sp->dim; ++i) {
321: if (x[i] > sp->xmax) sp->xmax = x[i];
322: if (x[i] < sp->xmin) sp->xmin = x[i];
323: if (y[i] > sp->ymax) sp->ymax = y[i];
324: if (y[i] < sp->ymin) sp->ymin = y[i];
325: if (z[i] < sp->zmin) sp->zmin = z[i];
326: if (z[i] > sp->zmax) sp->zmax = z[i];
327: // if (z[i] > sp->zmax && z[i] < 5.) sp->zmax = z[i];
329: sp->x[sp->loc] = x[i];
330: sp->y[sp->loc] = y[i];
331: sp->z[sp->loc++] = z[i];
332: }
333: ++sp->nopts;
334: PetscFunctionReturn(PETSC_SUCCESS);
335: }
337: /*@
338: PetscDrawSPDraw - Redraws a scatter plot.
340: Collective
342: Input Parameters:
343: + sp - the scatter plot context
344: - clear - clear the window before drawing the new plot
346: Level: intermediate
348: .seealso: `PetscDrawLGDraw()`, `PetscDrawLGSPDraw()`, `PetscDrawSP`, `PetscDrawSPCreate()`, `PetscDrawSPReset()`, `PetscDrawSPAddPoint()`, `PetscDrawSPAddPoints()`
349: @*/
350: PetscErrorCode PetscDrawSPDraw(PetscDrawSP sp, PetscBool clear)
351: {
352: PetscDraw draw;
353: PetscBool isnull;
354: PetscMPIInt rank, size;
356: PetscFunctionBegin;
358: draw = sp->win;
359: PetscCall(PetscDrawIsNull(draw, &isnull));
360: if (isnull) PetscFunctionReturn(PETSC_SUCCESS);
361: PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)sp), &rank));
362: PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)sp), &size));
364: if (clear) {
365: PetscCall(PetscDrawCheckResizedWindow(draw));
366: PetscCall(PetscDrawClear(draw));
367: }
368: {
369: PetscReal glower[2] = {sp->xmin, sp->ymin};
370: PetscReal gupper[2] = {sp->xmax, sp->ymax};
371: PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, glower, 2, MPIU_REAL, MPIU_MIN, PetscObjectComm((PetscObject)sp)));
372: PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, gupper, 2, MPIU_REAL, MPIU_MAX, PetscObjectComm((PetscObject)sp)));
373: PetscCall(PetscDrawAxisSetLimits(sp->axis, glower[0], gupper[0], glower[1], gupper[1]));
374: PetscCall(PetscDrawAxisDraw(sp->axis));
375: }
377: PetscDrawCollectiveBegin(draw);
378: {
379: const int dim = sp->dim, nopts = sp->nopts;
381: for (int i = 0; i < dim; ++i) {
382: for (int p = 0; p < nopts; ++p) {
383: int color = sp->colorized ? PetscDrawRealToColor(sp->z[p * dim], sp->zmin, sp->zmax) : (size > 1 ? PetscDrawRealToColor(rank, 0, size - 1) : PETSC_DRAW_RED);
385: PetscCall(PetscDrawPoint(draw, sp->x[p * dim + i], sp->y[p * dim + i], color));
386: }
387: }
388: }
389: PetscDrawCollectiveEnd(draw);
391: PetscCall(PetscDrawFlush(draw));
392: PetscCall(PetscDrawPause(draw));
393: PetscFunctionReturn(PETSC_SUCCESS);
394: }
396: /*@
397: PetscDrawSPSave - Saves a drawn image
399: Collective
401: Input Parameter:
402: . sp - the scatter plot context
404: Level: intermediate
406: .seealso: `PetscDrawSPCreate()`, `PetscDrawSPGetDraw()`, `PetscDrawSetSave()`, `PetscDrawSave()`
407: @*/
408: PetscErrorCode PetscDrawSPSave(PetscDrawSP sp)
409: {
410: PetscFunctionBegin;
412: PetscCall(PetscDrawSave(sp->win));
413: PetscFunctionReturn(PETSC_SUCCESS);
414: }
416: /*@
417: PetscDrawSPSetLimits - Sets the axis limits for a scatter plot. If more points are added after this call, the limits will be adjusted to include those additional points.
419: Not Collective
421: Input Parameters:
422: + sp - the line graph context
423: . x_min - the horizontal lower limit
424: . x_max - the horizontal upper limit
425: . y_min - the vertical lower limit
426: - y_max - the vertical upper limit
428: Level: intermediate
430: .seealso: `PetscDrawSP`, `PetscDrawAxis`, `PetscDrawSPCreate()`, `PetscDrawSPDraw()`, `PetscDrawSPAddPoint()`, `PetscDrawSPAddPoints()`, `PetscDrawSPGetAxis()`
431: @*/
432: PetscErrorCode PetscDrawSPSetLimits(PetscDrawSP sp, PetscReal x_min, PetscReal x_max, PetscReal y_min, PetscReal y_max)
433: {
434: PetscFunctionBegin;
436: sp->xmin = x_min;
437: sp->xmax = x_max;
438: sp->ymin = y_min;
439: sp->ymax = y_max;
440: PetscFunctionReturn(PETSC_SUCCESS);
441: }
443: /*@
444: PetscDrawSPGetAxis - Gets the axis context associated with a scatter plot
446: Not Collective
448: Input Parameter:
449: . sp - the scatter plot context
451: Output Parameter:
452: . axis - the axis context
454: Level: intermediate
456: Note:
457: This is useful if one wants to change some axis property, such as labels, color, etc. The axis context should not be destroyed by the application code.
459: .seealso: `PetscDrawSP`, `PetscDrawSPCreate()`, `PetscDrawSPDraw()`, `PetscDrawSPAddPoint()`, `PetscDrawSPAddPoints()`, `PetscDrawAxis`, `PetscDrawAxisCreate()`
460: @*/
461: PetscErrorCode PetscDrawSPGetAxis(PetscDrawSP sp, PetscDrawAxis *axis)
462: {
463: PetscFunctionBegin;
465: PetscAssertPointer(axis, 2);
466: *axis = sp->axis;
467: PetscFunctionReturn(PETSC_SUCCESS);
468: }
470: /*@
471: PetscDrawSPGetDraw - Gets the draw context associated with a scatter plot
473: Not Collective
475: Input Parameter:
476: . sp - the scatter plot context
478: Output Parameter:
479: . draw - the draw context
481: Level: intermediate
483: .seealso: `PetscDrawSP`, `PetscDrawSPCreate()`, `PetscDrawSPDraw()`, `PetscDraw`
484: @*/
485: PetscErrorCode PetscDrawSPGetDraw(PetscDrawSP sp, PetscDraw *draw)
486: {
487: PetscFunctionBegin;
489: PetscAssertPointer(draw, 2);
490: *draw = sp->win;
491: PetscFunctionReturn(PETSC_SUCCESS);
492: }