1 /* 2 Contains the data structure for plotting a bargraph in a window with an axis. 3 */ 4 5 #include <petsc/private/drawimpl.h> /*I "petscdraw.h" I*/ 6 #include <petscviewer.h> /*I "petscviewer.h" I*/ 7 8 PetscClassId PETSC_DRAWBAR_CLASSID = 0; 9 10 /*@C 11 PetscDrawBarCreate - Creates a bar graph data structure. 12 13 Collective 14 15 Input Parameter: 16 . draw - The window where the graph will be made 17 18 Output Parameter: 19 . bar - The bar graph context 20 21 Notes: 22 Call `PetscDrawBarSetData()` to provide the bins to be plotted and then `PetscDrawBarDraw()` to display the new plot 23 24 The difference between a bar chart, `PetscDrawBar`, and a histogram, `PetscDrawHG`, is explained here <https://stattrek.com/statistics/charts/histogram.aspx?Tutorial=AP> 25 26 The MPI communicator that owns the `PetscDraw` owns this `PetscDrawBar`, but the calls to set options and add data are ignored on all processes except the 27 zeroth MPI process in the communicator. All MPI processes in the communicator must call `PetscDrawBarDraw()` to display the updated graph. 28 29 Level: intermediate 30 31 .seealso: `PetscDrawBar`, `PetscDrawLGCreate()`, `PetscDrawLG`, `PetscDrawSPCreate()`, `PetscDrawSP`, `PetscDrawHGCreate()`, `PetscDrawHG`, `PetscDrawBarDestroy()`, `PetscDrawBarSetData()`, 32 `PetscDrawBarDraw()`, `PetscDrawBarSave()`, `PetscDrawBarSetColor()`, `PetscDrawBarSort()`, `PetscDrawBarSetLimits()`, `PetscDrawBarGetAxis()`, `PetscDrawAxis`, 33 `PetscDrawBarGetDraw()`, `PetscDrawBarSetFromOptions()` 34 @*/ 35 PetscErrorCode PetscDrawBarCreate(PetscDraw draw, PetscDrawBar *bar) 36 { 37 PetscDrawBar h; 38 39 PetscFunctionBegin; 40 PetscValidHeaderSpecific(draw, PETSC_DRAW_CLASSID, 1); 41 PetscAssertPointer(bar, 2); 42 43 PetscCall(PetscHeaderCreate(h, PETSC_DRAWBAR_CLASSID, "DrawBar", "Bar Graph", "Draw", PetscObjectComm((PetscObject)draw), PetscDrawBarDestroy, NULL)); 44 45 PetscCall(PetscObjectReference((PetscObject)draw)); 46 h->win = draw; 47 48 h->view = NULL; 49 h->destroy = NULL; 50 h->color = PETSC_DRAW_GREEN; 51 h->ymin = 0.; /* if user has not set these then they are determined from the data */ 52 h->ymax = 0.; 53 h->numBins = 0; 54 55 PetscCall(PetscDrawAxisCreate(draw, &h->axis)); 56 h->axis->xticks = NULL; 57 58 *bar = h; 59 PetscFunctionReturn(PETSC_SUCCESS); 60 } 61 62 /*@C 63 PetscDrawBarSetData - Set the data for a bar graph 64 65 Logically Collective 66 67 Input Parameters: 68 + bar - The bar graph context. 69 . bins - number of items 70 . data - values of each item 71 - labels - optional label for each bar, `NULL` terminated array of strings 72 73 Level: intermediate 74 75 Notes: 76 Call `PetscDrawBarDraw()` after this call to display the new plot 77 78 The data is ignored on all MPI processes except rank zero 79 80 .seealso: `PetscDrawBar`, `PetscDrawBarCreate()`, `PetscDrawBarDraw()` 81 @*/ 82 PetscErrorCode PetscDrawBarSetData(PetscDrawBar bar, PetscInt bins, const PetscReal data[], const char *const *labels) 83 { 84 PetscFunctionBegin; 85 PetscValidHeaderSpecific(bar, PETSC_DRAWBAR_CLASSID, 1); 86 87 if (bar->numBins != bins) { 88 PetscCall(PetscFree(bar->values)); 89 PetscCall(PetscMalloc1(bins, &bar->values)); 90 bar->numBins = bins; 91 } 92 PetscCall(PetscArraycpy(bar->values, data, bins)); 93 bar->numBins = bins; 94 if (labels) PetscCall(PetscStrArrayallocpy(labels, &bar->labels)); 95 PetscFunctionReturn(PETSC_SUCCESS); 96 } 97 98 /*@C 99 PetscDrawBarDestroy - Frees all space taken up by bar graph data structure. 100 101 Collective 102 103 Input Parameter: 104 . bar - The bar graph context 105 106 Level: intermediate 107 108 .seealso: `PetscDrawBar`, `PetscDrawBarCreate()` 109 @*/ 110 PetscErrorCode PetscDrawBarDestroy(PetscDrawBar *bar) 111 { 112 PetscFunctionBegin; 113 if (!*bar) PetscFunctionReturn(PETSC_SUCCESS); 114 PetscValidHeaderSpecific(*bar, PETSC_DRAWBAR_CLASSID, 1); 115 if (--((PetscObject)*bar)->refct > 0) PetscFunctionReturn(PETSC_SUCCESS); 116 117 PetscCall(PetscFree((*bar)->values)); 118 PetscCall(PetscStrArrayDestroy(&(*bar)->labels)); 119 PetscCall(PetscDrawAxisDestroy(&(*bar)->axis)); 120 PetscCall(PetscDrawDestroy(&(*bar)->win)); 121 PetscCall(PetscHeaderDestroy(bar)); 122 PetscFunctionReturn(PETSC_SUCCESS); 123 } 124 125 /*@ 126 PetscDrawBarDraw - Redraws a bar graph. 127 128 Collective 129 130 Input Parameter: 131 . bar - The bar graph context 132 133 Level: intermediate 134 135 .seealso: `PetscDrawBar`, `PetscDrawBarCreate()`, `PetscDrawBarSetData()` 136 @*/ 137 PetscErrorCode PetscDrawBarDraw(PetscDrawBar bar) 138 { 139 PetscDraw draw; 140 PetscBool isnull; 141 PetscReal xmin, xmax, ymin, ymax, *values, binLeft, binRight; 142 PetscInt numValues, i, bcolor, color, idx, *perm, nplot; 143 PetscMPIInt rank; 144 char **labels; 145 146 PetscFunctionBegin; 147 PetscValidHeaderSpecific(bar, PETSC_DRAWBAR_CLASSID, 1); 148 PetscCall(PetscDrawIsNull(bar->win, &isnull)); 149 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 150 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)bar), &rank)); 151 152 if (bar->numBins < 1) PetscFunctionReturn(PETSC_SUCCESS); 153 154 color = bar->color; 155 if (color == PETSC_DRAW_ROTATE) bcolor = PETSC_DRAW_BLACK + 1; 156 else bcolor = color; 157 158 numValues = bar->numBins; 159 values = bar->values; 160 if (bar->ymin == bar->ymax) { 161 /* user has not set bounds on bars so set them based on the data */ 162 ymin = PETSC_MAX_REAL; 163 ymax = PETSC_MIN_REAL; 164 for (i = 0; i < numValues; i++) { 165 ymin = PetscMin(ymin, values[i]); 166 ymax = PetscMax(ymax, values[i]); 167 } 168 } else { 169 ymin = bar->ymin; 170 ymax = bar->ymax; 171 } 172 nplot = numValues; /* number of points to actually plot; if some are lower than requested tolerance */ 173 xmin = 0.0; 174 xmax = nplot; 175 labels = bar->labels; 176 177 if (bar->sort) { 178 PetscCall(PetscMalloc1(numValues, &perm)); 179 for (i = 0; i < numValues; i++) perm[i] = i; 180 PetscCall(PetscSortRealWithPermutation(numValues, values, perm)); 181 if (bar->sorttolerance) { 182 for (i = 0; i < numValues; i++) { 183 if (values[perm[numValues - i - 1]] < bar->sorttolerance) { 184 nplot = i; 185 break; 186 } 187 } 188 } 189 } 190 191 draw = bar->win; 192 PetscCall(PetscDrawCheckResizedWindow(draw)); 193 PetscCall(PetscDrawClear(draw)); 194 195 PetscCall(PetscDrawAxisSetLimits(bar->axis, xmin, xmax, ymin, ymax)); 196 PetscCall(PetscDrawAxisDraw(bar->axis)); 197 198 PetscDrawCollectiveBegin(draw); 199 if (rank == 0) { /* Draw bins */ 200 for (i = 0; i < nplot; i++) { 201 idx = (bar->sort ? perm[numValues - i - 1] : i); 202 binLeft = xmin + i; 203 binRight = xmin + i + 1; 204 PetscCall(PetscDrawRectangle(draw, binLeft, ymin, binRight, values[idx], bcolor, bcolor, bcolor, bcolor)); 205 PetscCall(PetscDrawLine(draw, binLeft, ymin, binLeft, values[idx], PETSC_DRAW_BLACK)); 206 PetscCall(PetscDrawLine(draw, binRight, ymin, binRight, values[idx], PETSC_DRAW_BLACK)); 207 PetscCall(PetscDrawLine(draw, binLeft, values[idx], binRight, values[idx], PETSC_DRAW_BLACK)); 208 if (labels) { 209 PetscReal h; 210 PetscCall(PetscDrawStringGetSize(draw, NULL, &h)); 211 PetscCall(PetscDrawStringCentered(draw, .5 * (binLeft + binRight), ymin - 1.5 * h, bcolor, labels[idx])); 212 } 213 if (color == PETSC_DRAW_ROTATE) bcolor++; 214 if (bcolor > PETSC_DRAW_BASIC_COLORS - 1) bcolor = PETSC_DRAW_BLACK + 1; 215 } 216 } 217 PetscDrawCollectiveEnd(draw); 218 if (bar->sort) PetscCall(PetscFree(perm)); 219 220 PetscCall(PetscDrawFlush(draw)); 221 PetscCall(PetscDrawPause(draw)); 222 PetscFunctionReturn(PETSC_SUCCESS); 223 } 224 225 /*@ 226 PetscDrawBarSave - Saves a drawn bar graph 227 228 Collective 229 230 Input Parameter: 231 . bar - The bar graph context 232 233 Level: intermediate 234 235 .seealso: `PetscDrawSave()`, `PetscDrawBar`, `PetscDrawBarCreate()`, `PetscDrawBarGetDraw()`, `PetscDrawSetSave()`, `PetscDrawBarSetData()` 236 @*/ 237 PetscErrorCode PetscDrawBarSave(PetscDrawBar bar) 238 { 239 PetscFunctionBegin; 240 PetscValidHeaderSpecific(bar, PETSC_DRAWBAR_CLASSID, 1); 241 PetscCall(PetscDrawSave(bar->win)); 242 PetscFunctionReturn(PETSC_SUCCESS); 243 } 244 245 /*@ 246 PetscDrawBarSetColor - Sets the color the bars will be drawn with. 247 248 Logically Collective 249 250 Input Parameters: 251 + bar - The bar graph context 252 - color - one of the colors defined in petscdraw.h or `PETSC_DRAW_ROTATE` to make each bar a 253 different color 254 255 Level: intermediate 256 257 .seealso: `PetscDrawBarCreate()`, `PetscDrawBar`, `PetscDrawBarSetData()`, `PetscDrawBarDraw()`, `PetscDrawBarGetAxis()` 258 @*/ 259 PetscErrorCode PetscDrawBarSetColor(PetscDrawBar bar, int color) 260 { 261 PetscFunctionBegin; 262 PetscValidHeaderSpecific(bar, PETSC_DRAWBAR_CLASSID, 1); 263 bar->color = color; 264 PetscFunctionReturn(PETSC_SUCCESS); 265 } 266 267 /*@ 268 PetscDrawBarSort - Sorts the values before drawing the bar chart, the bars will be in ascending order from left to right 269 270 Logically Collective 271 272 Input Parameters: 273 + bar - The bar graph context 274 . sort - `PETSC_TRUE` to sort the values 275 - tolerance - discard values less than tolerance 276 277 Level: intermediate 278 279 .seealso: `PetscDrawBar`, `PetscDrawBarCreate()`, `PetscDrawBarSetData()`, `PetscDrawBarSetColor()`, `PetscDrawBarDraw()`, `PetscDrawBarGetAxis()` 280 @*/ 281 PetscErrorCode PetscDrawBarSort(PetscDrawBar bar, PetscBool sort, PetscReal tolerance) 282 { 283 PetscFunctionBegin; 284 PetscValidHeaderSpecific(bar, PETSC_DRAWBAR_CLASSID, 1); 285 bar->sort = sort; 286 bar->sorttolerance = tolerance; 287 PetscFunctionReturn(PETSC_SUCCESS); 288 } 289 290 /*@ 291 PetscDrawBarSetLimits - Sets the axis limits for a bar graph. If more 292 points are added after this call, the limits will be adjusted to 293 include those additional points. 294 295 Logically Collective 296 297 Input Parameters: 298 + bar - The bar graph context 299 . y_min - The lower limit 300 - y_max - The upper limit 301 302 Level: intermediate 303 304 .seealso: `PetscDrawBar`, `PetscDrawBarCreate()`, `PetscDrawBarGetAxis()`, `PetscDrawBarSetData()`, `PetscDrawBarDraw()` 305 @*/ 306 PetscErrorCode PetscDrawBarSetLimits(PetscDrawBar bar, PetscReal y_min, PetscReal y_max) 307 { 308 PetscFunctionBegin; 309 PetscValidHeaderSpecific(bar, PETSC_DRAWBAR_CLASSID, 1); 310 bar->ymin = y_min; 311 bar->ymax = y_max; 312 PetscFunctionReturn(PETSC_SUCCESS); 313 } 314 315 /*@C 316 PetscDrawBarGetAxis - Gets the axis context associated with a bar graph. 317 This is useful if one wants to change some axis property, such as 318 labels, color, etc. The axis context should not be destroyed by the 319 application code. 320 321 Not Collective, axis is parallel if bar is parallel 322 323 Input Parameter: 324 . bar - The bar graph context 325 326 Output Parameter: 327 . axis - The axis context 328 329 Level: intermediate 330 331 .seealso: `PetscDrawBar`, `PetscDrawBarCreate()`, `PetscDrawAxis`, `PetscDrawAxisCreate()` 332 @*/ 333 PetscErrorCode PetscDrawBarGetAxis(PetscDrawBar bar, PetscDrawAxis *axis) 334 { 335 PetscFunctionBegin; 336 PetscValidHeaderSpecific(bar, PETSC_DRAWBAR_CLASSID, 1); 337 PetscAssertPointer(axis, 2); 338 *axis = bar->axis; 339 PetscFunctionReturn(PETSC_SUCCESS); 340 } 341 342 /*@C 343 PetscDrawBarGetDraw - Gets the draw context associated with a bar graph. 344 345 Not Collective, draw is parallel if bar is parallel 346 347 Input Parameter: 348 . bar - The bar graph context 349 350 Output Parameter: 351 . draw - The draw context 352 353 Level: intermediate 354 355 .seealso: `PetscDrawBar`, `PetscDraw`, `PetscDrawBarCreate()`, `PetscDrawBarDraw()` 356 @*/ 357 PetscErrorCode PetscDrawBarGetDraw(PetscDrawBar bar, PetscDraw *draw) 358 { 359 PetscFunctionBegin; 360 PetscValidHeaderSpecific(bar, PETSC_DRAWBAR_CLASSID, 1); 361 PetscAssertPointer(draw, 2); 362 *draw = bar->win; 363 PetscFunctionReturn(PETSC_SUCCESS); 364 } 365 366 /*@ 367 PetscDrawBarSetFromOptions - Sets options related to the display of the `PetscDrawBar` 368 369 Collective 370 371 Input Parameter: 372 . bar - the bar graph context 373 374 Options Database Key: 375 . -bar_sort - sort the entries before drawing the bar graph 376 377 Level: intermediate 378 379 Note: 380 Does not set options related to the underlying `PetscDraw` or `PetscDrawAxis` 381 382 .seealso: `PetscDrawBar`, `PetscDrawBarDestroy()`, `PetscDrawBarCreate()`, `PetscDrawBarSort()` 383 @*/ 384 PetscErrorCode PetscDrawBarSetFromOptions(PetscDrawBar bar) 385 { 386 PetscBool set; 387 388 PetscFunctionBegin; 389 PetscValidHeaderSpecific(bar, PETSC_DRAWBAR_CLASSID, 1); 390 391 PetscCall(PetscOptionsHasName(((PetscObject)bar)->options, ((PetscObject)bar)->prefix, "-bar_sort", &set)); 392 if (set) { 393 PetscReal tol = bar->sorttolerance; 394 PetscCall(PetscOptionsGetReal(((PetscObject)bar)->options, ((PetscObject)bar)->prefix, "-bar_sort", &tol, NULL)); 395 PetscCall(PetscDrawBarSort(bar, PETSC_TRUE, tol)); 396 } 397 PetscFunctionReturn(PETSC_SUCCESS); 398 } 399