Date: 2025-03-28T21:11:10+00:00

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: /*@
     13:   PetscDrawSPCreate - Creates a scatter plot data structure.

     15:   Collective

     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

     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;
     44:   PetscAssertPointer(drawsp, 3);

     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;

     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;
    113:   PetscAssertPointer(dim, 2);
    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  = (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: }

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

    184:   Level: intermediate

    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.

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

    196:   PetscFunctionBegin;

    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];

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

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

    227:   Not Collective

    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()`

    235:   Level: intermediate

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

    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;

    247:   PetscFunctionBegin;

    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));

    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];

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

    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.

    288:   Not Collective

    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.

    296:   Level: intermediate

    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

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

    308:   PetscFunctionBegin;
    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];

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

    340: /*@
    341:   PetscDrawSPDraw - Redraws a scatter plot.

    343:   Collective

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

    349:   Level: intermediate

    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;

    359:   PetscFunctionBegin;
    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));

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

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

    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);

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

    394:   PetscCall(PetscDrawFlush(draw));
    395:   PetscCall(PetscDrawPause(draw));
    396:   PetscFunctionReturn(PETSC_SUCCESS);
    397: }

    399: /*@
    400:   PetscDrawSPSave - Saves a drawn image

    402:   Collective

    404:   Input Parameter:
    405: . sp - the scatter plot context

    407:   Level: intermediate

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

    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.

    422:   Not Collective

    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

    431:   Level: intermediate

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

    446: /*@
    447:   PetscDrawSPGetAxis - Gets the axis context associated with a scatter plot

    449:   Not Collective

    451:   Input Parameter:
    452: . sp - the scatter plot context

    454:   Output Parameter:
    455: . axis - the axis context

    457:   Level: intermediate

    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.

    462: .seealso: `PetscDrawSP`, `PetscDrawSPCreate()`, `PetscDrawSPDraw()`, `PetscDrawSPAddPoint()`, `PetscDrawSPAddPoints()`, `PetscDrawAxis`, `PetscDrawAxisCreate()`
    463: @*/
    464: PetscErrorCode PetscDrawSPGetAxis(PetscDrawSP sp, PetscDrawAxis *axis)
    465: {
    466:   PetscFunctionBegin;
    468:   PetscAssertPointer(axis, 2);
    469:   *axis = sp->axis;
    470:   PetscFunctionReturn(PETSC_SUCCESS);
    471: }

    473: /*@
    474:   PetscDrawSPGetDraw - Gets the draw context associated with a scatter plot

    476:   Not Collective

    478:   Input Parameter:
    479: . sp - the scatter plot context

    481:   Output Parameter:
    482: . draw - the draw context

    484:   Level: intermediate

    486: .seealso: `PetscDrawSP`, `PetscDrawSPCreate()`, `PetscDrawSPDraw()`, `PetscDraw`
    487: @*/
    488: PetscErrorCode PetscDrawSPGetDraw(PetscDrawSP sp, PetscDraw *draw)
    489: {
    490:   PetscFunctionBegin;
    492:   PetscAssertPointer(draw, 2);
    493:   *draw = sp->win;
    494:   PetscFunctionReturn(PETSC_SUCCESS);
    495: }