xref: /petsc/src/sys/classes/draw/utils/dscatter.c (revision a69119a591a03a9d906b29c0a4e9802e4d7c9795)
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 */
6 
7 #include <petscdraw.h>              /*I "petscdraw.h" I*/
8 #include <petsc/private/drawimpl.h> /*I "petscsys.h" I*/
9 
10 PetscClassId PETSC_DRAWSP_CLASSID = 0;
11 
12 /*@C
13   PetscDrawSPCreate - Creates a scatter plot data structure.
14 
15   Collective on PetscDraw
16 
17   Input Parameters:
18 + win - the window where the graph will be made.
19 - dim - the number of sets of points which will be drawn
20 
21   Output Parameters:
22 . drawsp - the scatter plot context
23 
24   Level: intermediate
25 
26   Notes:
27   Add points to the plot with PetscDrawSPAddPoint() or PetscDrawSPAddPoints(); the new points are not displayed until PetscDrawSPDraw() is called.
28 
29   PetscDrawSPReset() removes all the points that have been added
30 
31   The MPI communicator that owns the PetscDraw owns this PetscDrawSP, and each processc can add points. All MPI processes in the communicator must call PetscDrawSPDraw() to display the updated graph.
32 
33 .seealso: `PetscDrawLGCreate()`, `PetscDrawLG`, `PetscDrawBarCreate()`, `PetscDrawBar`, `PetscDrawHGCreate()`, `PetscDrawHG`, `PetscDrawSPDestroy()`, `PetscDraw`, `PetscDrawSP`, `PetscDrawSPSetDimension()`, `PetscDrawSPReset()`,
34           `PetscDrawSPAddPoint()`, `PetscDrawSPAddPoints()`, `PetscDrawSPDraw()`, `PetscDrawSPSave()`, `PetscDrawSPSetLimits()`, `PetscDrawSPGetAxis()`, `PetscDrawAxis`, `PetscDrawSPGetDraw()`
35 @*/
36 PetscErrorCode PetscDrawSPCreate(PetscDraw draw, int dim, PetscDrawSP *drawsp) {
37   PetscDrawSP sp;
38 
39   PetscFunctionBegin;
40   PetscValidHeaderSpecific(draw, PETSC_DRAW_CLASSID, 1);
41   PetscValidPointer(drawsp, 3);
42 
43   PetscCall(PetscHeaderCreate(sp, PETSC_DRAWSP_CLASSID, "DrawSP", "Scatter Plot", "Draw", PetscObjectComm((PetscObject)draw), PetscDrawSPDestroy, NULL));
44   PetscCall(PetscLogObjectParent((PetscObject)draw, (PetscObject)sp));
45   PetscCall(PetscObjectReference((PetscObject)draw));
46   sp->win       = draw;
47   sp->view      = NULL;
48   sp->destroy   = NULL;
49   sp->nopts     = 0;
50   sp->dim       = -1;
51   sp->xmin      = 1.e20;
52   sp->ymin      = 1.e20;
53   sp->zmin      = 1.e20;
54   sp->xmax      = -1.e20;
55   sp->ymax      = -1.e20;
56   sp->zmax      = -1.e20;
57   sp->colorized = PETSC_FALSE;
58   sp->loc       = 0;
59 
60   PetscCall(PetscDrawSPSetDimension(sp, dim));
61   PetscCall(PetscDrawAxisCreate(draw, &sp->axis));
62   PetscCall(PetscLogObjectParent((PetscObject)sp, (PetscObject)sp->axis));
63 
64   *drawsp = sp;
65   PetscFunctionReturn(0);
66 }
67 
68 /*@
69   PetscDrawSPSetDimension - Change the number of sets of points that are to be drawn.
70 
71   Not collective
72 
73   Input Parameters:
74 + sp  - the line graph context.
75 - dim - the number of curves on this process
76 
77   Level: intermediate
78 
79 .seealso: `PetscDrawSP`, `PetscDrawSPCreate()`, `PetscDrawSPAddPoint()`, `PetscDrawSPAddPoints()`
80 @*/
81 PetscErrorCode PetscDrawSPSetDimension(PetscDrawSP sp, int dim) {
82   PetscFunctionBegin;
83   PetscValidHeaderSpecific(sp, PETSC_DRAWSP_CLASSID, 1);
84   if (sp->dim == dim) PetscFunctionReturn(0);
85   sp->dim = dim;
86   PetscCall(PetscFree3(sp->x, sp->y, sp->z));
87   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));
88   PetscCall(PetscLogObjectMemory((PetscObject)sp, 3 * dim * PETSC_DRAW_SP_CHUNK_SIZE * sizeof(PetscReal)));
89   sp->len = dim * PETSC_DRAW_SP_CHUNK_SIZE;
90   PetscFunctionReturn(0);
91 }
92 
93 /*@
94   PetscDrawSPGetDimension - Get the number of sets of points that are to be drawn.
95 
96   Not collective
97 
98   Input Parameters:
99 . sp  - the line graph context.
100 
101   Output Parameter:
102 . dim - the number of curves on this process
103 
104   Level: intermediate
105 
106 .seealso: `PetscDrawSP`, `PetscDrawSPCreate()`, `PetscDrawSPAddPoint()`, `PetscDrawSPAddPoints()`
107 @*/
108 PetscErrorCode PetscDrawSPGetDimension(PetscDrawSP sp, int *dim) {
109   PetscFunctionBegin;
110   PetscValidHeaderSpecific(sp, PETSC_DRAWSP_CLASSID, 1);
111   PetscValidPointer(dim, 2);
112   *dim = sp->dim;
113   PetscFunctionReturn(0);
114 }
115 
116 /*@
117   PetscDrawSPReset - Clears line graph to allow for reuse with new data.
118 
119   Not collective
120 
121   Input Parameter:
122 . sp - the line graph context.
123 
124   Level: intermediate
125 
126 .seealso: `PetscDrawSP`, `PetscDrawSPCreate()`, `PetscDrawSPAddPoint()`, `PetscDrawSPAddPoints()`, `PetscDrawSPDraw()`
127 @*/
128 PetscErrorCode PetscDrawSPReset(PetscDrawSP sp) {
129   PetscFunctionBegin;
130   PetscValidHeaderSpecific(sp, PETSC_DRAWSP_CLASSID, 1);
131   sp->xmin  = 1.e20;
132   sp->ymin  = 1.e20;
133   sp->zmin  = 1.e20;
134   sp->xmax  = -1.e20;
135   sp->ymax  = -1.e20;
136   sp->zmax  = -1.e20;
137   sp->loc   = 0;
138   sp->nopts = 0;
139   PetscFunctionReturn(0);
140 }
141 
142 /*@
143   PetscDrawSPDestroy - Frees all space taken up by scatter plot data structure.
144 
145   Collective on PetscDrawSP
146 
147   Input Parameter:
148 . sp - the line graph context
149 
150   Level: intermediate
151 
152 .seealso: `PetscDrawSPCreate()`, `PetscDrawSP`, `PetscDrawSPReset()`
153 @*/
154 PetscErrorCode PetscDrawSPDestroy(PetscDrawSP *sp) {
155   PetscFunctionBegin;
156   if (!*sp) PetscFunctionReturn(0);
157   PetscValidHeaderSpecific(*sp, PETSC_DRAWSP_CLASSID, 1);
158   if (--((PetscObject)(*sp))->refct > 0) {
159     *sp = NULL;
160     PetscFunctionReturn(0);
161   }
162 
163   PetscCall(PetscFree3((*sp)->x, (*sp)->y, (*sp)->z));
164   PetscCall(PetscDrawAxisDestroy(&(*sp)->axis));
165   PetscCall(PetscDrawDestroy(&(*sp)->win));
166   PetscCall(PetscHeaderDestroy(sp));
167   PetscFunctionReturn(0);
168 }
169 
170 /*@
171   PetscDrawSPAddPoint - Adds another point to each of the scatter plots.
172 
173   Not collective
174 
175   Input Parameters:
176 + sp - the scatter plot data structure
177 - x, y - two arrays of length dim containing the new x and y coordinate values for each of the curves. Here  dim is the number of curves passed to PetscDrawSPCreate()
178 
179   Level: intermediate
180 
181   Notes:
182   The new points will not be displayed until a call to PetscDrawSPDraw() is made
183 
184 .seealso: `PetscDrawSPAddPoints()`, `PetscDrawSP`, `PetscDrawSPCreate()`, `PetscDrawSPReset()`, `PetscDrawSPDraw()`, `PetscDrawSPAddPointColorized()`
185 @*/
186 PetscErrorCode PetscDrawSPAddPoint(PetscDrawSP sp, PetscReal *x, PetscReal *y) {
187   PetscInt i;
188 
189   PetscFunctionBegin;
190   PetscValidHeaderSpecific(sp, PETSC_DRAWSP_CLASSID, 1);
191 
192   if (sp->loc + sp->dim >= sp->len) { /* allocate more space */
193     PetscReal *tmpx, *tmpy, *tmpz;
194     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));
195     PetscCall(PetscLogObjectMemory((PetscObject)sp, 3 * sp->dim * PETSC_DRAW_SP_CHUNK_SIZE * sizeof(PetscReal)));
196     PetscCall(PetscArraycpy(tmpx, sp->x, sp->len));
197     PetscCall(PetscArraycpy(tmpy, sp->y, sp->len));
198     PetscCall(PetscArraycpy(tmpz, sp->z, sp->len));
199     PetscCall(PetscFree3(sp->x, sp->y, sp->z));
200     sp->x = tmpx;
201     sp->y = tmpy;
202     sp->z = tmpz;
203     sp->len += sp->dim * PETSC_DRAW_SP_CHUNK_SIZE;
204   }
205   for (i = 0; i < sp->dim; ++i) {
206     if (x[i] > sp->xmax) sp->xmax = x[i];
207     if (x[i] < sp->xmin) sp->xmin = x[i];
208     if (y[i] > sp->ymax) sp->ymax = y[i];
209     if (y[i] < sp->ymin) sp->ymin = y[i];
210 
211     sp->x[sp->loc]   = x[i];
212     sp->y[sp->loc++] = y[i];
213   }
214   ++sp->nopts;
215   PetscFunctionReturn(0);
216 }
217 
218 /*@C
219   PetscDrawSPAddPoints - Adds several points to each of the scatter plots.
220 
221   Not collective
222 
223   Input Parameters:
224 + sp - the LineGraph data structure
225 . xx,yy - points to two arrays of pointers that point to arrays containing the new x and y points for each curve.
226 - n - number of points being added
227 
228   Level: intermediate
229 
230   Notes:
231   The new points will not be displayed until a call to PetscDrawSPDraw() is made
232 
233 .seealso: `PetscDrawSPAddPoint()`, `PetscDrawSP`, `PetscDrawSPCreate()`, `PetscDrawSPReset()`, `PetscDrawSPDraw()`, `PetscDrawSPAddPointColorized()`
234 @*/
235 PetscErrorCode PetscDrawSPAddPoints(PetscDrawSP sp, int n, PetscReal **xx, PetscReal **yy) {
236   PetscInt   i, j, k;
237   PetscReal *x, *y;
238 
239   PetscFunctionBegin;
240   PetscValidHeaderSpecific(sp, PETSC_DRAWSP_CLASSID, 1);
241 
242   if (sp->loc + n * sp->dim >= sp->len) { /* allocate more space */
243     PetscReal *tmpx, *tmpy, *tmpz;
244     PetscInt   chunk = PETSC_DRAW_SP_CHUNK_SIZE;
245     if (n > chunk) chunk = n;
246     PetscCall(PetscMalloc3(sp->len + sp->dim * chunk, &tmpx, sp->len + sp->dim * chunk, &tmpy, sp->len + sp->dim * chunk, &tmpz));
247     PetscCall(PetscLogObjectMemory((PetscObject)sp, 3 * sp->dim * PETSC_DRAW_SP_CHUNK_SIZE * sizeof(PetscReal)));
248     PetscCall(PetscArraycpy(tmpx, sp->x, sp->len));
249     PetscCall(PetscArraycpy(tmpy, sp->y, sp->len));
250     PetscCall(PetscArraycpy(tmpz, sp->z, sp->len));
251     PetscCall(PetscFree3(sp->x, sp->y, sp->z));
252 
253     sp->x = tmpx;
254     sp->y = tmpy;
255     sp->z = tmpz;
256     sp->len += sp->dim * PETSC_DRAW_SP_CHUNK_SIZE;
257   }
258   for (j = 0; j < sp->dim; ++j) {
259     x = xx[j];
260     y = yy[j];
261     k = sp->loc + j;
262     for (i = 0; i < n; ++i) {
263       if (x[i] > sp->xmax) sp->xmax = x[i];
264       if (x[i] < sp->xmin) sp->xmin = x[i];
265       if (y[i] > sp->ymax) sp->ymax = y[i];
266       if (y[i] < sp->ymin) sp->ymin = y[i];
267 
268       sp->x[k] = x[i];
269       sp->y[k] = y[i];
270       k += sp->dim;
271     }
272   }
273   sp->loc += n * sp->dim;
274   sp->nopts += n;
275   PetscFunctionReturn(0);
276 }
277 
278 /*@
279   PetscDrawSPAddPointColorized - Adds another point to each of the scatter plots as well as a numeric value to be used to colorize the scatter point.
280 
281   Not collective
282 
283   Input Parameters:
284 + sp - the scatter plot data structure
285 . x, y - two arrays of length dim containing the new x and y coordinate values for each of the curves. Here  dim is the number of curves passed to PetscDrawSPCreate()
286 - z - array of length dim containing the numeric values that will be mapped to [0,255] and used for scatter point colors.
287 
288   Level: intermediate
289 
290   Notes:
291   The new points will not be displayed until a call to PetscDrawSPDraw() is made
292 
293 .seealso: `PetscDrawSPAddPoints()`, `PetscDrawSP`, `PetscDrawSPCreate()`, `PetscDrawSPReset()`, `PetscDrawSPDraw()`, `PetscDrawSPAddPoint()`
294 @*/
295 PetscErrorCode PetscDrawSPAddPointColorized(PetscDrawSP sp, PetscReal *x, PetscReal *y, PetscReal *z) {
296   PetscInt i;
297 
298   PetscFunctionBegin;
299   PetscValidHeaderSpecific(sp, PETSC_DRAWSP_CLASSID, 1);
300   sp->colorized = PETSC_TRUE;
301   if (sp->loc + sp->dim >= sp->len) { /* allocate more space */
302     PetscReal *tmpx, *tmpy, *tmpz;
303     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));
304     PetscCall(PetscLogObjectMemory((PetscObject)sp, 3 * sp->dim * PETSC_DRAW_SP_CHUNK_SIZE * sizeof(PetscReal)));
305     PetscCall(PetscArraycpy(tmpx, sp->x, sp->len));
306     PetscCall(PetscArraycpy(tmpy, sp->y, sp->len));
307     PetscCall(PetscArraycpy(tmpz, sp->z, sp->len));
308     PetscCall(PetscFree3(sp->x, sp->y, sp->z));
309     sp->x = tmpx;
310     sp->y = tmpy;
311     sp->z = tmpz;
312     sp->len += sp->dim * PETSC_DRAW_SP_CHUNK_SIZE;
313   }
314   for (i = 0; i < sp->dim; ++i) {
315     if (x[i] > sp->xmax) sp->xmax = x[i];
316     if (x[i] < sp->xmin) sp->xmin = x[i];
317     if (y[i] > sp->ymax) sp->ymax = y[i];
318     if (y[i] < sp->ymin) sp->ymin = y[i];
319     if (z[i] < sp->zmin) sp->zmin = z[i];
320     if (z[i] > sp->zmax) sp->zmax = z[i];
321     // if (z[i] > sp->zmax && z[i] < 5.) sp->zmax = z[i];
322 
323     sp->x[sp->loc]   = x[i];
324     sp->y[sp->loc]   = y[i];
325     sp->z[sp->loc++] = z[i];
326   }
327   ++sp->nopts;
328   PetscFunctionReturn(0);
329 }
330 
331 /*@
332   PetscDrawSPDraw - Redraws a scatter plot.
333 
334   Collective on PetscDrawSP
335 
336   Input Parameters:
337 + sp - the line graph context
338 - clear - clear the window before drawing the new plot
339 
340   Level: intermediate
341 
342 .seealso: `PetscDrawLGDraw()`, `PetscDrawLGSPDraw()`, `PetscDrawSP`, `PetscDrawSPCreate()`, `PetscDrawSPReset()`, `PetscDrawSPAddPoint()`, `PetscDrawSPAddPoints()`
343 @*/
344 PetscErrorCode PetscDrawSPDraw(PetscDrawSP sp, PetscBool clear) {
345   PetscDraw   draw;
346   PetscBool   isnull;
347   PetscMPIInt rank, size;
348 
349   PetscFunctionBegin;
350   PetscValidHeaderSpecific(sp, PETSC_DRAWSP_CLASSID, 1);
351   draw = sp->win;
352   PetscCall(PetscDrawIsNull(draw, &isnull));
353   if (isnull) PetscFunctionReturn(0);
354   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)sp), &rank));
355   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)sp), &size));
356 
357   if (clear) {
358     PetscCall(PetscDrawCheckResizedWindow(draw));
359     PetscCall(PetscDrawClear(draw));
360   }
361   {
362     PetscReal lower[2] = {sp->xmin, sp->ymin}, glower[2];
363     PetscReal upper[2] = {sp->xmax, sp->ymax}, gupper[2];
364     PetscCall(MPIU_Allreduce(lower, glower, 2, MPIU_REAL, MPIU_MIN, PetscObjectComm((PetscObject)sp)));
365     PetscCall(MPIU_Allreduce(upper, gupper, 2, MPIU_REAL, MPIU_MAX, PetscObjectComm((PetscObject)sp)));
366     PetscCall(PetscDrawAxisSetLimits(sp->axis, glower[0], gupper[0], glower[1], gupper[1]));
367     PetscCall(PetscDrawAxisDraw(sp->axis));
368   }
369 
370   PetscDrawCollectiveBegin(draw);
371   {
372     const int dim = sp->dim, nopts = sp->nopts;
373 
374     for (int i = 0; i < dim; ++i) {
375       for (int p = 0; p < nopts; ++p) {
376         PetscInt color = sp->colorized ? PetscDrawRealToColor(sp->z[p * dim], sp->zmin, sp->zmax) : (size > 1 ? PetscDrawRealToColor(rank, 0, size - 1) : PETSC_DRAW_RED);
377 
378         PetscCall(PetscDrawPoint(draw, sp->x[p * dim + i], sp->y[p * dim + i], color));
379       }
380     }
381   }
382   PetscDrawCollectiveEnd(draw);
383 
384   PetscCall(PetscDrawFlush(draw));
385   PetscCall(PetscDrawPause(draw));
386   PetscFunctionReturn(0);
387 }
388 
389 /*@
390   PetscDrawSPSave - Saves a drawn image
391 
392   Collective on PetscDrawSP
393 
394   Input Parameter:
395 . sp - the scatter plot context
396 
397   Level: intermediate
398 
399 .seealso: `PetscDrawSPCreate()`, `PetscDrawSPGetDraw()`, `PetscDrawSetSave()`, `PetscDrawSave()`
400 @*/
401 PetscErrorCode PetscDrawSPSave(PetscDrawSP sp) {
402   PetscFunctionBegin;
403   PetscValidHeaderSpecific(sp, PETSC_DRAWSP_CLASSID, 1);
404   PetscCall(PetscDrawSave(sp->win));
405   PetscFunctionReturn(0);
406 }
407 
408 /*@
409   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.
410 
411   Not collective
412 
413   Input Parameters:
414 + xsp - the line graph context
415 - x_min,x_max,y_min,y_max - the limits
416 
417   Level: intermediate
418 
419 .seealso: `PetscDrawSP`, `PetscDrawSPCreate()`, `PetscDrawSPDraw()`, `PetscDrawSPAddPoint()`, `PetscDrawSPAddPoints()`, `PetscDrawSPGetAxis()`
420 @*/
421 PetscErrorCode PetscDrawSPSetLimits(PetscDrawSP sp, PetscReal x_min, PetscReal x_max, PetscReal y_min, PetscReal y_max) {
422   PetscFunctionBegin;
423   PetscValidHeaderSpecific(sp, PETSC_DRAWSP_CLASSID, 1);
424   sp->xmin = x_min;
425   sp->xmax = x_max;
426   sp->ymin = y_min;
427   sp->ymax = y_max;
428   PetscFunctionReturn(0);
429 }
430 
431 /*@
432   PetscDrawSPGetAxis - Gets the axis context associated with a line graph.
433 
434   Not Collective
435 
436   Input Parameter:
437 . sp - the line graph context
438 
439   Output Parameter:
440 . axis - the axis context
441 
442   Note:
443   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.
444 
445   Level: intermediate
446 
447 .seealso: `PetscDrawSP`, `PetscDrawSPCreate()`, `PetscDrawSPDraw()`, `PetscDrawSPAddPoint()`, `PetscDrawSPAddPoints()`, `PetscDrawAxis`, `PetscDrawAxisCreate()`
448 @*/
449 PetscErrorCode PetscDrawSPGetAxis(PetscDrawSP sp, PetscDrawAxis *axis) {
450   PetscFunctionBegin;
451   PetscValidHeaderSpecific(sp, PETSC_DRAWSP_CLASSID, 1);
452   PetscValidPointer(axis, 2);
453   *axis = sp->axis;
454   PetscFunctionReturn(0);
455 }
456 
457 /*@
458   PetscDrawSPGetDraw - Gets the draw context associated with a line graph.
459 
460   Not Collective
461 
462   Input Parameter:
463 . sp - the line graph context
464 
465   Output Parameter:
466 . draw - the draw context
467 
468   Level: intermediate
469 
470 .seealso: `PetscDrawSP`, `PetscDrawSPCreate()`, `PetscDrawSPDraw()`, `PetscDraw`
471 @*/
472 PetscErrorCode PetscDrawSPGetDraw(PetscDrawSP sp, PetscDraw *draw) {
473   PetscFunctionBegin;
474   PetscValidHeaderSpecific(sp, PETSC_DRAWSP_CLASSID, 1);
475   PetscValidPointer(draw, 2);
476   *draw = sp->win;
477   PetscFunctionReturn(0);
478 }
479