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 = bins; 87 } 88 PetscCall(PetscArraycpy(bar->values, data, bins)); 89 bar->numBins = 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, bcolor, color, idx, *perm, nplot; 139 PetscMPIInt rank; 140 char **labels; 141 142 PetscFunctionBegin; 143 PetscValidHeaderSpecific(bar, PETSC_DRAWBAR_CLASSID, 1); 144 PetscCall(PetscDrawIsNull(bar->win, &isnull)); 145 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 146 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)bar), &rank)); 147 148 if (bar->numBins < 1) PetscFunctionReturn(PETSC_SUCCESS); 149 150 color = bar->color; 151 if (color == PETSC_DRAW_ROTATE) bcolor = PETSC_DRAW_BLACK + 1; 152 else bcolor = color; 153 154 numValues = bar->numBins; 155 values = bar->values; 156 if (bar->ymin == bar->ymax) { 157 /* user has not set bounds on bars so set them based on the data */ 158 ymin = PETSC_MAX_REAL; 159 ymax = PETSC_MIN_REAL; 160 for (i = 0; i < numValues; i++) { 161 ymin = PetscMin(ymin, values[i]); 162 ymax = PetscMax(ymax, values[i]); 163 } 164 } else { 165 ymin = bar->ymin; 166 ymax = bar->ymax; 167 } 168 nplot = numValues; /* number of points to actually plot; if some are lower than requested tolerance */ 169 xmin = 0.0; 170 xmax = nplot; 171 labels = bar->labels; 172 173 if (bar->sort) { 174 PetscCall(PetscMalloc1(numValues, &perm)); 175 for (i = 0; i < numValues; i++) perm[i] = i; 176 PetscCall(PetscSortRealWithPermutation(numValues, values, perm)); 177 if (bar->sorttolerance) { 178 for (i = 0; i < numValues; i++) { 179 if (values[perm[numValues - i - 1]] < bar->sorttolerance) { 180 nplot = i; 181 break; 182 } 183 } 184 } 185 } 186 187 draw = bar->win; 188 PetscCall(PetscDrawCheckResizedWindow(draw)); 189 PetscCall(PetscDrawClear(draw)); 190 191 PetscCall(PetscDrawAxisSetLimits(bar->axis, xmin, xmax, ymin, ymax)); 192 PetscCall(PetscDrawAxisDraw(bar->axis)); 193 194 PetscDrawCollectiveBegin(draw); 195 if (rank == 0) { /* Draw bins */ 196 for (i = 0; i < nplot; i++) { 197 idx = (bar->sort ? perm[numValues - i - 1] : i); 198 binLeft = xmin + i; 199 binRight = xmin + i + 1; 200 PetscCall(PetscDrawRectangle(draw, binLeft, ymin, binRight, values[idx], bcolor, bcolor, bcolor, bcolor)); 201 PetscCall(PetscDrawLine(draw, binLeft, ymin, binLeft, values[idx], PETSC_DRAW_BLACK)); 202 PetscCall(PetscDrawLine(draw, binRight, ymin, binRight, values[idx], PETSC_DRAW_BLACK)); 203 PetscCall(PetscDrawLine(draw, binLeft, values[idx], binRight, values[idx], PETSC_DRAW_BLACK)); 204 if (labels) { 205 PetscReal h; 206 PetscCall(PetscDrawStringGetSize(draw, NULL, &h)); 207 PetscCall(PetscDrawStringCentered(draw, .5 * (binLeft + binRight), ymin - 1.5 * h, bcolor, labels[idx])); 208 } 209 if (color == PETSC_DRAW_ROTATE) bcolor++; 210 if (bcolor > PETSC_DRAW_BASIC_COLORS - 1) bcolor = PETSC_DRAW_BLACK + 1; 211 } 212 } 213 PetscDrawCollectiveEnd(draw); 214 if (bar->sort) PetscCall(PetscFree(perm)); 215 216 PetscCall(PetscDrawFlush(draw)); 217 PetscCall(PetscDrawPause(draw)); 218 PetscFunctionReturn(PETSC_SUCCESS); 219 } 220 221 /*@ 222 PetscDrawBarSave - Saves a drawn bar graph 223 224 Collective 225 226 Input Parameter: 227 . bar - The bar graph context 228 229 Level: intermediate 230 231 .seealso: `PetscDrawSave()`, `PetscDrawBar`, `PetscDrawBarCreate()`, `PetscDrawBarGetDraw()`, `PetscDrawSetSave()`, `PetscDrawBarSetData()` 232 @*/ 233 PetscErrorCode PetscDrawBarSave(PetscDrawBar bar) 234 { 235 PetscFunctionBegin; 236 PetscValidHeaderSpecific(bar, PETSC_DRAWBAR_CLASSID, 1); 237 PetscCall(PetscDrawSave(bar->win)); 238 PetscFunctionReturn(PETSC_SUCCESS); 239 } 240 241 /*@ 242 PetscDrawBarSetColor - Sets the color the bars will be drawn with. 243 244 Logically Collective 245 246 Input Parameters: 247 + bar - The bar graph context 248 - color - one of the colors defined in petscdraw.h or `PETSC_DRAW_ROTATE` to make each bar a 249 different color 250 251 Level: intermediate 252 253 .seealso: `PetscDrawBarCreate()`, `PetscDrawBar`, `PetscDrawBarSetData()`, `PetscDrawBarDraw()`, `PetscDrawBarGetAxis()` 254 @*/ 255 PetscErrorCode PetscDrawBarSetColor(PetscDrawBar bar, int color) 256 { 257 PetscFunctionBegin; 258 PetscValidHeaderSpecific(bar, PETSC_DRAWBAR_CLASSID, 1); 259 bar->color = color; 260 PetscFunctionReturn(PETSC_SUCCESS); 261 } 262 263 /*@ 264 PetscDrawBarSort - Sorts the values before drawing the bar chart, the bars will be in ascending order from left to right 265 266 Logically Collective 267 268 Input Parameters: 269 + bar - The bar graph context 270 . sort - `PETSC_TRUE` to sort the values 271 - tolerance - discard values less than tolerance 272 273 Level: intermediate 274 275 .seealso: `PetscDrawBar`, `PetscDrawBarCreate()`, `PetscDrawBarSetData()`, `PetscDrawBarSetColor()`, `PetscDrawBarDraw()`, `PetscDrawBarGetAxis()` 276 @*/ 277 PetscErrorCode PetscDrawBarSort(PetscDrawBar bar, PetscBool sort, PetscReal tolerance) 278 { 279 PetscFunctionBegin; 280 PetscValidHeaderSpecific(bar, PETSC_DRAWBAR_CLASSID, 1); 281 bar->sort = sort; 282 bar->sorttolerance = tolerance; 283 PetscFunctionReturn(PETSC_SUCCESS); 284 } 285 286 /*@ 287 PetscDrawBarSetLimits - Sets the axis limits for a bar graph. If more 288 points are added after this call, the limits will be adjusted to 289 include those additional points. 290 291 Logically Collective 292 293 Input Parameters: 294 + bar - The bar graph context 295 . y_min - The lower limit 296 - y_max - The upper limit 297 298 Level: intermediate 299 300 .seealso: `PetscDrawBar`, `PetscDrawBarCreate()`, `PetscDrawBarGetAxis()`, `PetscDrawBarSetData()`, `PetscDrawBarDraw()` 301 @*/ 302 PetscErrorCode PetscDrawBarSetLimits(PetscDrawBar bar, PetscReal y_min, PetscReal y_max) 303 { 304 PetscFunctionBegin; 305 PetscValidHeaderSpecific(bar, PETSC_DRAWBAR_CLASSID, 1); 306 bar->ymin = y_min; 307 bar->ymax = y_max; 308 PetscFunctionReturn(PETSC_SUCCESS); 309 } 310 311 /*@ 312 PetscDrawBarGetAxis - Gets the axis context associated with a bar graph. 313 This is useful if one wants to change some axis property, such as 314 labels, color, etc. The axis context should not be destroyed by the 315 application code. 316 317 Not Collective, axis is parallel if bar is parallel 318 319 Input Parameter: 320 . bar - The bar graph context 321 322 Output Parameter: 323 . axis - The axis context 324 325 Level: intermediate 326 327 .seealso: `PetscDrawBar`, `PetscDrawBarCreate()`, `PetscDrawAxis`, `PetscDrawAxisCreate()` 328 @*/ 329 PetscErrorCode PetscDrawBarGetAxis(PetscDrawBar bar, PetscDrawAxis *axis) 330 { 331 PetscFunctionBegin; 332 PetscValidHeaderSpecific(bar, PETSC_DRAWBAR_CLASSID, 1); 333 PetscAssertPointer(axis, 2); 334 *axis = bar->axis; 335 PetscFunctionReturn(PETSC_SUCCESS); 336 } 337 338 /*@ 339 PetscDrawBarGetDraw - Gets the draw context associated with a bar graph. 340 341 Not Collective, draw is parallel if bar is parallel 342 343 Input Parameter: 344 . bar - The bar graph context 345 346 Output Parameter: 347 . draw - The draw context 348 349 Level: intermediate 350 351 .seealso: `PetscDrawBar`, `PetscDraw`, `PetscDrawBarCreate()`, `PetscDrawBarDraw()` 352 @*/ 353 PetscErrorCode PetscDrawBarGetDraw(PetscDrawBar bar, PetscDraw *draw) 354 { 355 PetscFunctionBegin; 356 PetscValidHeaderSpecific(bar, PETSC_DRAWBAR_CLASSID, 1); 357 PetscAssertPointer(draw, 2); 358 *draw = bar->win; 359 PetscFunctionReturn(PETSC_SUCCESS); 360 } 361 362 /*@ 363 PetscDrawBarSetFromOptions - Sets options related to the display of the `PetscDrawBar` 364 365 Collective 366 367 Input Parameter: 368 . bar - the bar graph context 369 370 Options Database Key: 371 . -bar_sort - sort the entries before drawing the bar graph 372 373 Level: intermediate 374 375 Note: 376 Does not set options related to the underlying `PetscDraw` or `PetscDrawAxis` 377 378 .seealso: `PetscDrawBar`, `PetscDrawBarDestroy()`, `PetscDrawBarCreate()`, `PetscDrawBarSort()` 379 @*/ 380 PetscErrorCode PetscDrawBarSetFromOptions(PetscDrawBar bar) 381 { 382 PetscBool set; 383 384 PetscFunctionBegin; 385 PetscValidHeaderSpecific(bar, PETSC_DRAWBAR_CLASSID, 1); 386 387 PetscCall(PetscOptionsHasName(((PetscObject)bar)->options, ((PetscObject)bar)->prefix, "-bar_sort", &set)); 388 if (set) { 389 PetscReal tol = bar->sorttolerance; 390 PetscCall(PetscOptionsGetReal(((PetscObject)bar)->options, ((PetscObject)bar)->prefix, "-bar_sort", &tol, NULL)); 391 PetscCall(PetscDrawBarSort(bar, PETSC_TRUE, tol)); 392 } 393 PetscFunctionReturn(PETSC_SUCCESS); 394 } 395