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 PetscDrawBar h; 38 39 PetscFunctionBegin; 40 PetscValidHeaderSpecific(draw, PETSC_DRAW_CLASSID, 1); 41 PetscValidPointer(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(0); 60 } 61 62 /*@C 63 PetscDrawBarSetData 64 65 Logically Collective on bar 66 67 Input Parameters: 68 + bar - The bar graph context. 69 . bins - number of items 70 . values - 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 ranks except zero 79 80 .seealso: `PetscDrawBar`, `PetscDrawBarCreate()`, `PetscDrawBar`, `PetscDrawBarDraw()` 81 @*/ 82 PetscErrorCode PetscDrawBarSetData(PetscDrawBar bar, PetscInt bins, const PetscReal data[], const char *const *labels) { 83 PetscFunctionBegin; 84 PetscValidHeaderSpecific(bar, PETSC_DRAWBAR_CLASSID, 1); 85 86 if (bar->numBins != bins) { 87 PetscCall(PetscFree(bar->values)); 88 PetscCall(PetscMalloc1(bins, &bar->values)); 89 bar->numBins = bins; 90 } 91 PetscCall(PetscArraycpy(bar->values, data, bins)); 92 bar->numBins = bins; 93 if (labels) PetscCall(PetscStrArrayallocpy(labels, &bar->labels)); 94 PetscFunctionReturn(0); 95 } 96 97 /*@C 98 PetscDrawBarDestroy - Frees all space taken up by bar graph data structure. 99 100 Collective over bar 101 102 Input Parameter: 103 . bar - The bar graph context 104 105 Level: intermediate 106 107 .seealso: `PetscDrawBar`, `PetscDrawBarCreate()` 108 @*/ 109 PetscErrorCode PetscDrawBarDestroy(PetscDrawBar *bar) { 110 PetscFunctionBegin; 111 if (!*bar) PetscFunctionReturn(0); 112 PetscValidHeaderSpecific(*bar, PETSC_DRAWBAR_CLASSID, 1); 113 if (--((PetscObject)(*bar))->refct > 0) PetscFunctionReturn(0); 114 115 PetscCall(PetscFree((*bar)->values)); 116 PetscCall(PetscStrArrayDestroy(&(*bar)->labels)); 117 PetscCall(PetscDrawAxisDestroy(&(*bar)->axis)); 118 PetscCall(PetscDrawDestroy(&(*bar)->win)); 119 PetscCall(PetscHeaderDestroy(bar)); 120 PetscFunctionReturn(0); 121 } 122 123 /*@ 124 PetscDrawBarDraw - Redraws a bar graph. 125 126 Collective on bar 127 128 Input Parameter: 129 . bar - The bar graph context 130 131 Level: intermediate 132 133 .seealso: `PetscDrawBar`, `PetscDrawBarCreate()`, `PetscDrawBarSetData()` 134 @*/ 135 PetscErrorCode PetscDrawBarDraw(PetscDrawBar bar) { 136 PetscDraw draw; 137 PetscBool isnull; 138 PetscReal xmin, xmax, ymin, ymax, *values, binLeft, binRight; 139 PetscInt numValues, i, bcolor, color, idx, *perm, nplot; 140 PetscMPIInt rank; 141 char **labels; 142 143 PetscFunctionBegin; 144 PetscValidHeaderSpecific(bar, PETSC_DRAWBAR_CLASSID, 1); 145 PetscCall(PetscDrawIsNull(bar->win, &isnull)); 146 if (isnull) PetscFunctionReturn(0); 147 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)bar), &rank)); 148 149 if (bar->numBins < 1) PetscFunctionReturn(0); 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 = 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 + i; 200 binRight = xmin + 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 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(0); 220 } 221 222 /*@ 223 PetscDrawBarSave - Saves a drawn bar graph 224 225 Collective on bar 226 227 Input Parameters: 228 . bar - The bar graph context 229 230 Level: intermediate 231 232 .seealso: `PetscDrawSave()`, `PetscDrawBar`, `PetscDrawBarCreate()`, `PetscDrawBarGetDraw()`, `PetscDrawSetSave()`, `PetscDrawSave()`, `PetscDrawBarSetData()` 233 @*/ 234 PetscErrorCode PetscDrawBarSave(PetscDrawBar bar) { 235 PetscFunctionBegin; 236 PetscValidHeaderSpecific(bar, PETSC_DRAWBAR_CLASSID, 1); 237 PetscCall(PetscDrawSave(bar->win)); 238 PetscFunctionReturn(0); 239 } 240 241 /*@ 242 PetscDrawBarSetColor - Sets the color the bars will be drawn with. 243 244 Logically Collective on bar 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 PetscFunctionBegin; 257 PetscValidHeaderSpecific(bar, PETSC_DRAWBAR_CLASSID, 1); 258 bar->color = color; 259 PetscFunctionReturn(0); 260 } 261 262 /*@ 263 PetscDrawBarSort - Sorts the values before drawing the bar chart, the bars will be in ascending order from left to right 264 265 Logically Collective on bar 266 267 Input Parameters: 268 + bar - The bar graph context 269 . sort - `PETSC_TRUE` to sort the values 270 - tolerance - discard values less than tolerance 271 272 Level: intermediate 273 274 .seealso: `PetscDrawBar`, `PetscDrawBarCreate()`, `PetscDrawBar`, `PetscDrawBarSetData()`, `PetscDrawBarSetColor()`, `PetscDrawBarDraw()`, `PetscDrawBarGetAxis()` 275 @*/ 276 PetscErrorCode PetscDrawBarSort(PetscDrawBar bar, PetscBool sort, PetscReal tolerance) { 277 PetscFunctionBegin; 278 PetscValidHeaderSpecific(bar, PETSC_DRAWBAR_CLASSID, 1); 279 bar->sort = sort; 280 bar->sorttolerance = tolerance; 281 PetscFunctionReturn(0); 282 } 283 284 /*@ 285 PetscDrawBarSetLimits - Sets the axis limits for a bar graph. If more 286 points are added after this call, the limits will be adjusted to 287 include those additional points. 288 289 Logically Collective on bar 290 291 Input Parameters: 292 + bar - The bar graph context 293 - y_min,y_max - The limits 294 295 Level: intermediate 296 297 .seealso: `PetscDrawBar`, `PetscDrawBarCreate()`, `PetscDrawBar`, `PetscDrawBarGetAxis()`, `PetscDrawBarSetData()`, `PetscDrawBarDraw()` 298 @*/ 299 PetscErrorCode PetscDrawBarSetLimits(PetscDrawBar bar, PetscReal y_min, PetscReal y_max) { 300 PetscFunctionBegin; 301 PetscValidHeaderSpecific(bar, PETSC_DRAWBAR_CLASSID, 1); 302 bar->ymin = y_min; 303 bar->ymax = y_max; 304 PetscFunctionReturn(0); 305 } 306 307 /*@C 308 PetscDrawBarGetAxis - Gets the axis context associated with a bar graph. 309 This is useful if one wants to change some axis property, such as 310 labels, color, etc. The axis context should not be destroyed by the 311 application code. 312 313 Not Collective, axis is parallel if bar is parallel 314 315 Input Parameter: 316 . bar - The bar graph context 317 318 Output Parameter: 319 . axis - The axis context 320 321 Level: intermediate 322 323 .seealso: `PetscDrawBar`, `PetscDrawBarCreate()`, `PetscDrawBar`, `PetscDrawAxis`, `PetscDrawAxisCreate()` 324 @*/ 325 PetscErrorCode PetscDrawBarGetAxis(PetscDrawBar bar, PetscDrawAxis *axis) { 326 PetscFunctionBegin; 327 PetscValidHeaderSpecific(bar, PETSC_DRAWBAR_CLASSID, 1); 328 PetscValidPointer(axis, 2); 329 *axis = bar->axis; 330 PetscFunctionReturn(0); 331 } 332 333 /*@C 334 PetscDrawBarGetDraw - Gets the draw context associated with a bar graph. 335 336 Not Collective, draw is parallel if bar is parallel 337 338 Input Parameter: 339 . bar - The bar graph context 340 341 Output Parameter: 342 . draw - The draw context 343 344 Level: intermediate 345 346 .seealso: `PetscDrawBar`, `PetscDraw`, `PetscDrawBarCreate()`, `PetscDrawBar`, `PetscDrawBarDraw()`, `PetscDraw` 347 @*/ 348 PetscErrorCode PetscDrawBarGetDraw(PetscDrawBar bar, PetscDraw *draw) { 349 PetscFunctionBegin; 350 PetscValidHeaderSpecific(bar, PETSC_DRAWBAR_CLASSID, 1); 351 PetscValidPointer(draw, 2); 352 *draw = bar->win; 353 PetscFunctionReturn(0); 354 } 355 356 /*@ 357 PetscDrawBarSetFromOptions - Sets options related to the display of the `PetscDrawBar` 358 359 Collective over bar 360 361 Options Database Key: 362 . -bar_sort - sort the entries before drawing the bar graph 363 364 Level: intermediate 365 366 Note: 367 Does not set options related to the underlying `PetscDraw` or `PetscDrawAxis` 368 369 .seealso: `PetscDrawBar`, `PetscDrawBarDestroy()`, `PetscDrawBarCreate()`, `PetscDrawBarSort()` 370 @*/ 371 PetscErrorCode PetscDrawBarSetFromOptions(PetscDrawBar bar) { 372 PetscBool set; 373 374 PetscFunctionBegin; 375 PetscValidHeaderSpecific(bar, PETSC_DRAWBAR_CLASSID, 1); 376 377 PetscCall(PetscOptionsHasName(((PetscObject)bar)->options, ((PetscObject)bar)->prefix, "-bar_sort", &set)); 378 if (set) { 379 PetscReal tol = bar->sorttolerance; 380 PetscCall(PetscOptionsGetReal(((PetscObject)bar)->options, ((PetscObject)bar)->prefix, "-bar_sort", &tol, NULL)); 381 PetscCall(PetscDrawBarSort(bar, PETSC_TRUE, tol)); 382 } 383 PetscFunctionReturn(0); 384 } 385