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