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