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 Parameter:
 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 Parameter:
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 - array of pointers that point to arrays containing the new x coordinates for each curve.
230: . yy - array of pointers that point to arrays containing the new y points for each curve.
231: - n - number of points being added, each represents a subarray of length dim where dim is the value from `PetscDrawSPGetDimension()`

233:   Level: intermediate

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

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

245:   PetscFunctionBegin;

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

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

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

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

286:   Not Collective

288:   Input Parameters:
289: + sp - the scatter plot data structure
290: . x - array of length dim containing the new x coordinate values for each of the point curves.
291: . y - array of length dim containing the new y coordinate values for each of the point curves.
292: - z - array of length dim containing the numeric values that will be mapped to [0,255] and used for scatter point colors.

294:   Level: intermediate

296:   Note:
297:   The dimensions of the arrays is the number of point curves passed to `PetscDrawSPCreate()`.
298:   The new points will not be displayed until a call to `PetscDrawSPDraw()` is made

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

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

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

338: /*@
339:   PetscDrawSPDraw - Redraws a scatter plot.

341:   Collective

343:   Input Parameters:
344: + sp - the scatter plot context
345: - clear - clear the window before drawing the new plot

347:   Level: intermediate

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

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

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

378:   PetscDrawCollectiveBegin(draw);
379:   {
380:     const int dim = sp->dim, nopts = sp->nopts;

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

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

392:   PetscCall(PetscDrawFlush(draw));
393:   PetscCall(PetscDrawPause(draw));
394:   PetscFunctionReturn(PETSC_SUCCESS);
395: }

397: /*@
398:   PetscDrawSPSave - Saves a drawn image

400:   Collective

402:   Input Parameter:
403: . sp - the scatter plot context

405:   Level: intermediate

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

417: /*@
418:   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.

420:   Not Collective

422:   Input Parameters:
423: + xsp - the line graph context
424: . x_min - the horizontal lower limit
425: . x_max - the horizontal upper limit
426: . y_min - the vertical lower limit
427: - y_max - the vertical upper limit

429:   Level: intermediate

431: .seealso: `PetscDrawSP`, `PetscDrawAxis`, `PetscDrawSPCreate()`, `PetscDrawSPDraw()`, `PetscDrawSPAddPoint()`, `PetscDrawSPAddPoints()`, `PetscDrawSPGetAxis()`
432: @*/
433: PetscErrorCode PetscDrawSPSetLimits(PetscDrawSP sp, PetscReal x_min, PetscReal x_max, PetscReal y_min, PetscReal y_max)
434: {
435:   PetscFunctionBegin;
437:   sp->xmin = x_min;
438:   sp->xmax = x_max;
439:   sp->ymin = y_min;
440:   sp->ymax = y_max;
441:   PetscFunctionReturn(PETSC_SUCCESS);
442: }

444: /*@
445:   PetscDrawSPGetAxis - Gets the axis context associated with a scatter plot

447:   Not Collective

449:   Input Parameter:
450: . sp - the scatter plot context

452:   Output Parameter:
453: . axis - the axis context

455:   Level: intermediate

457:   Note:
458:   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.

460: .seealso: `PetscDrawSP`, `PetscDrawSPCreate()`, `PetscDrawSPDraw()`, `PetscDrawSPAddPoint()`, `PetscDrawSPAddPoints()`, `PetscDrawAxis`, `PetscDrawAxisCreate()`
461: @*/
462: PetscErrorCode PetscDrawSPGetAxis(PetscDrawSP sp, PetscDrawAxis *axis)
463: {
464:   PetscFunctionBegin;
467:   *axis = sp->axis;
468:   PetscFunctionReturn(PETSC_SUCCESS);
469: }

471: /*@
472:   PetscDrawSPGetDraw - Gets the draw context associated with a scatter plot

474:   Not Collective

476:   Input Parameter:
477: . sp - the scatter plot context

479:   Output Parameter:
480: . draw - the draw context

482:   Level: intermediate

484: .seealso: `PetscDrawSP`, `PetscDrawSPCreate()`, `PetscDrawSPDraw()`, `PetscDraw`
485: @*/
486: PetscErrorCode PetscDrawSPGetDraw(PetscDrawSP sp, PetscDraw *draw)
487: {
488:   PetscFunctionBegin;
491:   *draw = sp->win;
492:   PetscFunctionReturn(PETSC_SUCCESS);
493: }