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