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