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 { 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 PetscCall(PetscLogObjectParent((PetscObject)draw,(PetscObject)h)); 46 47 PetscCall(PetscObjectReference((PetscObject)draw)); 48 h->win = draw; 49 50 h->view = NULL; 51 h->destroy = NULL; 52 h->color = PETSC_DRAW_GREEN; 53 h->ymin = 0.; /* if user has not set these then they are determined from the data */ 54 h->ymax = 0.; 55 h->numBins = 0; 56 57 PetscCall(PetscDrawAxisCreate(draw,&h->axis)); 58 h->axis->xticks = NULL; 59 60 *bar = h; 61 PetscFunctionReturn(0); 62 } 63 64 /*@C 65 PetscDrawBarSetData 66 67 Logically Collective on PetscDrawBar 68 69 Input Parameters: 70 + bar - The bar graph context. 71 . bins - number of items 72 . values - values of each item 73 - labels - optional label for each bar, NULL terminated array of strings 74 75 Level: intermediate 76 77 Notes: 78 Call PetscDrawBarDraw() after this call to display the new plot 79 80 .seealso: `PetscDrawBarCreate()`, `PetscDrawBar`, `PetscDrawBarDraw()` 81 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) { 96 PetscCall(PetscStrArrayallocpy(labels,&bar->labels)); 97 } 98 PetscFunctionReturn(0); 99 } 100 101 /*@C 102 PetscDrawBarDestroy - Frees all space taken up by bar graph data structure. 103 104 Collective over PetscDrawBar 105 106 Input Parameter: 107 . bar - The bar graph context 108 109 Level: intermediate 110 111 .seealso: `PetscDrawBarCreate()` 112 @*/ 113 PetscErrorCode PetscDrawBarDestroy(PetscDrawBar *bar) 114 { 115 PetscFunctionBegin; 116 if (!*bar) PetscFunctionReturn(0); 117 PetscValidHeaderSpecific(*bar,PETSC_DRAWBAR_CLASSID,1); 118 if (--((PetscObject)(*bar))->refct > 0) PetscFunctionReturn(0); 119 120 PetscCall(PetscFree((*bar)->values)); 121 PetscCall(PetscStrArrayDestroy(&(*bar)->labels)); 122 PetscCall(PetscDrawAxisDestroy(&(*bar)->axis)); 123 PetscCall(PetscDrawDestroy(&(*bar)->win)); 124 PetscCall(PetscHeaderDestroy(bar)); 125 PetscFunctionReturn(0); 126 } 127 128 /*@ 129 PetscDrawBarDraw - Redraws a bar graph. 130 131 Collective on PetscDrawBar 132 133 Input Parameter: 134 . bar - The bar graph context 135 136 Level: intermediate 137 138 .seealso: `PetscDrawBar`, `PetscDrawBarCreate()`, `PetscDrawBarSetData()` 139 140 @*/ 141 PetscErrorCode PetscDrawBarDraw(PetscDrawBar bar) 142 { 143 PetscDraw draw; 144 PetscBool isnull; 145 PetscReal xmin,xmax,ymin,ymax,*values,binLeft,binRight; 146 PetscInt numValues,i,bcolor,color,idx,*perm,nplot; 147 PetscMPIInt rank; 148 char **labels; 149 150 PetscFunctionBegin; 151 PetscValidHeaderSpecific(bar,PETSC_DRAWBAR_CLASSID,1); 152 PetscCall(PetscDrawIsNull(bar->win,&isnull)); 153 if (isnull) PetscFunctionReturn(0); 154 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)bar),&rank)); 155 156 if (bar->numBins < 1) PetscFunctionReturn(0); 157 158 color = bar->color; 159 if (color == PETSC_DRAW_ROTATE) bcolor = PETSC_DRAW_BLACK+1; 160 else bcolor = color; 161 162 numValues = bar->numBins; 163 values = bar->values; 164 if (bar->ymin == bar->ymax) { 165 /* user has not set bounds on bars so set them based on the data */ 166 ymin = PETSC_MAX_REAL; 167 ymax = PETSC_MIN_REAL; 168 for (i=0; i<numValues; i++) { 169 ymin = PetscMin(ymin,values[i]); 170 ymax = PetscMax(ymax,values[i]); 171 } 172 } else { 173 ymin = bar->ymin; 174 ymax = bar->ymax; 175 } 176 nplot = numValues; /* number of points to actually plot; if some are lower than requested tolerance */ 177 xmin = 0.0; 178 xmax = nplot; 179 labels = bar->labels; 180 181 if (bar->sort) { 182 PetscCall(PetscMalloc1(numValues,&perm)); 183 for (i=0; i<numValues;i++) perm[i] = i; 184 PetscCall(PetscSortRealWithPermutation(numValues,values,perm)); 185 if (bar->sorttolerance) { 186 for (i=0; i<numValues;i++) { 187 if (values[perm[numValues - i - 1]] < bar->sorttolerance) { 188 nplot = i; 189 break; 190 } 191 } 192 } 193 } 194 195 draw = bar->win; 196 PetscCall(PetscDrawCheckResizedWindow(draw)); 197 PetscCall(PetscDrawClear(draw)); 198 199 PetscCall(PetscDrawAxisSetLimits(bar->axis,xmin,xmax,ymin,ymax)); 200 PetscCall(PetscDrawAxisDraw(bar->axis)); 201 202 PetscDrawCollectiveBegin(draw); 203 if (rank == 0) { /* Draw bins */ 204 for (i=0; i<nplot; i++) { 205 idx = (bar->sort ? perm[numValues - i - 1] : i); 206 binLeft = xmin + i; 207 binRight = xmin + i + 1; 208 PetscCall(PetscDrawRectangle(draw,binLeft,ymin,binRight,values[idx],bcolor,bcolor,bcolor,bcolor)); 209 PetscCall(PetscDrawLine(draw,binLeft,ymin,binLeft,values[idx],PETSC_DRAW_BLACK)); 210 PetscCall(PetscDrawLine(draw,binRight,ymin,binRight,values[idx],PETSC_DRAW_BLACK)); 211 PetscCall(PetscDrawLine(draw,binLeft,values[idx],binRight,values[idx],PETSC_DRAW_BLACK)); 212 if (labels) { 213 PetscReal h; 214 PetscCall(PetscDrawStringGetSize(draw,NULL,&h)); 215 PetscCall(PetscDrawStringCentered(draw,.5*(binLeft+binRight),ymin - 1.5*h,bcolor,labels[idx])); 216 } 217 if (color == PETSC_DRAW_ROTATE) bcolor++; 218 if (bcolor > PETSC_DRAW_BASIC_COLORS-1) bcolor = PETSC_DRAW_BLACK+1; 219 } 220 } 221 PetscDrawCollectiveEnd(draw); 222 if (bar->sort) PetscCall(PetscFree(perm)); 223 224 PetscCall(PetscDrawFlush(draw)); 225 PetscCall(PetscDrawPause(draw)); 226 PetscFunctionReturn(0); 227 } 228 229 /*@ 230 PetscDrawBarSave - Saves a drawn image 231 232 Collective on PetscDrawBar 233 234 Input Parameters: 235 . bar - The bar graph context 236 237 Level: intermediate 238 239 .seealso: `PetscDrawBarCreate()`, `PetscDrawBarGetDraw()`, `PetscDrawSetSave()`, `PetscDrawSave()`, `PetscDrawBarSetData()` 240 @*/ 241 PetscErrorCode PetscDrawBarSave(PetscDrawBar bar) 242 { 243 PetscFunctionBegin; 244 PetscValidHeaderSpecific(bar,PETSC_DRAWBAR_CLASSID,1); 245 PetscCall(PetscDrawSave(bar->win)); 246 PetscFunctionReturn(0); 247 } 248 249 /*@ 250 PetscDrawBarSetColor - Sets the color the bars will be drawn with. 251 252 Logically Collective on PetscDrawBar 253 254 Input Parameters: 255 + bar - The bar graph context 256 - color - one of the colors defined in petscdraw.h or PETSC_DRAW_ROTATE to make each bar a 257 different color 258 259 Level: intermediate 260 261 .seealso: `PetscDrawBarCreate()`, `PetscDrawBar`, `PetscDrawBarSetData()`, `PetscDrawBarDraw()`, `PetscDrawBarGetAxis()` 262 263 @*/ 264 PetscErrorCode PetscDrawBarSetColor(PetscDrawBar bar, int color) 265 { 266 PetscFunctionBegin; 267 PetscValidHeaderSpecific(bar, PETSC_DRAWBAR_CLASSID,1); 268 bar->color = color; 269 PetscFunctionReturn(0); 270 } 271 272 /*@ 273 PetscDrawBarSort - Sorts the values before drawing the bar chart 274 275 Logically Collective on PetscDrawBar 276 277 Input Parameters: 278 + bar - The bar graph context 279 . sort - PETSC_TRUE to sort the values 280 - tolerance - discard values less than tolerance 281 282 Level: intermediate 283 284 .seealso: `PetscDrawBarCreate()`, `PetscDrawBar`, `PetscDrawBarSetData()`, `PetscDrawBarSetColor()`, `PetscDrawBarDraw()`, `PetscDrawBarGetAxis()` 285 @*/ 286 PetscErrorCode PetscDrawBarSort(PetscDrawBar bar, PetscBool sort, PetscReal tolerance) 287 { 288 PetscFunctionBegin; 289 PetscValidHeaderSpecific(bar,PETSC_DRAWBAR_CLASSID,1); 290 bar->sort = sort; 291 bar->sorttolerance = tolerance; 292 PetscFunctionReturn(0); 293 } 294 295 /*@ 296 PetscDrawBarSetLimits - Sets the axis limits for a bar graph. If more 297 points are added after this call, the limits will be adjusted to 298 include those additional points. 299 300 Logically Collective on PetscDrawBar 301 302 Input Parameters: 303 + bar - The bar graph context 304 - y_min,y_max - The limits 305 306 Level: intermediate 307 308 .seealso: `PetscDrawBarCreate()`, `PetscDrawBar`, `PetscDrawBarGetAxis()`, `PetscDrawBarSetData()`, `PetscDrawBarDraw()` 309 @*/ 310 PetscErrorCode PetscDrawBarSetLimits(PetscDrawBar bar, PetscReal y_min, PetscReal y_max) 311 { 312 PetscFunctionBegin; 313 PetscValidHeaderSpecific(bar,PETSC_DRAWBAR_CLASSID,1); 314 bar->ymin = y_min; 315 bar->ymax = y_max; 316 PetscFunctionReturn(0); 317 } 318 319 /*@C 320 PetscDrawBarGetAxis - Gets the axis context associated with a bar graph. 321 This is useful if one wants to change some axis property, such as 322 labels, color, etc. The axis context should not be destroyed by the 323 application code. 324 325 Not Collective, PetscDrawAxis is parallel if PetscDrawBar is parallel 326 327 Input Parameter: 328 . bar - The bar graph context 329 330 Output Parameter: 331 . axis - The axis context 332 333 Level: intermediate 334 335 .seealso: `PetscDrawBarCreate()`, `PetscDrawBar`, `PetscDrawAxis`, `PetscDrawAxisCreate()` 336 @*/ 337 PetscErrorCode PetscDrawBarGetAxis(PetscDrawBar bar,PetscDrawAxis *axis) 338 { 339 PetscFunctionBegin; 340 PetscValidHeaderSpecific(bar,PETSC_DRAWBAR_CLASSID,1); 341 PetscValidPointer(axis,2); 342 *axis = bar->axis; 343 PetscFunctionReturn(0); 344 } 345 346 /*@C 347 PetscDrawBarGetDraw - Gets the draw context associated with a bar graph. 348 349 Not Collective, PetscDraw is parallel if PetscDrawBar is parallel 350 351 Input Parameter: 352 . bar - The bar graph context 353 354 Output Parameter: 355 . draw - The draw context 356 357 Level: intermediate 358 359 .seealso: `PetscDrawBarCreate()`, `PetscDrawBar`, `PetscDrawBarDraw()`, `PetscDraw` 360 @*/ 361 PetscErrorCode PetscDrawBarGetDraw(PetscDrawBar bar,PetscDraw *draw) 362 { 363 PetscFunctionBegin; 364 PetscValidHeaderSpecific(bar,PETSC_DRAWBAR_CLASSID,1); 365 PetscValidPointer(draw,2); 366 *draw = bar->win; 367 PetscFunctionReturn(0); 368 } 369 370 /*@ 371 PetscDrawBarSetFromOptions - Sets options related to the PetscDrawBar 372 373 Collective over PetscDrawBar 374 375 Options Database: 376 . -bar_sort - sort the entries before drawing the bar graph 377 378 Level: intermediate 379 380 .seealso: `PetscDrawBarDestroy()`, `PetscDrawBarCreate()`, `PetscDrawBarSort()` 381 @*/ 382 PetscErrorCode PetscDrawBarSetFromOptions(PetscDrawBar bar) 383 { 384 PetscBool set; 385 386 PetscFunctionBegin; 387 PetscValidHeaderSpecific(bar,PETSC_DRAWBAR_CLASSID,1); 388 389 PetscCall(PetscOptionsHasName(((PetscObject)bar)->options,((PetscObject)bar)->prefix,"-bar_sort",&set)); 390 if (set) { 391 PetscReal tol = bar->sorttolerance; 392 PetscCall(PetscOptionsGetReal(((PetscObject)bar)->options,((PetscObject)bar)->prefix,"-bar_sort",&tol,NULL)); 393 PetscCall(PetscDrawBarSort(bar,PETSC_TRUE,tol)); 394 } 395 PetscFunctionReturn(0); 396 } 397