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