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 PetscCall(PetscLogObjectParent((PetscObject)draw, (PetscObject)h)); 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(0); 61 } 62 63 /*@C 64 PetscDrawBarSetData 65 66 Logically Collective on bar 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 PetscFunctionBegin; 85 PetscValidHeaderSpecific(bar, PETSC_DRAWBAR_CLASSID, 1); 86 87 if (bar->numBins != bins) { 88 PetscCall(PetscFree(bar->values)); 89 PetscCall(PetscMalloc1(bins, &bar->values)); 90 bar->numBins = bins; 91 } 92 PetscCall(PetscArraycpy(bar->values, data, bins)); 93 bar->numBins = bins; 94 if (labels) PetscCall(PetscStrArrayallocpy(labels, &bar->labels)); 95 PetscFunctionReturn(0); 96 } 97 98 /*@C 99 PetscDrawBarDestroy - Frees all space taken up by bar graph data structure. 100 101 Collective over bar 102 103 Input Parameter: 104 . bar - The bar graph context 105 106 Level: intermediate 107 108 .seealso: `PetscDrawBar`, `PetscDrawBarCreate()` 109 @*/ 110 PetscErrorCode PetscDrawBarDestroy(PetscDrawBar *bar) { 111 PetscFunctionBegin; 112 if (!*bar) PetscFunctionReturn(0); 113 PetscValidHeaderSpecific(*bar, PETSC_DRAWBAR_CLASSID, 1); 114 if (--((PetscObject)(*bar))->refct > 0) PetscFunctionReturn(0); 115 116 PetscCall(PetscFree((*bar)->values)); 117 PetscCall(PetscStrArrayDestroy(&(*bar)->labels)); 118 PetscCall(PetscDrawAxisDestroy(&(*bar)->axis)); 119 PetscCall(PetscDrawDestroy(&(*bar)->win)); 120 PetscCall(PetscHeaderDestroy(bar)); 121 PetscFunctionReturn(0); 122 } 123 124 /*@ 125 PetscDrawBarDraw - Redraws a bar graph. 126 127 Collective on bar 128 129 Input Parameter: 130 . bar - The bar graph context 131 132 Level: intermediate 133 134 .seealso: `PetscDrawBar`, `PetscDrawBarCreate()`, `PetscDrawBarSetData()` 135 @*/ 136 PetscErrorCode PetscDrawBarDraw(PetscDrawBar bar) { 137 PetscDraw draw; 138 PetscBool isnull; 139 PetscReal xmin, xmax, ymin, ymax, *values, binLeft, binRight; 140 PetscInt numValues, i, bcolor, color, idx, *perm, nplot; 141 PetscMPIInt rank; 142 char **labels; 143 144 PetscFunctionBegin; 145 PetscValidHeaderSpecific(bar, PETSC_DRAWBAR_CLASSID, 1); 146 PetscCall(PetscDrawIsNull(bar->win, &isnull)); 147 if (isnull) PetscFunctionReturn(0); 148 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)bar), &rank)); 149 150 if (bar->numBins < 1) PetscFunctionReturn(0); 151 152 color = bar->color; 153 if (color == PETSC_DRAW_ROTATE) bcolor = PETSC_DRAW_BLACK + 1; 154 else bcolor = color; 155 156 numValues = bar->numBins; 157 values = bar->values; 158 if (bar->ymin == bar->ymax) { 159 /* user has not set bounds on bars so set them based on the data */ 160 ymin = PETSC_MAX_REAL; 161 ymax = PETSC_MIN_REAL; 162 for (i = 0; i < numValues; i++) { 163 ymin = PetscMin(ymin, values[i]); 164 ymax = PetscMax(ymax, values[i]); 165 } 166 } else { 167 ymin = bar->ymin; 168 ymax = bar->ymax; 169 } 170 nplot = numValues; /* number of points to actually plot; if some are lower than requested tolerance */ 171 xmin = 0.0; 172 xmax = nplot; 173 labels = bar->labels; 174 175 if (bar->sort) { 176 PetscCall(PetscMalloc1(numValues, &perm)); 177 for (i = 0; i < numValues; i++) perm[i] = i; 178 PetscCall(PetscSortRealWithPermutation(numValues, values, perm)); 179 if (bar->sorttolerance) { 180 for (i = 0; i < numValues; i++) { 181 if (values[perm[numValues - i - 1]] < bar->sorttolerance) { 182 nplot = i; 183 break; 184 } 185 } 186 } 187 } 188 189 draw = bar->win; 190 PetscCall(PetscDrawCheckResizedWindow(draw)); 191 PetscCall(PetscDrawClear(draw)); 192 193 PetscCall(PetscDrawAxisSetLimits(bar->axis, xmin, xmax, ymin, ymax)); 194 PetscCall(PetscDrawAxisDraw(bar->axis)); 195 196 PetscDrawCollectiveBegin(draw); 197 if (rank == 0) { /* Draw bins */ 198 for (i = 0; i < nplot; i++) { 199 idx = (bar->sort ? perm[numValues - i - 1] : i); 200 binLeft = xmin + i; 201 binRight = xmin + i + 1; 202 PetscCall(PetscDrawRectangle(draw, binLeft, ymin, binRight, values[idx], bcolor, bcolor, bcolor, bcolor)); 203 PetscCall(PetscDrawLine(draw, binLeft, ymin, binLeft, values[idx], PETSC_DRAW_BLACK)); 204 PetscCall(PetscDrawLine(draw, binRight, ymin, binRight, values[idx], PETSC_DRAW_BLACK)); 205 PetscCall(PetscDrawLine(draw, binLeft, values[idx], binRight, values[idx], PETSC_DRAW_BLACK)); 206 if (labels) { 207 PetscReal h; 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(0); 221 } 222 223 /*@ 224 PetscDrawBarSave - Saves a drawn bar graph 225 226 Collective on bar 227 228 Input Parameters: 229 . bar - The bar graph context 230 231 Level: intermediate 232 233 .seealso: `PetscDrawSave()`, `PetscDrawBar`, `PetscDrawBarCreate()`, `PetscDrawBarGetDraw()`, `PetscDrawSetSave()`, `PetscDrawSave()`, `PetscDrawBarSetData()` 234 @*/ 235 PetscErrorCode PetscDrawBarSave(PetscDrawBar bar) { 236 PetscFunctionBegin; 237 PetscValidHeaderSpecific(bar, PETSC_DRAWBAR_CLASSID, 1); 238 PetscCall(PetscDrawSave(bar->win)); 239 PetscFunctionReturn(0); 240 } 241 242 /*@ 243 PetscDrawBarSetColor - Sets the color the bars will be drawn with. 244 245 Logically Collective on bar 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 PetscFunctionBegin; 258 PetscValidHeaderSpecific(bar, PETSC_DRAWBAR_CLASSID, 1); 259 bar->color = color; 260 PetscFunctionReturn(0); 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 on bar 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()`, `PetscDrawBar`, `PetscDrawBarSetData()`, `PetscDrawBarSetColor()`, `PetscDrawBarDraw()`, `PetscDrawBarGetAxis()` 276 @*/ 277 PetscErrorCode PetscDrawBarSort(PetscDrawBar bar, PetscBool sort, PetscReal tolerance) { 278 PetscFunctionBegin; 279 PetscValidHeaderSpecific(bar, PETSC_DRAWBAR_CLASSID, 1); 280 bar->sort = sort; 281 bar->sorttolerance = tolerance; 282 PetscFunctionReturn(0); 283 } 284 285 /*@ 286 PetscDrawBarSetLimits - Sets the axis limits for a bar graph. If more 287 points are added after this call, the limits will be adjusted to 288 include those additional points. 289 290 Logically Collective on bar 291 292 Input Parameters: 293 + bar - The bar graph context 294 - y_min,y_max - The limits 295 296 Level: intermediate 297 298 .seealso: `PetscDrawBar`, `PetscDrawBarCreate()`, `PetscDrawBar`, `PetscDrawBarGetAxis()`, `PetscDrawBarSetData()`, `PetscDrawBarDraw()` 299 @*/ 300 PetscErrorCode PetscDrawBarSetLimits(PetscDrawBar bar, PetscReal y_min, PetscReal y_max) { 301 PetscFunctionBegin; 302 PetscValidHeaderSpecific(bar, PETSC_DRAWBAR_CLASSID, 1); 303 bar->ymin = y_min; 304 bar->ymax = y_max; 305 PetscFunctionReturn(0); 306 } 307 308 /*@C 309 PetscDrawBarGetAxis - Gets the axis context associated with a bar graph. 310 This is useful if one wants to change some axis property, such as 311 labels, color, etc. The axis context should not be destroyed by the 312 application code. 313 314 Not Collective, axis is parallel if bar is parallel 315 316 Input Parameter: 317 . bar - The bar graph context 318 319 Output Parameter: 320 . axis - The axis context 321 322 Level: intermediate 323 324 .seealso: `PetscDrawBar`, `PetscDrawBarCreate()`, `PetscDrawBar`, `PetscDrawAxis`, `PetscDrawAxisCreate()` 325 @*/ 326 PetscErrorCode PetscDrawBarGetAxis(PetscDrawBar bar, PetscDrawAxis *axis) { 327 PetscFunctionBegin; 328 PetscValidHeaderSpecific(bar, PETSC_DRAWBAR_CLASSID, 1); 329 PetscValidPointer(axis, 2); 330 *axis = bar->axis; 331 PetscFunctionReturn(0); 332 } 333 334 /*@C 335 PetscDrawBarGetDraw - Gets the draw context associated with a bar graph. 336 337 Not Collective, draw is parallel if bar is parallel 338 339 Input Parameter: 340 . bar - The bar graph context 341 342 Output Parameter: 343 . draw - The draw context 344 345 Level: intermediate 346 347 .seealso: `PetscDrawBar`, `PetscDraw`, `PetscDrawBarCreate()`, `PetscDrawBar`, `PetscDrawBarDraw()`, `PetscDraw` 348 @*/ 349 PetscErrorCode PetscDrawBarGetDraw(PetscDrawBar bar, PetscDraw *draw) { 350 PetscFunctionBegin; 351 PetscValidHeaderSpecific(bar, PETSC_DRAWBAR_CLASSID, 1); 352 PetscValidPointer(draw, 2); 353 *draw = bar->win; 354 PetscFunctionReturn(0); 355 } 356 357 /*@ 358 PetscDrawBarSetFromOptions - Sets options related to the display of the `PetscDrawBar` 359 360 Collective over bar 361 362 Options Database Key: 363 . -bar_sort - sort the entries before drawing the bar graph 364 365 Level: intermediate 366 367 Note: 368 Does not set options related to the underlying `PetscDraw` or `PetscDrawAxis` 369 370 .seealso: `PetscDrawBar`, `PetscDrawBarDestroy()`, `PetscDrawBarCreate()`, `PetscDrawBarSort()` 371 @*/ 372 PetscErrorCode PetscDrawBarSetFromOptions(PetscDrawBar bar) { 373 PetscBool set; 374 375 PetscFunctionBegin; 376 PetscValidHeaderSpecific(bar, PETSC_DRAWBAR_CLASSID, 1); 377 378 PetscCall(PetscOptionsHasName(((PetscObject)bar)->options, ((PetscObject)bar)->prefix, "-bar_sort", &set)); 379 if (set) { 380 PetscReal tol = bar->sorttolerance; 381 PetscCall(PetscOptionsGetReal(((PetscObject)bar)->options, ((PetscObject)bar)->prefix, "-bar_sort", &tol, NULL)); 382 PetscCall(PetscDrawBarSort(bar, PETSC_TRUE, tol)); 383 } 384 PetscFunctionReturn(0); 385 } 386