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