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: }