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