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