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