xref: /petsc/src/sys/classes/draw/utils/bars.c (revision 5b399a637f946da949d4901b9cfb4dd7404a5662)
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    Level: intermediate
43 
44    Concepts: bar graph^creating
45 
46 .seealso: PetscDrawBarDestroy()
47 
48 @*/
49 PetscErrorCode  PetscDrawBarCreate(PetscDraw draw, PetscDrawBar *bar)
50 {
51   PetscDrawBar    h;
52   PetscBool      isnull;
53   PetscErrorCode ierr;
54 
55   PetscFunctionBegin;
56   PetscValidHeaderSpecific(draw,PETSC_DRAW_CLASSID,1);
57   PetscValidPointer(bar,2);
58   ierr = PetscDrawIsNull(draw,&isnull);CHKERRQ(ierr);
59   if (isnull) {*bar = NULL; PetscFunctionReturn(0);}
60 
61   ierr = PetscHeaderCreate(h, PETSC_DRAWBAR_CLASSID, "PetscDrawBar", "Bar Graph", "Draw", PetscObjectComm((PetscObject)draw), PetscDrawBarDestroy, NULL);CHKERRQ(ierr);
62   ierr = PetscLogObjectParent((PetscObject)draw,(PetscObject)h);CHKERRQ(ierr);
63 
64   ierr = PetscObjectReference((PetscObject)draw);CHKERRQ(ierr);
65   h->win = draw;
66 
67   h->view        = NULL;
68   h->destroy     = NULL;
69   h->color       = PETSC_DRAW_GREEN;
70   h->ymin        = 0.;  /* if user has not set these then they are determined from the data */
71   h->ymax        = 0.;
72   h->numBins     = 0;
73 
74   ierr = PetscDrawAxisCreate(draw,&h->axis);CHKERRQ(ierr);
75   if (h->axis) h->axis->xticks = NULL;
76 
77   *bar = h;
78   PetscFunctionReturn(0);
79 }
80 
81 #undef __FUNCT__
82 #define __FUNCT__ "PetscDrawBarSetData"
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 
97 @*/
98 PetscErrorCode  PetscDrawBarSetData(PetscDrawBar bar, PetscInt bins,const PetscReal data[],const char *const *labels)
99 {
100   PetscErrorCode ierr;
101 
102   PetscFunctionBegin;
103   if (!bar) PetscFunctionReturn(0);
104   PetscValidHeaderSpecific(bar,PETSC_DRAWBAR_CLASSID,1);
105 
106   if (bar->numBins != bins) {
107     ierr = PetscFree(bar->values);CHKERRQ(ierr);
108     ierr = PetscMalloc1(bins, &bar->values);CHKERRQ(ierr);
109     bar->numBins = bins;
110   }
111   ierr = PetscMemcpy(bar->values,data,bins*sizeof(PetscReal));CHKERRQ(ierr);
112   bar->numBins = bins;
113   if (labels) {
114     ierr = PetscStrArrayallocpy(labels,&bar->labels);CHKERRQ(ierr);
115   }
116   PetscFunctionReturn(0);
117 }
118 
119 #undef __FUNCT__
120 #define __FUNCT__ "PetscDrawBarDestroy"
121 /*@C
122   PetscDrawBarDestroy - Frees all space taken up by bar graph data structure.
123 
124   Collective over PetscDrawBar
125 
126   Input Parameter:
127 . bar - The bar graph context
128 
129   Level: intermediate
130 
131 .seealso:  PetscDrawBarCreate()
132 @*/
133 PetscErrorCode  PetscDrawBarDestroy(PetscDrawBar *bar)
134 {
135   PetscErrorCode ierr;
136 
137   PetscFunctionBegin;
138   if (!*bar) PetscFunctionReturn(0);
139   PetscValidHeaderSpecific(*bar,PETSC_DRAWBAR_CLASSID,1);
140   if (--((PetscObject)(*bar))->refct > 0) PetscFunctionReturn(0);
141 
142   ierr = PetscFree((*bar)->values);CHKERRQ(ierr);
143   ierr = PetscStrArrayDestroy(&(*bar)->labels);CHKERRQ(ierr);
144   ierr = PetscDrawAxisDestroy(&(*bar)->axis);CHKERRQ(ierr);
145   ierr = PetscDrawDestroy(&(*bar)->win);CHKERRQ(ierr);
146   ierr = PetscHeaderDestroy(bar);CHKERRQ(ierr);
147   PetscFunctionReturn(0);
148 }
149 
150 #undef __FUNCT__
151 #define __FUNCT__ "PetscDrawBarDraw"
152 /*@
153   PetscDrawBarDraw - Redraws a bar graph.
154 
155   Collective on PetscDrawBar
156 
157   Input Parameter:
158 . bar - The bar graph context
159 
160   Level: intermediate
161 
162 @*/
163 PetscErrorCode  PetscDrawBarDraw(PetscDrawBar bar)
164 {
165   PetscDraw      draw;
166   PetscBool      isnull;
167   PetscReal      xmin,xmax,ymin,ymax,*values,binLeft,binRight;
168   PetscInt       numValues,i,bcolor,color,idx,*perm,nplot;
169   PetscMPIInt    rank;
170   PetscErrorCode ierr;
171   char           **labels;
172 
173   PetscFunctionBegin;
174   if (!bar) PetscFunctionReturn(0);
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);CHKERRQ(ierr);
179 
180   if (bar->numBins < 1) PetscFunctionReturn(0);
181 
182   color = bar->color;
183   if (color == PETSC_DRAW_ROTATE) bcolor = 2;
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.2*h,bcolor,labels[idx]);CHKERRQ(ierr);
240       }
241       if (color == PETSC_DRAW_ROTATE) bcolor++;
242       if (bcolor > PETSC_DRAW_BASIC_COLORS-1) bcolor = 2;
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 #undef __FUNCT__
254 #define __FUNCT__ "PetscDrawBarSetColor"
255 /*@
256   PetscDrawBarSetColor - Sets the color the bars will be drawn with.
257 
258   Logically Collective on PetscDrawBar
259 
260   Input Parameters:
261 + bar - The bar graph context
262 - color - one of the colors defined in petscdraw.h or PETSC_DRAW_ROTATE to make each bar a
263           different color
264 
265   Level: intermediate
266 
267 @*/
268 PetscErrorCode  PetscDrawBarSetColor(PetscDrawBar bar, int color)
269 {
270   PetscFunctionBegin;
271   if (!bar) PetscFunctionReturn(0);
272   PetscValidHeaderSpecific(bar, PETSC_DRAWBAR_CLASSID,1);
273   bar->color = color;
274   PetscFunctionReturn(0);
275 }
276 
277 #undef __FUNCT__
278 #define __FUNCT__ "PetscDrawBarSort"
279 /*@
280   PetscDrawBarSort - Sorts the values before drawing the bar chart
281 
282   Logically Collective on PetscDrawBar
283 
284   Input Parameters:
285 + bar - The bar graph context
286 . sort - PETSC_TRUE to sort the values
287 . tolerance - discard values less than tolerance
288 
289   Level: intermediate
290 
291   Concepts: bar graph^setting axis
292 @*/
293 PetscErrorCode  PetscDrawBarSort(PetscDrawBar bar, PetscBool sort, PetscReal tolerance)
294 {
295   PetscFunctionBegin;
296   if (!bar) PetscFunctionReturn(0);
297   PetscValidHeaderSpecific(bar,PETSC_DRAWBAR_CLASSID,1);
298   bar->sort          = sort;
299   bar->sorttolerance = tolerance;
300   PetscFunctionReturn(0);
301 }
302 
303 #undef __FUNCT__
304 #define __FUNCT__ "PetscDrawBarSetLimits"
305 /*@
306   PetscDrawBarSetLimits - Sets the axis limits for a bar graph. If more
307   points are added after this call, the limits will be adjusted to
308   include those additional points.
309 
310   Logically Collective on PetscDrawBar
311 
312   Input Parameters:
313 + bar - The bar graph context
314 - y_min,y_max - The limits
315 
316   Level: intermediate
317 
318   Concepts: bar graph^setting axis
319 @*/
320 PetscErrorCode  PetscDrawBarSetLimits(PetscDrawBar bar, PetscReal y_min, PetscReal y_max)
321 {
322   PetscFunctionBegin;
323   if (!bar) PetscFunctionReturn(0);
324   PetscValidHeaderSpecific(bar,PETSC_DRAWBAR_CLASSID,1);
325   bar->ymin = y_min;
326   bar->ymax = y_max;
327   PetscFunctionReturn(0);
328 }
329 
330 #undef __FUNCT__
331 #define __FUNCT__ "PetscDrawBarGetAxis"
332 /*@C
333   PetscDrawBarGetAxis - Gets the axis context associated with a bar graph.
334   This is useful if one wants to change some axis property, such as
335   labels, color, etc. The axis context should not be destroyed by the
336   application code.
337 
338   Not Collective, PetscDrawAxis is parallel if PetscDrawBar is parallel
339 
340   Input Parameter:
341 . bar - The bar graph context
342 
343   Output Parameter:
344 . axis - The axis context
345 
346   Level: intermediate
347 
348 @*/
349 PetscErrorCode  PetscDrawBarGetAxis(PetscDrawBar bar, PetscDrawAxis *axis)
350 {
351   PetscFunctionBegin;
352   PetscValidPointer(axis,2);
353   if (!bar) {*axis = NULL; PetscFunctionReturn(0);}
354   PetscValidHeaderSpecific(bar,PETSC_DRAWBAR_CLASSID,1);
355   *axis = bar->axis;
356   PetscFunctionReturn(0);
357 }
358 
359 #undef __FUNCT__
360 #define __FUNCT__ "PetscDrawBarGetDraw"
361 /*@C
362   PetscDrawBarGetDraw - Gets the draw context associated with a bar graph.
363 
364   Not Collective, PetscDraw is parallel if PetscDrawBar is parallel
365 
366   Input Parameter:
367 . bar - The bar graph context
368 
369   Output Parameter:
370 . draw  - The draw context
371 
372   Level: intermediate
373 
374 @*/
375 PetscErrorCode  PetscDrawBarGetDraw(PetscDrawBar bar, PetscDraw *draw)
376 {
377   PetscFunctionBegin;
378   PetscValidPointer(draw,2);
379   if (!bar) {*draw = NULL; PetscFunctionReturn(0);}
380   PetscValidHeaderSpecific(bar,PETSC_DRAWBAR_CLASSID,1);
381   *draw = bar->win;
382   PetscFunctionReturn(0);
383 }
384 
385 #undef __FUNCT__
386 #define __FUNCT__ "PetscDrawBarSetFromOptions"
387 /*@
388     PetscDrawBarSetFromOptions - Sets options related to the PetscDrawBar
389 
390     Collective over PetscDrawBar
391 
392     Options Database:
393 .  -bar_sort - sort the entries before drawing the bar graph
394 
395     Level: intermediate
396 
397 
398 .seealso:  PetscDrawBarDestroy(), PetscDrawBarCreate()
399 @*/
400 PetscErrorCode  PetscDrawBarSetFromOptions(PetscDrawBar bar)
401 {
402   PetscErrorCode ierr;
403   PetscBool      set;
404 
405   PetscFunctionBegin;
406   if (!bar) PetscFunctionReturn(0);
407   PetscValidHeaderSpecific(bar,PETSC_DRAWBAR_CLASSID,1);
408 
409   ierr = PetscOptionsHasName(((PetscObject)bar)->options,NULL,"-bar_sort",&set);CHKERRQ(ierr);
410   if (set) {
411     PetscReal tol = bar->sorttolerance;
412     ierr = PetscOptionsGetReal(((PetscObject)bar)->options,NULL,"-bar_sort",&tol,NULL);CHKERRQ(ierr);
413     ierr = PetscDrawBarSort(bar,PETSC_TRUE,tol);CHKERRQ(ierr);
414   }
415   PetscFunctionReturn(0);
416 }
417 
418