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 PetscDraw 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 process in the communicator. All MPI processes in the communicator must call PetscDrawBarDraw() to display the updated graph. 29 30 Level: intermediate 31 32 .seealso: `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 PetscDrawBar 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 .seealso: `PetscDrawBarCreate()`, `PetscDrawBar`, `PetscDrawBarDraw()` 80 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 PetscDrawBar 101 102 Input Parameter: 103 . bar - The bar graph context 104 105 Level: intermediate 106 107 .seealso: `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 PetscDrawBar 127 128 Input Parameter: 129 . bar - The bar graph context 130 131 Level: intermediate 132 133 .seealso: `PetscDrawBar`, `PetscDrawBarCreate()`, `PetscDrawBarSetData()` 134 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 image 225 226 Collective on PetscDrawBar 227 228 Input Parameters: 229 . bar - The bar graph context 230 231 Level: intermediate 232 233 .seealso: `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 PetscDrawBar 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 @*/ 257 PetscErrorCode PetscDrawBarSetColor(PetscDrawBar bar, int color) { 258 PetscFunctionBegin; 259 PetscValidHeaderSpecific(bar, PETSC_DRAWBAR_CLASSID, 1); 260 bar->color = color; 261 PetscFunctionReturn(0); 262 } 263 264 /*@ 265 PetscDrawBarSort - Sorts the values before drawing the bar chart 266 267 Logically Collective on PetscDrawBar 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: `PetscDrawBarCreate()`, `PetscDrawBar`, `PetscDrawBarSetData()`, `PetscDrawBarSetColor()`, `PetscDrawBarDraw()`, `PetscDrawBarGetAxis()` 277 @*/ 278 PetscErrorCode PetscDrawBarSort(PetscDrawBar bar, PetscBool sort, PetscReal tolerance) { 279 PetscFunctionBegin; 280 PetscValidHeaderSpecific(bar, PETSC_DRAWBAR_CLASSID, 1); 281 bar->sort = sort; 282 bar->sorttolerance = tolerance; 283 PetscFunctionReturn(0); 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 on PetscDrawBar 292 293 Input Parameters: 294 + bar - The bar graph context 295 - y_min,y_max - The limits 296 297 Level: intermediate 298 299 .seealso: `PetscDrawBarCreate()`, `PetscDrawBar`, `PetscDrawBarGetAxis()`, `PetscDrawBarSetData()`, `PetscDrawBarDraw()` 300 @*/ 301 PetscErrorCode PetscDrawBarSetLimits(PetscDrawBar bar, PetscReal y_min, PetscReal y_max) { 302 PetscFunctionBegin; 303 PetscValidHeaderSpecific(bar, PETSC_DRAWBAR_CLASSID, 1); 304 bar->ymin = y_min; 305 bar->ymax = y_max; 306 PetscFunctionReturn(0); 307 } 308 309 /*@C 310 PetscDrawBarGetAxis - Gets the axis context associated with a bar graph. 311 This is useful if one wants to change some axis property, such as 312 labels, color, etc. The axis context should not be destroyed by the 313 application code. 314 315 Not Collective, PetscDrawAxis is parallel if PetscDrawBar is parallel 316 317 Input Parameter: 318 . bar - The bar graph context 319 320 Output Parameter: 321 . axis - The axis context 322 323 Level: intermediate 324 325 .seealso: `PetscDrawBarCreate()`, `PetscDrawBar`, `PetscDrawAxis`, `PetscDrawAxisCreate()` 326 @*/ 327 PetscErrorCode PetscDrawBarGetAxis(PetscDrawBar bar, PetscDrawAxis *axis) { 328 PetscFunctionBegin; 329 PetscValidHeaderSpecific(bar, PETSC_DRAWBAR_CLASSID, 1); 330 PetscValidPointer(axis, 2); 331 *axis = bar->axis; 332 PetscFunctionReturn(0); 333 } 334 335 /*@C 336 PetscDrawBarGetDraw - Gets the draw context associated with a bar graph. 337 338 Not Collective, PetscDraw is parallel if PetscDrawBar is parallel 339 340 Input Parameter: 341 . bar - The bar graph context 342 343 Output Parameter: 344 . draw - The draw context 345 346 Level: intermediate 347 348 .seealso: `PetscDrawBarCreate()`, `PetscDrawBar`, `PetscDrawBarDraw()`, `PetscDraw` 349 @*/ 350 PetscErrorCode PetscDrawBarGetDraw(PetscDrawBar bar, PetscDraw *draw) { 351 PetscFunctionBegin; 352 PetscValidHeaderSpecific(bar, PETSC_DRAWBAR_CLASSID, 1); 353 PetscValidPointer(draw, 2); 354 *draw = bar->win; 355 PetscFunctionReturn(0); 356 } 357 358 /*@ 359 PetscDrawBarSetFromOptions - Sets options related to the PetscDrawBar 360 361 Collective over PetscDrawBar 362 363 Options Database: 364 . -bar_sort - sort the entries before drawing the bar graph 365 366 Level: intermediate 367 368 .seealso: `PetscDrawBarDestroy()`, `PetscDrawBarCreate()`, `PetscDrawBarSort()` 369 @*/ 370 PetscErrorCode PetscDrawBarSetFromOptions(PetscDrawBar bar) { 371 PetscBool set; 372 373 PetscFunctionBegin; 374 PetscValidHeaderSpecific(bar, PETSC_DRAWBAR_CLASSID, 1); 375 376 PetscCall(PetscOptionsHasName(((PetscObject)bar)->options, ((PetscObject)bar)->prefix, "-bar_sort", &set)); 377 if (set) { 378 PetscReal tol = bar->sorttolerance; 379 PetscCall(PetscOptionsGetReal(((PetscObject)bar)->options, ((PetscObject)bar)->prefix, "-bar_sort", &tol, NULL)); 380 PetscCall(PetscDrawBarSort(bar, PETSC_TRUE, tol)); 381 } 382 PetscFunctionReturn(0); 383 } 384