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 <petscdraw.h>
  8: #include <petsc/private/drawimpl.h>

 10: PetscClassId PETSC_DRAWSP_CLASSID = 0;

 12: /*@C
 13:   PetscDrawSPCreate - Creates a scatter plot data structure.

 15:   Collective

 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

 21:   Output Parameters:
 22: . drawsp - the scatter plot context

 24:   Level: intermediate

 26:   Notes:
 27:   Add points to the plot with `PetscDrawSPAddPoint()` or `PetscDrawSPAddPoints()`; the new points are not displayed until `PetscDrawSPDraw()` is called.

 29:   `PetscDrawSPReset()` removes all the points that have been added

 31:   `PetscDrawSPSetDimension()` determines how many point curves are being plotted.

 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.

 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;

 42:   PetscFunctionBegin;

 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      = 1.e20;
 54:   sp->ymin      = 1.e20;
 55:   sp->zmin      = 1.e20;
 56:   sp->xmax      = -1.e20;
 57:   sp->ymax      = -1.e20;
 58:   sp->zmax      = -1.e20;
 59:   sp->colorized = PETSC_FALSE;
 60:   sp->loc       = 0;

 62:   PetscCall(PetscDrawSPSetDimension(sp, dim));
 63:   PetscCall(PetscDrawAxisCreate(draw, &sp->axis));

 65:   *drawsp = sp;
 66:   PetscFunctionReturn(PETSC_SUCCESS);
 67: }

 69: /*@
 70:   PetscDrawSPSetDimension - Change the number of points that are added at each  `PetscDrawSPAddPoint()`

 72:   Not collective

 74:   Input Parameters:
 75: + sp  - the scatter plot context.
 76: - dim - the number of point curves on this process

 78:   Level: intermediate

 80: .seealso: `PetscDrawSP`, `PetscDrawSPCreate()`, `PetscDrawSPAddPoint()`, `PetscDrawSPAddPoints()`
 81: @*/
 82: PetscErrorCode PetscDrawSPSetDimension(PetscDrawSP sp, int dim)
 83: {
 84:   PetscFunctionBegin;
 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: }

 94: /*@
 95:   PetscDrawSPGetDimension - Get the number of sets of points that are to be drawn at each `PetscDrawSPAddPoint()`

 97:   Not collective

 99:   Input Parameters:
100: . sp  - the scatter plot context.

102:   Output Parameter:
103: . dim - the number of point curves on this process

105:   Level: intermediate

107: .seealso: `PetscDrawSP`, `PetscDrawSPCreate()`, `PetscDrawSPAddPoint()`, `PetscDrawSPAddPoints()`
108: @*/
109: PetscErrorCode PetscDrawSPGetDimension(PetscDrawSP sp, int *dim)
110: {
111:   PetscFunctionBegin;
114:   *dim = sp->dim;
115:   PetscFunctionReturn(PETSC_SUCCESS);
116: }

118: /*@
119:   PetscDrawSPReset - Clears scatter plot to allow for reuse with new data.

121:   Not collective

123:   Input Parameter:
124: . sp - the scatter plot context.

126:   Level: intermediate

128: .seealso: `PetscDrawSP`, `PetscDrawSPCreate()`, `PetscDrawSPAddPoint()`, `PetscDrawSPAddPoints()`, `PetscDrawSPDraw()`
129: @*/
130: PetscErrorCode PetscDrawSPReset(PetscDrawSP sp)
131: {
132:   PetscFunctionBegin;
134:   sp->xmin  = 1.e20;
135:   sp->ymin  = 1.e20;
136:   sp->zmin  = 1.e20;
137:   sp->xmax  = -1.e20;
138:   sp->ymax  = -1.e20;
139:   sp->zmax  = -1.e20;
140:   sp->loc   = 0;
141:   sp->nopts = 0;
142:   PetscFunctionReturn(PETSC_SUCCESS);
143: }

145: /*@
146:   PetscDrawSPDestroy - Frees all space taken up by scatter plot data structure.

148:   Collective

150:   Input Parameter:
151: . sp - the scatter plot context

153:   Level: intermediate

155: .seealso: `PetscDrawSPCreate()`, `PetscDrawSP`, `PetscDrawSPReset()`
156: @*/
157: PetscErrorCode PetscDrawSPDestroy(PetscDrawSP *sp)
158: {
159:   PetscFunctionBegin;
160:   if (!*sp) PetscFunctionReturn(PETSC_SUCCESS);
162:   if (--((PetscObject)(*sp))->refct > 0) {
163:     *sp = NULL;
164:     PetscFunctionReturn(PETSC_SUCCESS);
165:   }

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

174: /*@
175:   PetscDrawSPAddPoint - Adds another point to each of the scatter plot point curves.

177:   Not collective

179:   Input Parameters:
180: + sp - the scatter plot data structure
181: - x, y - two arrays of length dim containing the new x and y coordinate values for each of the point curves. Here  dim is the number of point curves passed to PetscDrawSPCreate()

183:   Level: intermediate

185:   Note:
186:   The new points will not be displayed until a call to `PetscDrawSPDraw()` is made

188: .seealso: `PetscDrawSPAddPoints()`, `PetscDrawSP`, `PetscDrawSPCreate()`, `PetscDrawSPReset()`, `PetscDrawSPDraw()`, `PetscDrawSPAddPointColorized()`
189: @*/
190: PetscErrorCode PetscDrawSPAddPoint(PetscDrawSP sp, PetscReal *x, PetscReal *y)
191: {
192:   PetscInt i;

194:   PetscFunctionBegin;

197:   if (sp->loc + sp->dim >= sp->len) { /* allocate more space */
198:     PetscReal *tmpx, *tmpy, *tmpz;
199:     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));
200:     PetscCall(PetscArraycpy(tmpx, sp->x, sp->len));
201:     PetscCall(PetscArraycpy(tmpy, sp->y, sp->len));
202:     PetscCall(PetscArraycpy(tmpz, sp->z, sp->len));
203:     PetscCall(PetscFree3(sp->x, sp->y, sp->z));
204:     sp->x = tmpx;
205:     sp->y = tmpy;
206:     sp->z = tmpz;
207:     sp->len += sp->dim * PETSC_DRAW_SP_CHUNK_SIZE;
208:   }
209:   for (i = 0; i < sp->dim; ++i) {
210:     if (x[i] > sp->xmax) sp->xmax = x[i];
211:     if (x[i] < sp->xmin) sp->xmin = x[i];
212:     if (y[i] > sp->ymax) sp->ymax = y[i];
213:     if (y[i] < sp->ymin) sp->ymin = y[i];

215:     sp->x[sp->loc]   = x[i];
216:     sp->y[sp->loc++] = y[i];
217:   }
218:   ++sp->nopts;
219:   PetscFunctionReturn(PETSC_SUCCESS);
220: }

222: /*@C
223:   PetscDrawSPAddPoints - Adds several points to each of the scatter plot point curves.

225:   Not collective

227:   Input Parameters:
228: + sp - the scatter plot context
229: . xx,yy - points to two arrays of pointers that point to arrays containing the new x and y points for each curve.
230: - n - number of points being added, each represents a subarray of length dim where dim is the value from `PetscDrawSPGetDimension()`

232:   Level: intermediate

234:   Note:
235:   The new points will not be displayed until a call to `PetscDrawSPDraw()` is made

237: .seealso: `PetscDrawSPAddPoint()`, `PetscDrawSP`, `PetscDrawSPCreate()`, `PetscDrawSPReset()`, `PetscDrawSPDraw()`, `PetscDrawSPAddPointColorized()`
238: @*/
239: PetscErrorCode PetscDrawSPAddPoints(PetscDrawSP sp, int n, PetscReal **xx, PetscReal **yy)
240: {
241:   PetscInt   i, j, k;
242:   PetscReal *x, *y;

244:   PetscFunctionBegin;

247:   if (sp->loc + n * sp->dim >= sp->len) { /* allocate more space */
248:     PetscReal *tmpx, *tmpy, *tmpz;
249:     PetscInt   chunk = PETSC_DRAW_SP_CHUNK_SIZE;
250:     if (n > chunk) chunk = n;
251:     PetscCall(PetscMalloc3(sp->len + sp->dim * chunk, &tmpx, sp->len + sp->dim * chunk, &tmpy, sp->len + sp->dim * chunk, &tmpz));
252:     PetscCall(PetscArraycpy(tmpx, sp->x, sp->len));
253:     PetscCall(PetscArraycpy(tmpy, sp->y, sp->len));
254:     PetscCall(PetscArraycpy(tmpz, sp->z, sp->len));
255:     PetscCall(PetscFree3(sp->x, sp->y, sp->z));

257:     sp->x = tmpx;
258:     sp->y = tmpy;
259:     sp->z = tmpz;
260:     sp->len += sp->dim * PETSC_DRAW_SP_CHUNK_SIZE;
261:   }
262:   for (j = 0; j < sp->dim; ++j) {
263:     x = xx[j];
264:     y = yy[j];
265:     k = sp->loc + j;
266:     for (i = 0; i < n; ++i) {
267:       if (x[i] > sp->xmax) sp->xmax = x[i];
268:       if (x[i] < sp->xmin) sp->xmin = x[i];
269:       if (y[i] > sp->ymax) sp->ymax = y[i];
270:       if (y[i] < sp->ymin) sp->ymin = y[i];

272:       sp->x[k] = x[i];
273:       sp->y[k] = y[i];
274:       k += sp->dim;
275:     }
276:   }
277:   sp->loc += n * sp->dim;
278:   sp->nopts += n;
279:   PetscFunctionReturn(PETSC_SUCCESS);
280: }

282: /*@
283:   PetscDrawSPAddPointColorized - Adds another point to each of the scatter plots as well as a numeric value to be used to colorize the scatter point.

285:   Not collective

287:   Input Parameters:
288: + sp - the scatter plot data structure
289: . x, y - two arrays of length dim containing the new x and y coordinate values for each of the point curves. Here  dim is the number of point curves passed to `PetscDrawSPCreate()`
290: - z - array of length dim containing the numeric values that will be mapped to [0,255] and used for scatter point colors.

292:   Level: intermediate

294:   Note:
295:   The new points will not be displayed until a call to `PetscDrawSPDraw()` is made

297: .seealso: `PetscDrawSPAddPoints()`, `PetscDrawSP`, `PetscDrawSPCreate()`, `PetscDrawSPReset()`, `PetscDrawSPDraw()`, `PetscDrawSPAddPoint()`
298: @*/
299: PetscErrorCode PetscDrawSPAddPointColorized(PetscDrawSP sp, PetscReal *x, PetscReal *y, PetscReal *z)
300: {
301:   PetscInt i;

303:   PetscFunctionBegin;
305:   sp->colorized = PETSC_TRUE;
306:   if (sp->loc + sp->dim >= sp->len) { /* allocate more space */
307:     PetscReal *tmpx, *tmpy, *tmpz;
308:     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));
309:     PetscCall(PetscArraycpy(tmpx, sp->x, sp->len));
310:     PetscCall(PetscArraycpy(tmpy, sp->y, sp->len));
311:     PetscCall(PetscArraycpy(tmpz, sp->z, sp->len));
312:     PetscCall(PetscFree3(sp->x, sp->y, sp->z));
313:     sp->x = tmpx;
314:     sp->y = tmpy;
315:     sp->z = tmpz;
316:     sp->len += sp->dim * PETSC_DRAW_SP_CHUNK_SIZE;
317:   }
318:   for (i = 0; i < sp->dim; ++i) {
319:     if (x[i] > sp->xmax) sp->xmax = x[i];
320:     if (x[i] < sp->xmin) sp->xmin = x[i];
321:     if (y[i] > sp->ymax) sp->ymax = y[i];
322:     if (y[i] < sp->ymin) sp->ymin = y[i];
323:     if (z[i] < sp->zmin) sp->zmin = z[i];
324:     if (z[i] > sp->zmax) sp->zmax = z[i];
325:     // if (z[i] > sp->zmax && z[i] < 5.) sp->zmax = z[i];

327:     sp->x[sp->loc]   = x[i];
328:     sp->y[sp->loc]   = y[i];
329:     sp->z[sp->loc++] = z[i];
330:   }
331:   ++sp->nopts;
332:   PetscFunctionReturn(PETSC_SUCCESS);
333: }

335: /*@
336:   PetscDrawSPDraw - Redraws a scatter plot.

338:   Collective

340:   Input Parameters:
341: + sp - the scatter plot context
342: - clear - clear the window before drawing the new plot

344:   Level: intermediate

346: .seealso: `PetscDrawLGDraw()`, `PetscDrawLGSPDraw()`, `PetscDrawSP`, `PetscDrawSPCreate()`, `PetscDrawSPReset()`, `PetscDrawSPAddPoint()`, `PetscDrawSPAddPoints()`
347: @*/
348: PetscErrorCode PetscDrawSPDraw(PetscDrawSP sp, PetscBool clear)
349: {
350:   PetscDraw   draw;
351:   PetscBool   isnull;
352:   PetscMPIInt rank, size;

354:   PetscFunctionBegin;
356:   draw = sp->win;
357:   PetscCall(PetscDrawIsNull(draw, &isnull));
358:   if (isnull) PetscFunctionReturn(PETSC_SUCCESS);
359:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)sp), &rank));
360:   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)sp), &size));

362:   if (clear) {
363:     PetscCall(PetscDrawCheckResizedWindow(draw));
364:     PetscCall(PetscDrawClear(draw));
365:   }
366:   {
367:     PetscReal lower[2] = {sp->xmin, sp->ymin}, glower[2];
368:     PetscReal upper[2] = {sp->xmax, sp->ymax}, gupper[2];
369:     PetscCall(MPIU_Allreduce(lower, glower, 2, MPIU_REAL, MPIU_MIN, PetscObjectComm((PetscObject)sp)));
370:     PetscCall(MPIU_Allreduce(upper, gupper, 2, MPIU_REAL, MPIU_MAX, PetscObjectComm((PetscObject)sp)));
371:     PetscCall(PetscDrawAxisSetLimits(sp->axis, glower[0], gupper[0], glower[1], gupper[1]));
372:     PetscCall(PetscDrawAxisDraw(sp->axis));
373:   }

375:   PetscDrawCollectiveBegin(draw);
376:   {
377:     const int dim = sp->dim, nopts = sp->nopts;

379:     for (int i = 0; i < dim; ++i) {
380:       for (int p = 0; p < nopts; ++p) {
381:         PetscInt color = sp->colorized ? PetscDrawRealToColor(sp->z[p * dim], sp->zmin, sp->zmax) : (size > 1 ? PetscDrawRealToColor(rank, 0, size - 1) : PETSC_DRAW_RED);

383:         PetscCall(PetscDrawPoint(draw, sp->x[p * dim + i], sp->y[p * dim + i], color));
384:       }
385:     }
386:   }
387:   PetscDrawCollectiveEnd(draw);

389:   PetscCall(PetscDrawFlush(draw));
390:   PetscCall(PetscDrawPause(draw));
391:   PetscFunctionReturn(PETSC_SUCCESS);
392: }

394: /*@
395:   PetscDrawSPSave - Saves a drawn image

397:   Collective

399:   Input Parameter:
400: . sp - the scatter plot context

402:   Level: intermediate

404: .seealso: `PetscDrawSPSave()`, `PetscDrawSPCreate()`, `PetscDrawSPGetDraw()`, `PetscDrawSetSave()`, `PetscDrawSave()`
405: @*/
406: PetscErrorCode PetscDrawSPSave(PetscDrawSP sp)
407: {
408:   PetscFunctionBegin;
410:   PetscCall(PetscDrawSave(sp->win));
411:   PetscFunctionReturn(PETSC_SUCCESS);
412: }

414: /*@
415:   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.

417:   Not collective

419:   Input Parameters:
420: + xsp - the line graph context
421: - x_min,x_max,y_min,y_max - the limits

423:   Level: intermediate

425: .seealso: `PetscDrawSP`, `PetscDrawAxis`, `PetscDrawSPCreate()`, `PetscDrawSPDraw()`, `PetscDrawSPAddPoint()`, `PetscDrawSPAddPoints()`, `PetscDrawSPGetAxis()`
426: @*/
427: PetscErrorCode PetscDrawSPSetLimits(PetscDrawSP sp, PetscReal x_min, PetscReal x_max, PetscReal y_min, PetscReal y_max)
428: {
429:   PetscFunctionBegin;
431:   sp->xmin = x_min;
432:   sp->xmax = x_max;
433:   sp->ymin = y_min;
434:   sp->ymax = y_max;
435:   PetscFunctionReturn(PETSC_SUCCESS);
436: }

438: /*@
439:   PetscDrawSPGetAxis - Gets the axis context associated with a scatter plot

441:   Not Collective

443:   Input Parameter:
444: . sp - the scatter plot context

446:   Output Parameter:
447: . axis - the axis context

449:   Note:
450:   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.

452:   Level: intermediate

454: .seealso: `PetscDrawSP`, `PetscDrawSPCreate()`, `PetscDrawSPDraw()`, `PetscDrawSPAddPoint()`, `PetscDrawSPAddPoints()`, `PetscDrawAxis`, `PetscDrawAxisCreate()`
455: @*/
456: PetscErrorCode PetscDrawSPGetAxis(PetscDrawSP sp, PetscDrawAxis *axis)
457: {
458:   PetscFunctionBegin;
461:   *axis = sp->axis;
462:   PetscFunctionReturn(PETSC_SUCCESS);
463: }

465: /*@
466:   PetscDrawSPGetDraw - Gets the draw context associated with a scatter plot

468:   Not Collective

470:   Input Parameter:
471: . sp - the scatter plot context

473:   Output Parameter:
474: . draw - the draw context

476:   Level: intermediate

478: .seealso: `PetscDrawSP`, `PetscDrawSPCreate()`, `PetscDrawSPDraw()`, `PetscDraw`
479: @*/
480: PetscErrorCode PetscDrawSPGetDraw(PetscDrawSP sp, PetscDraw *draw)
481: {
482:   PetscFunctionBegin;
485:   *draw = sp->win;
486:   PetscFunctionReturn(PETSC_SUCCESS);
487: }