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 } 87 PetscCall(PetscArraycpy(bar->values, data, bins)); 88 PetscCall(PetscCIntCast(bins, &bar->numBins)); 89 if (labels) PetscCall(PetscStrArrayallocpy(labels, &bar->labels)); 90 PetscFunctionReturn(PETSC_SUCCESS); 91 } 92 93 /*@ 94 PetscDrawBarDestroy - Frees all space taken up by bar graph data structure. 95 96 Collective 97 98 Input Parameter: 99 . bar - The bar graph context 100 101 Level: intermediate 102 103 .seealso: `PetscDrawBar`, `PetscDrawBarCreate()` 104 @*/ 105 PetscErrorCode PetscDrawBarDestroy(PetscDrawBar *bar) 106 { 107 PetscFunctionBegin; 108 if (!*bar) PetscFunctionReturn(PETSC_SUCCESS); 109 PetscValidHeaderSpecific(*bar, PETSC_DRAWBAR_CLASSID, 1); 110 if (--((PetscObject)*bar)->refct > 0) PetscFunctionReturn(PETSC_SUCCESS); 111 112 PetscCall(PetscFree((*bar)->values)); 113 PetscCall(PetscStrArrayDestroy(&(*bar)->labels)); 114 PetscCall(PetscDrawAxisDestroy(&(*bar)->axis)); 115 PetscCall(PetscDrawDestroy(&(*bar)->win)); 116 PetscCall(PetscHeaderDestroy(bar)); 117 PetscFunctionReturn(PETSC_SUCCESS); 118 } 119 120 /*@ 121 PetscDrawBarDraw - Redraws a bar graph. 122 123 Collective 124 125 Input Parameter: 126 . bar - The bar graph context 127 128 Level: intermediate 129 130 .seealso: `PetscDrawBar`, `PetscDrawBarCreate()`, `PetscDrawBarSetData()` 131 @*/ 132 PetscErrorCode PetscDrawBarDraw(PetscDrawBar bar) 133 { 134 PetscDraw draw; 135 PetscBool isnull; 136 PetscReal xmin, xmax, ymin, ymax, *values, binLeft, binRight; 137 PetscInt numValues, i, idx, *perm, nplot; 138 PetscMPIInt rank; 139 char **labels; 140 int bcolor, color; 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 = (PetscReal)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 + (PetscReal)i; 199 binRight = xmin + (PetscReal)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 207 PetscCall(PetscDrawStringGetSize(draw, NULL, &h)); 208 PetscCall(PetscDrawStringCentered(draw, .5 * (binLeft + binRight), ymin - 1.5 * h, bcolor, labels[idx])); 209 } 210 if (color == PETSC_DRAW_ROTATE) bcolor++; 211 if (bcolor > PETSC_DRAW_BASIC_COLORS - 1) bcolor = PETSC_DRAW_BLACK + 1; 212 } 213 } 214 PetscDrawCollectiveEnd(draw); 215 if (bar->sort) PetscCall(PetscFree(perm)); 216 217 PetscCall(PetscDrawFlush(draw)); 218 PetscCall(PetscDrawPause(draw)); 219 PetscFunctionReturn(PETSC_SUCCESS); 220 } 221 222 /*@ 223 PetscDrawBarSave - Saves a drawn bar graph 224 225 Collective 226 227 Input Parameter: 228 . bar - The bar graph context 229 230 Level: intermediate 231 232 .seealso: `PetscDrawSave()`, `PetscDrawBar`, `PetscDrawBarCreate()`, `PetscDrawBarGetDraw()`, `PetscDrawSetSave()`, `PetscDrawBarSetData()` 233 @*/ 234 PetscErrorCode PetscDrawBarSave(PetscDrawBar bar) 235 { 236 PetscFunctionBegin; 237 PetscValidHeaderSpecific(bar, PETSC_DRAWBAR_CLASSID, 1); 238 PetscCall(PetscDrawSave(bar->win)); 239 PetscFunctionReturn(PETSC_SUCCESS); 240 } 241 242 /*@ 243 PetscDrawBarSetColor - Sets the color the bars will be drawn with. 244 245 Logically Collective 246 247 Input Parameters: 248 + bar - The bar graph context 249 - color - one of the colors defined in petscdraw.h or `PETSC_DRAW_ROTATE` to make each bar a 250 different color 251 252 Level: intermediate 253 254 .seealso: `PetscDrawBarCreate()`, `PetscDrawBar`, `PetscDrawBarSetData()`, `PetscDrawBarDraw()`, `PetscDrawBarGetAxis()` 255 @*/ 256 PetscErrorCode PetscDrawBarSetColor(PetscDrawBar bar, int color) 257 { 258 PetscFunctionBegin; 259 PetscValidHeaderSpecific(bar, PETSC_DRAWBAR_CLASSID, 1); 260 bar->color = color; 261 PetscFunctionReturn(PETSC_SUCCESS); 262 } 263 264 /*@ 265 PetscDrawBarSort - Sorts the values before drawing the bar chart, the bars will be in ascending order from left to right 266 267 Logically Collective 268 269 Input Parameters: 270 + bar - The bar graph context 271 . sort - `PETSC_TRUE` to sort the values 272 - tolerance - discard values less than tolerance 273 274 Level: intermediate 275 276 .seealso: `PetscDrawBar`, `PetscDrawBarCreate()`, `PetscDrawBarSetData()`, `PetscDrawBarSetColor()`, `PetscDrawBarDraw()`, `PetscDrawBarGetAxis()` 277 @*/ 278 PetscErrorCode PetscDrawBarSort(PetscDrawBar bar, PetscBool sort, PetscReal tolerance) 279 { 280 PetscFunctionBegin; 281 PetscValidHeaderSpecific(bar, PETSC_DRAWBAR_CLASSID, 1); 282 bar->sort = sort; 283 bar->sorttolerance = tolerance; 284 PetscFunctionReturn(PETSC_SUCCESS); 285 } 286 287 /*@ 288 PetscDrawBarSetLimits - Sets the axis limits for a bar graph. If more 289 points are added after this call, the limits will be adjusted to 290 include those additional points. 291 292 Logically Collective 293 294 Input Parameters: 295 + bar - The bar graph context 296 . y_min - The lower limit 297 - y_max - The upper limit 298 299 Level: intermediate 300 301 .seealso: `PetscDrawBar`, `PetscDrawBarCreate()`, `PetscDrawBarGetAxis()`, `PetscDrawBarSetData()`, `PetscDrawBarDraw()` 302 @*/ 303 PetscErrorCode PetscDrawBarSetLimits(PetscDrawBar bar, PetscReal y_min, PetscReal y_max) 304 { 305 PetscFunctionBegin; 306 PetscValidHeaderSpecific(bar, PETSC_DRAWBAR_CLASSID, 1); 307 bar->ymin = y_min; 308 bar->ymax = y_max; 309 PetscFunctionReturn(PETSC_SUCCESS); 310 } 311 312 /*@ 313 PetscDrawBarGetAxis - Gets the axis context associated with a bar graph. 314 This is useful if one wants to change some axis property, such as 315 labels, color, etc. The axis context should not be destroyed by the 316 application code. 317 318 Not Collective, axis is parallel if bar is parallel 319 320 Input Parameter: 321 . bar - The bar graph context 322 323 Output Parameter: 324 . axis - The axis context 325 326 Level: intermediate 327 328 .seealso: `PetscDrawBar`, `PetscDrawBarCreate()`, `PetscDrawAxis`, `PetscDrawAxisCreate()` 329 @*/ 330 PetscErrorCode PetscDrawBarGetAxis(PetscDrawBar bar, PetscDrawAxis *axis) 331 { 332 PetscFunctionBegin; 333 PetscValidHeaderSpecific(bar, PETSC_DRAWBAR_CLASSID, 1); 334 PetscAssertPointer(axis, 2); 335 *axis = bar->axis; 336 PetscFunctionReturn(PETSC_SUCCESS); 337 } 338 339 /*@ 340 PetscDrawBarGetDraw - Gets the draw context associated with a bar graph. 341 342 Not Collective, draw is parallel if bar is parallel 343 344 Input Parameter: 345 . bar - The bar graph context 346 347 Output Parameter: 348 . draw - The draw context 349 350 Level: intermediate 351 352 .seealso: `PetscDrawBar`, `PetscDraw`, `PetscDrawBarCreate()`, `PetscDrawBarDraw()` 353 @*/ 354 PetscErrorCode PetscDrawBarGetDraw(PetscDrawBar bar, PetscDraw *draw) 355 { 356 PetscFunctionBegin; 357 PetscValidHeaderSpecific(bar, PETSC_DRAWBAR_CLASSID, 1); 358 PetscAssertPointer(draw, 2); 359 *draw = bar->win; 360 PetscFunctionReturn(PETSC_SUCCESS); 361 } 362 363 /*@ 364 PetscDrawBarSetFromOptions - Sets options related to the display of the `PetscDrawBar` 365 366 Collective 367 368 Input Parameter: 369 . bar - the bar graph context 370 371 Options Database Key: 372 . -bar_sort - sort the entries before drawing the bar graph 373 374 Level: intermediate 375 376 Note: 377 Does not set options related to the underlying `PetscDraw` or `PetscDrawAxis` 378 379 .seealso: `PetscDrawBar`, `PetscDrawBarDestroy()`, `PetscDrawBarCreate()`, `PetscDrawBarSort()` 380 @*/ 381 PetscErrorCode PetscDrawBarSetFromOptions(PetscDrawBar bar) 382 { 383 PetscBool set; 384 385 PetscFunctionBegin; 386 PetscValidHeaderSpecific(bar, PETSC_DRAWBAR_CLASSID, 1); 387 388 PetscCall(PetscOptionsHasName(((PetscObject)bar)->options, ((PetscObject)bar)->prefix, "-bar_sort", &set)); 389 if (set) { 390 PetscReal tol = bar->sorttolerance; 391 PetscCall(PetscOptionsGetReal(((PetscObject)bar)->options, ((PetscObject)bar)->prefix, "-bar_sort", &tol, NULL)); 392 PetscCall(PetscDrawBarSort(bar, PETSC_TRUE, tol)); 393 } 394 PetscFunctionReturn(PETSC_SUCCESS); 395 } 396