1 2 /* 3 Contains the data structure for plotting a bargraph in a window with an axis. 4 */ 5 #include <petscdraw.h> /*I "petscdraw.h" I*/ 6 #include <petsc/private/petscimpl.h> /*I "petscsys.h" I*/ 7 #include <petscviewer.h> /*I "petscviewer.h" I*/ 8 #include <../src/sys/classes/draw/utils/axisimpl.h> /* so we can directly modify axis xticks */ 9 10 PetscClassId PETSC_DRAWBAR_CLASSID = 0; 11 12 struct _p_PetscDrawBar { 13 PETSCHEADER(int); 14 PetscErrorCode (*destroy)(PetscDrawSP); 15 PetscErrorCode (*view)(PetscDrawSP,PetscViewer); 16 PetscDraw win; 17 PetscDrawAxis axis; 18 PetscReal ymin,ymax; 19 int numBins; 20 PetscReal *values; 21 int color; 22 char **labels; 23 PetscBool sort; 24 PetscReal sorttolerance; 25 }; 26 27 #define CHUNKSIZE 100 28 29 /*@C 30 PetscDrawBarCreate - Creates a bar graph data structure. 31 32 Collective over PetscDraw 33 34 Input Parameters: 35 . draw - The window where the graph will be made 36 37 Output Parameters: 38 . bar - The bar graph context 39 40 Notes: 41 Call PetscDrawBarSetData() to provide the bins to be plotted and then PetscDrawBarDraw() to display the new plot 42 43 The difference between a bar chart, PetscDrawBar, and a histogram, PetscDrawHG, is explained here https://stattrek.com/statistics/charts/histogram.aspx?Tutorial=AP 44 45 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 46 zeroth MPI process in the communicator. All MPI processes in the communicator must call PetscDrawBarDraw() to display the updated graph. 47 48 Level: intermediate 49 50 .seealso: PetscDrawLGCreate(), PetscDrawLG, PetscDrawSPCreate(), PetscDrawSP, PetscDrawHGCreate(), PetscDrawHG, PetscDrawBarDestroy(), PetscDrawBarSetData(), 51 PetscDrawBar, PetscDrawBarDraw(), PetscDrawBarSave(), PetscDrawBarSetColor(), PetscDrawBarSort(), PetscDrawBarSetLimits(), PetscDrawBarGetAxis(), PetscDrawAxis, 52 PetscDrawBarGetDraw(), PetscDrawBarSetFromOptions() 53 @*/ 54 PetscErrorCode PetscDrawBarCreate(PetscDraw draw,PetscDrawBar *bar) 55 { 56 PetscDrawBar h; 57 PetscErrorCode ierr; 58 59 PetscFunctionBegin; 60 PetscValidHeaderSpecific(draw,PETSC_DRAW_CLASSID,1); 61 PetscValidPointer(bar,2); 62 63 ierr = PetscHeaderCreate(h,PETSC_DRAWBAR_CLASSID,"DrawBar","Bar Graph","Draw",PetscObjectComm((PetscObject)draw),PetscDrawBarDestroy,NULL);CHKERRQ(ierr); 64 ierr = PetscLogObjectParent((PetscObject)draw,(PetscObject)h);CHKERRQ(ierr); 65 66 ierr = PetscObjectReference((PetscObject)draw);CHKERRQ(ierr); 67 h->win = draw; 68 69 h->view = NULL; 70 h->destroy = NULL; 71 h->color = PETSC_DRAW_GREEN; 72 h->ymin = 0.; /* if user has not set these then they are determined from the data */ 73 h->ymax = 0.; 74 h->numBins = 0; 75 76 ierr = PetscDrawAxisCreate(draw,&h->axis);CHKERRQ(ierr); 77 h->axis->xticks = NULL; 78 79 *bar = h; 80 PetscFunctionReturn(0); 81 } 82 83 /*@C 84 PetscDrawBarSetData 85 86 Logically Collective on PetscDrawBar 87 88 Input Parameter: 89 + bar - The bar graph context. 90 . bins - number of items 91 . values - values of each item 92 - labels - optional label for each bar, NULL terminated array of strings 93 94 Level: intermediate 95 96 Notes: 97 Call PetscDrawBarDraw() after this call to display the new plot 98 99 .seealso: PetscDrawBarCreate(), PetscDrawBar, PetscDrawBarDraw() 100 101 @*/ 102 PetscErrorCode PetscDrawBarSetData(PetscDrawBar bar,PetscInt bins,const PetscReal data[],const char *const *labels) 103 { 104 PetscErrorCode ierr; 105 106 PetscFunctionBegin; 107 PetscValidHeaderSpecific(bar,PETSC_DRAWBAR_CLASSID,1); 108 109 if (bar->numBins != bins) { 110 ierr = PetscFree(bar->values);CHKERRQ(ierr); 111 ierr = PetscMalloc1(bins, &bar->values);CHKERRQ(ierr); 112 bar->numBins = bins; 113 } 114 ierr = PetscArraycpy(bar->values,data,bins);CHKERRQ(ierr); 115 bar->numBins = bins; 116 if (labels) { 117 ierr = PetscStrArrayallocpy(labels,&bar->labels);CHKERRQ(ierr); 118 } 119 PetscFunctionReturn(0); 120 } 121 122 /*@C 123 PetscDrawBarDestroy - Frees all space taken up by bar graph data structure. 124 125 Collective over PetscDrawBar 126 127 Input Parameter: 128 . bar - The bar graph context 129 130 Level: intermediate 131 132 .seealso: PetscDrawBarCreate() 133 @*/ 134 PetscErrorCode PetscDrawBarDestroy(PetscDrawBar *bar) 135 { 136 PetscErrorCode ierr; 137 138 PetscFunctionBegin; 139 if (!*bar) PetscFunctionReturn(0); 140 PetscValidHeaderSpecific(*bar,PETSC_DRAWBAR_CLASSID,1); 141 if (--((PetscObject)(*bar))->refct > 0) PetscFunctionReturn(0); 142 143 ierr = PetscFree((*bar)->values);CHKERRQ(ierr); 144 ierr = PetscStrArrayDestroy(&(*bar)->labels);CHKERRQ(ierr); 145 ierr = PetscDrawAxisDestroy(&(*bar)->axis);CHKERRQ(ierr); 146 ierr = PetscDrawDestroy(&(*bar)->win);CHKERRQ(ierr); 147 ierr = PetscHeaderDestroy(bar);CHKERRQ(ierr); 148 PetscFunctionReturn(0); 149 } 150 151 /*@ 152 PetscDrawBarDraw - Redraws a bar graph. 153 154 Collective on PetscDrawBar 155 156 Input Parameter: 157 . bar - The bar graph context 158 159 Level: intermediate 160 161 .seealso: PetscDrawBar, PetscDrawBarCreate(), PetscDrawBarSetData() 162 163 @*/ 164 PetscErrorCode PetscDrawBarDraw(PetscDrawBar bar) 165 { 166 PetscDraw draw; 167 PetscBool isnull; 168 PetscReal xmin,xmax,ymin,ymax,*values,binLeft,binRight; 169 PetscInt numValues,i,bcolor,color,idx,*perm,nplot; 170 PetscMPIInt rank; 171 PetscErrorCode ierr; 172 char **labels; 173 174 PetscFunctionBegin; 175 PetscValidHeaderSpecific(bar,PETSC_DRAWBAR_CLASSID,1); 176 ierr = PetscDrawIsNull(bar->win,&isnull);CHKERRQ(ierr); 177 if (isnull) PetscFunctionReturn(0); 178 ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)bar),&rank);CHKERRMPI(ierr); 179 180 if (bar->numBins < 1) PetscFunctionReturn(0); 181 182 color = bar->color; 183 if (color == PETSC_DRAW_ROTATE) bcolor = PETSC_DRAW_BLACK+1; 184 else bcolor = color; 185 186 numValues = bar->numBins; 187 values = bar->values; 188 if (bar->ymin == bar->ymax) { 189 /* user has not set bounds on bars so set them based on the data */ 190 ymin = PETSC_MAX_REAL; 191 ymax = PETSC_MIN_REAL; 192 for (i=0; i<numValues; i++) { 193 ymin = PetscMin(ymin,values[i]); 194 ymax = PetscMax(ymax,values[i]); 195 } 196 } else { 197 ymin = bar->ymin; 198 ymax = bar->ymax; 199 } 200 nplot = numValues; /* number of points to actually plot; if some are lower than requested tolerance */ 201 xmin = 0.0; 202 xmax = nplot; 203 labels = bar->labels; 204 205 if (bar->sort) { 206 ierr = PetscMalloc1(numValues,&perm);CHKERRQ(ierr); 207 for (i=0; i<numValues;i++) perm[i] = i; 208 ierr = PetscSortRealWithPermutation(numValues,values,perm);CHKERRQ(ierr); 209 if (bar->sorttolerance) { 210 for (i=0; i<numValues;i++) { 211 if (values[perm[numValues - i - 1]] < bar->sorttolerance) { 212 nplot = i; 213 break; 214 } 215 } 216 } 217 } 218 219 draw = bar->win; 220 ierr = PetscDrawCheckResizedWindow(draw);CHKERRQ(ierr); 221 ierr = PetscDrawClear(draw);CHKERRQ(ierr); 222 223 ierr = PetscDrawAxisSetLimits(bar->axis,xmin,xmax,ymin,ymax);CHKERRQ(ierr); 224 ierr = PetscDrawAxisDraw(bar->axis);CHKERRQ(ierr); 225 226 ierr = PetscDrawCollectiveBegin(draw);CHKERRQ(ierr); 227 if (!rank) { /* Draw bins */ 228 for (i=0; i<nplot; i++) { 229 idx = (bar->sort ? perm[numValues - i - 1] : i); 230 binLeft = xmin + i; 231 binRight = xmin + i + 1; 232 ierr = PetscDrawRectangle(draw,binLeft,ymin,binRight,values[idx],bcolor,bcolor,bcolor,bcolor);CHKERRQ(ierr); 233 ierr = PetscDrawLine(draw,binLeft,ymin,binLeft,values[idx],PETSC_DRAW_BLACK);CHKERRQ(ierr); 234 ierr = PetscDrawLine(draw,binRight,ymin,binRight,values[idx],PETSC_DRAW_BLACK);CHKERRQ(ierr); 235 ierr = PetscDrawLine(draw,binLeft,values[idx],binRight,values[idx],PETSC_DRAW_BLACK);CHKERRQ(ierr); 236 if (labels) { 237 PetscReal h; 238 ierr = PetscDrawStringGetSize(draw,NULL,&h);CHKERRQ(ierr); 239 ierr = PetscDrawStringCentered(draw,.5*(binLeft+binRight),ymin - 1.5*h,bcolor,labels[idx]);CHKERRQ(ierr); 240 } 241 if (color == PETSC_DRAW_ROTATE) bcolor++; 242 if (bcolor > PETSC_DRAW_BASIC_COLORS-1) bcolor = PETSC_DRAW_BLACK+1; 243 } 244 } 245 ierr = PetscDrawCollectiveEnd(draw);CHKERRQ(ierr); 246 if (bar->sort) {ierr = PetscFree(perm);CHKERRQ(ierr);} 247 248 ierr = PetscDrawFlush(draw);CHKERRQ(ierr); 249 ierr = PetscDrawPause(draw);CHKERRQ(ierr); 250 PetscFunctionReturn(0); 251 } 252 253 /*@ 254 PetscDrawBarSave - Saves a drawn image 255 256 Collective on PetscDrawBar 257 258 Input Parameters: 259 . bar - The bar graph context 260 261 Level: intermediate 262 263 .seealso: PetscDrawBarCreate(), PetscDrawBarGetDraw(), PetscDrawSetSave(), PetscDrawSave(), PetscDrawBarSetData() 264 @*/ 265 PetscErrorCode PetscDrawBarSave(PetscDrawBar bar) 266 { 267 PetscErrorCode ierr; 268 269 PetscFunctionBegin; 270 PetscValidHeaderSpecific(bar,PETSC_DRAWBAR_CLASSID,1); 271 ierr = PetscDrawSave(bar->win);CHKERRQ(ierr); 272 PetscFunctionReturn(0); 273 } 274 275 /*@ 276 PetscDrawBarSetColor - Sets the color the bars will be drawn with. 277 278 Logically Collective on PetscDrawBar 279 280 Input Parameters: 281 + bar - The bar graph context 282 - color - one of the colors defined in petscdraw.h or PETSC_DRAW_ROTATE to make each bar a 283 different color 284 285 Level: intermediate 286 287 .seealso: PetscDrawBarCreate(), PetscDrawBar, PetscDrawBarSetData(), PetscDrawBarDraw(), PetscDrawBarGetAxis() 288 289 @*/ 290 PetscErrorCode PetscDrawBarSetColor(PetscDrawBar bar, int color) 291 { 292 PetscFunctionBegin; 293 PetscValidHeaderSpecific(bar, PETSC_DRAWBAR_CLASSID,1); 294 bar->color = color; 295 PetscFunctionReturn(0); 296 } 297 298 /*@ 299 PetscDrawBarSort - Sorts the values before drawing the bar chart 300 301 Logically Collective on PetscDrawBar 302 303 Input Parameters: 304 + bar - The bar graph context 305 . sort - PETSC_TRUE to sort the values 306 - tolerance - discard values less than tolerance 307 308 Level: intermediate 309 310 .seealso: PetscDrawBarCreate(), PetscDrawBar, PetscDrawBarSetData(), PetscDrawBarSetColor(), PetscDrawBarDraw(), PetscDrawBarGetAxis() 311 @*/ 312 PetscErrorCode PetscDrawBarSort(PetscDrawBar bar, PetscBool sort, PetscReal tolerance) 313 { 314 PetscFunctionBegin; 315 PetscValidHeaderSpecific(bar,PETSC_DRAWBAR_CLASSID,1); 316 bar->sort = sort; 317 bar->sorttolerance = tolerance; 318 PetscFunctionReturn(0); 319 } 320 321 /*@ 322 PetscDrawBarSetLimits - Sets the axis limits for a bar graph. If more 323 points are added after this call, the limits will be adjusted to 324 include those additional points. 325 326 Logically Collective on PetscDrawBar 327 328 Input Parameters: 329 + bar - The bar graph context 330 - y_min,y_max - The limits 331 332 Level: intermediate 333 334 .seealso: PetscDrawBarCreate(), PetscDrawBar, PetscDrawBarGetAxis(), PetscDrawBarSetData(), PetscDrawBarDraw() 335 @*/ 336 PetscErrorCode PetscDrawBarSetLimits(PetscDrawBar bar, PetscReal y_min, PetscReal y_max) 337 { 338 PetscFunctionBegin; 339 PetscValidHeaderSpecific(bar,PETSC_DRAWBAR_CLASSID,1); 340 bar->ymin = y_min; 341 bar->ymax = y_max; 342 PetscFunctionReturn(0); 343 } 344 345 /*@C 346 PetscDrawBarGetAxis - Gets the axis context associated with a bar graph. 347 This is useful if one wants to change some axis property, such as 348 labels, color, etc. The axis context should not be destroyed by the 349 application code. 350 351 Not Collective, PetscDrawAxis is parallel if PetscDrawBar is parallel 352 353 Input Parameter: 354 . bar - The bar graph context 355 356 Output Parameter: 357 . axis - The axis context 358 359 Level: intermediate 360 361 .seealso: PetscDrawBarCreate(), PetscDrawBar, PetscDrawAxis, PetscDrawAxisCreate() 362 @*/ 363 PetscErrorCode PetscDrawBarGetAxis(PetscDrawBar bar,PetscDrawAxis *axis) 364 { 365 PetscFunctionBegin; 366 PetscValidHeaderSpecific(bar,PETSC_DRAWBAR_CLASSID,1); 367 PetscValidPointer(axis,2); 368 *axis = bar->axis; 369 PetscFunctionReturn(0); 370 } 371 372 /*@C 373 PetscDrawBarGetDraw - Gets the draw context associated with a bar graph. 374 375 Not Collective, PetscDraw is parallel if PetscDrawBar is parallel 376 377 Input Parameter: 378 . bar - The bar graph context 379 380 Output Parameter: 381 . draw - The draw context 382 383 Level: intermediate 384 385 .seealso: PetscDrawBarCreate(), PetscDrawBar, PetscDrawBarDraw(), PetscDraw 386 @*/ 387 PetscErrorCode PetscDrawBarGetDraw(PetscDrawBar bar,PetscDraw *draw) 388 { 389 PetscFunctionBegin; 390 PetscValidHeaderSpecific(bar,PETSC_DRAWBAR_CLASSID,1); 391 PetscValidPointer(draw,2); 392 *draw = bar->win; 393 PetscFunctionReturn(0); 394 } 395 396 /*@ 397 PetscDrawBarSetFromOptions - Sets options related to the PetscDrawBar 398 399 Collective over PetscDrawBar 400 401 Options Database: 402 . -bar_sort - sort the entries before drawing the bar graph 403 404 Level: intermediate 405 406 407 .seealso: PetscDrawBarDestroy(), PetscDrawBarCreate(), PetscDrawBarSort() 408 @*/ 409 PetscErrorCode PetscDrawBarSetFromOptions(PetscDrawBar bar) 410 { 411 PetscErrorCode ierr; 412 PetscBool set; 413 414 PetscFunctionBegin; 415 PetscValidHeaderSpecific(bar,PETSC_DRAWBAR_CLASSID,1); 416 417 ierr = PetscOptionsHasName(((PetscObject)bar)->options,((PetscObject)bar)->prefix,"-bar_sort",&set);CHKERRQ(ierr); 418 if (set) { 419 PetscReal tol = bar->sorttolerance; 420 ierr = PetscOptionsGetReal(((PetscObject)bar)->options,((PetscObject)bar)->prefix,"-bar_sort",&tol,NULL);CHKERRQ(ierr); 421 ierr = PetscDrawBarSort(bar,PETSC_TRUE,tol);CHKERRQ(ierr); 422 } 423 PetscFunctionReturn(0); 424 } 425