xref: /petsc/src/sys/classes/draw/utils/bars.c (revision d12e167ebf17844deeae3c4cdd43de9ffb5cfe5d)
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__ "PetscDrawBarSave"
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()
268 @*/
269 PetscErrorCode  PetscDrawBarSave(PetscDrawBar bar)
270 {
271   PetscErrorCode ierr;
272 
273   PetscFunctionBegin;
274   if (!bar) PetscFunctionReturn(0);
275   PetscValidHeaderSpecific(bar,PETSC_DRAWBAR_CLASSID,1);
276   ierr = PetscDrawSave(bar->win);CHKERRQ(ierr);
277   PetscFunctionReturn(0);
278 }
279 
280 #undef __FUNCT__
281 #define __FUNCT__ "PetscDrawBarSetColor"
282 /*@
283   PetscDrawBarSetColor - Sets the color the bars will be drawn with.
284 
285   Logically Collective on PetscDrawBar
286 
287   Input Parameters:
288 + bar - The bar graph context
289 - color - one of the colors defined in petscdraw.h or PETSC_DRAW_ROTATE to make each bar a
290           different color
291 
292   Level: intermediate
293 
294 @*/
295 PetscErrorCode  PetscDrawBarSetColor(PetscDrawBar bar, int color)
296 {
297   PetscFunctionBegin;
298   if (!bar) PetscFunctionReturn(0);
299   PetscValidHeaderSpecific(bar, PETSC_DRAWBAR_CLASSID,1);
300   bar->color = color;
301   PetscFunctionReturn(0);
302 }
303 
304 #undef __FUNCT__
305 #define __FUNCT__ "PetscDrawBarSort"
306 /*@
307   PetscDrawBarSort - Sorts the values before drawing the bar chart
308 
309   Logically Collective on PetscDrawBar
310 
311   Input Parameters:
312 + bar - The bar graph context
313 . sort - PETSC_TRUE to sort the values
314 . tolerance - discard values less than tolerance
315 
316   Level: intermediate
317 
318   Concepts: bar graph^setting axis
319 @*/
320 PetscErrorCode  PetscDrawBarSort(PetscDrawBar bar, PetscBool sort, PetscReal tolerance)
321 {
322   PetscFunctionBegin;
323   if (!bar) PetscFunctionReturn(0);
324   PetscValidHeaderSpecific(bar,PETSC_DRAWBAR_CLASSID,1);
325   bar->sort          = sort;
326   bar->sorttolerance = tolerance;
327   PetscFunctionReturn(0);
328 }
329 
330 #undef __FUNCT__
331 #define __FUNCT__ "PetscDrawBarSetLimits"
332 /*@
333   PetscDrawBarSetLimits - Sets the axis limits for a bar graph. If more
334   points are added after this call, the limits will be adjusted to
335   include those additional points.
336 
337   Logically Collective on PetscDrawBar
338 
339   Input Parameters:
340 + bar - The bar graph context
341 - y_min,y_max - The limits
342 
343   Level: intermediate
344 
345   Concepts: bar graph^setting axis
346 @*/
347 PetscErrorCode  PetscDrawBarSetLimits(PetscDrawBar bar, PetscReal y_min, PetscReal y_max)
348 {
349   PetscFunctionBegin;
350   if (!bar) PetscFunctionReturn(0);
351   PetscValidHeaderSpecific(bar,PETSC_DRAWBAR_CLASSID,1);
352   bar->ymin = y_min;
353   bar->ymax = y_max;
354   PetscFunctionReturn(0);
355 }
356 
357 #undef __FUNCT__
358 #define __FUNCT__ "PetscDrawBarGetAxis"
359 /*@C
360   PetscDrawBarGetAxis - Gets the axis context associated with a bar graph.
361   This is useful if one wants to change some axis property, such as
362   labels, color, etc. The axis context should not be destroyed by the
363   application code.
364 
365   Not Collective, PetscDrawAxis is parallel if PetscDrawBar is parallel
366 
367   Input Parameter:
368 . bar - The bar graph context
369 
370   Output Parameter:
371 . axis - The axis context
372 
373   Level: intermediate
374 
375 @*/
376 PetscErrorCode  PetscDrawBarGetAxis(PetscDrawBar bar, PetscDrawAxis *axis)
377 {
378   PetscFunctionBegin;
379   PetscValidPointer(axis,2);
380   if (!bar) {*axis = NULL; PetscFunctionReturn(0);}
381   PetscValidHeaderSpecific(bar,PETSC_DRAWBAR_CLASSID,1);
382   *axis = bar->axis;
383   PetscFunctionReturn(0);
384 }
385 
386 #undef __FUNCT__
387 #define __FUNCT__ "PetscDrawBarGetDraw"
388 /*@C
389   PetscDrawBarGetDraw - Gets the draw context associated with a bar graph.
390 
391   Not Collective, PetscDraw is parallel if PetscDrawBar is parallel
392 
393   Input Parameter:
394 . bar - The bar graph context
395 
396   Output Parameter:
397 . draw  - The draw context
398 
399   Level: intermediate
400 
401 @*/
402 PetscErrorCode  PetscDrawBarGetDraw(PetscDrawBar bar, PetscDraw *draw)
403 {
404   PetscFunctionBegin;
405   PetscValidPointer(draw,2);
406   if (!bar) {*draw = NULL; PetscFunctionReturn(0);}
407   PetscValidHeaderSpecific(bar,PETSC_DRAWBAR_CLASSID,1);
408   *draw = bar->win;
409   PetscFunctionReturn(0);
410 }
411 
412 #undef __FUNCT__
413 #define __FUNCT__ "PetscDrawBarSetFromOptions"
414 /*@
415     PetscDrawBarSetFromOptions - Sets options related to the PetscDrawBar
416 
417     Collective over PetscDrawBar
418 
419     Options Database:
420 .  -bar_sort - sort the entries before drawing the bar graph
421 
422     Level: intermediate
423 
424 
425 .seealso:  PetscDrawBarDestroy(), PetscDrawBarCreate()
426 @*/
427 PetscErrorCode  PetscDrawBarSetFromOptions(PetscDrawBar bar)
428 {
429   PetscErrorCode ierr;
430   PetscBool      set;
431 
432   PetscFunctionBegin;
433   if (!bar) PetscFunctionReturn(0);
434   PetscValidHeaderSpecific(bar,PETSC_DRAWBAR_CLASSID,1);
435 
436   ierr = PetscOptionsHasName(((PetscObject)bar)->options,NULL,"-bar_sort",&set);CHKERRQ(ierr);
437   if (set) {
438     PetscReal tol = bar->sorttolerance;
439     ierr = PetscOptionsGetReal(((PetscObject)bar)->options,NULL,"-bar_sort",&tol,NULL);CHKERRQ(ierr);
440     ierr = PetscDrawBarSort(bar,PETSC_TRUE,tol);CHKERRQ(ierr);
441   }
442   PetscFunctionReturn(0);
443 }
444 
445