Change license from GPLv2+ to GPLv3+.
[pspp-builds.git] / src / output / charts / barchart.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2004 Free Software Foundation, Inc.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
16
17
18 #include <config.h>
19
20 #include <stdio.h>
21 #include <plot.h>
22 #include <stdarg.h>
23 #include <math.h>
24 #include <output/charts/barchart.h>
25 #include <output/chart.h>
26 #include <output/charts/plot-chart.h>
27
28 #define CATAGORIES 6
29 #define SUB_CATAGORIES 3
30
31 static const    double x_min = 0;
32 static const    double x_max = 15.0;
33
34 static const char *cat_labels[] =
35   {
36     "Age",
37     "Intelligence",
38     "Wealth",
39     "Emotional",
40     "cat 5",
41     "cat 6",
42     "cat 7",
43     "cat 8",
44     "cat 9",
45     "cat 10",
46     "cat 11"
47   };
48
49
50
51
52 /* Subcatagories */
53 static const double data1[] =
54 {
55   28,83,
56   34,
57   29,13,
58    9,4,
59    3,3,
60    2,0,
61    1,0,
62    0,
63    1,1
64 };
65
66
67 static const double data2[] =
68 {
69   45,13,
70    9,4,
71    3,43,
72    2,0,
73    1,20,
74    0,0,
75   1,1,
76   0,0
77 };
78
79 static const double data3[] =
80   {
81     23,18,
82     0, 45,23, 9, 40, 24,4, 8
83   };
84
85
86 static const char subcat_name[]="Gender";
87
88
89 struct subcat {
90   const double *data;
91   const char *label;
92 };
93
94 static const struct subcat sub_catagory[SUB_CATAGORIES] =
95   {
96     {data1, "male"},
97     {data2, "female"},
98     {data3, "47xxy"}
99   };
100
101
102
103 static const    double y_min = 0;
104 static const    double y_max = 120.0;
105 static const    double y_tick = 20.0;
106
107
108
109 static void write_legend(struct chart *chart) ;
110
111
112 void
113 draw_barchart(struct chart *ch, const char *title,
114               const char *xlabel, const char *ylabel, enum bar_opts opt)
115 {
116   double d;
117   int i;
118
119   double interval_size = fabs(ch->data_right - ch->data_left) / ( CATAGORIES );
120
121   double bar_width = interval_size / 1.1 ;
122
123   double ordinate_scale = fabs(ch->data_top -  ch->data_bottom) /
124     fabs(y_max - y_min) ;
125
126   if ( opt != BAR_STACKED )
127       bar_width /= SUB_CATAGORIES;
128
129   /* Move to data bottom-left */
130   pl_move_r(ch->lp, ch->data_left, ch->data_bottom);
131
132   pl_savestate_r(ch->lp);
133   pl_filltype_r(ch->lp,1);
134
135   /* Draw the data */
136   for (i = 0 ; i < CATAGORIES ; ++i )
137     {
138       int sc;
139       double ystart=0.0;
140       double x = i * interval_size;
141
142       pl_savestate_r(ch->lp);
143
144       draw_tick (ch, TICK_ABSCISSA, x + (interval_size/2 ),
145                  cat_labels[i]);
146
147       for(sc = 0 ; sc < SUB_CATAGORIES ; ++sc )
148         {
149
150           pl_savestate_r(ch->lp);
151           pl_fillcolorname_r(ch->lp,data_colour[sc]);
152
153           switch ( opt )
154             {
155             case BAR_GROUPED:
156               pl_fboxrel_r(ch->lp,
157                            x + (sc * bar_width ), 0,
158                            x + (sc + 1) * bar_width,
159                              sub_catagory[sc].data[i] * ordinate_scale );
160               break;
161
162
163             case BAR_STACKED:
164
165               pl_fboxrel_r(ch->lp,
166                            x, ystart,
167                            x + bar_width,
168                            ystart + sub_catagory[sc].data[i] * ordinate_scale );
169
170               ystart +=    sub_catagory[sc].data[i] * ordinate_scale ;
171
172               break;
173
174             default:
175               break;
176             }
177           pl_restorestate_r(ch->lp);
178         }
179
180       pl_restorestate_r(ch->lp);
181     }
182   pl_restorestate_r(ch->lp);
183
184   for ( d = y_min; d <= y_max ; d += y_tick )
185     {
186
187       draw_tick (ch, TICK_ORDINATE,
188                  (d - y_min ) * ordinate_scale, "%g", d);
189
190     }
191
192   /* Write the abscissa label */
193   pl_move_r(ch->lp,ch->data_left, ch->abscissa_top);
194   pl_alabel_r(ch->lp,0,'t',xlabel);
195
196
197   /* Write the ordinate label */
198   pl_savestate_r(ch->lp);
199   pl_move_r(ch->lp,ch->data_bottom, ch->ordinate_right);
200   pl_textangle_r(ch->lp,90);
201   pl_alabel_r(ch->lp,0,0,ylabel);
202   pl_restorestate_r(ch->lp);
203
204
205   chart_write_title(ch, title);
206
207   write_legend(ch);
208
209
210 }
211
212
213
214
215
216 static void
217 write_legend(struct chart *chart)
218 {
219   int sc;
220
221   pl_savestate_r(chart->lp);
222
223   pl_filltype_r(chart->lp,1);
224
225   pl_move_r(chart->lp, chart->legend_left,
226             chart->data_bottom + chart->font_size * SUB_CATAGORIES * 1.5);
227
228   pl_alabel_r(chart->lp,0,'b',subcat_name);
229
230   for (sc = 0 ; sc < SUB_CATAGORIES ; ++sc )
231     {
232       pl_fmove_r(chart->lp,
233                  chart->legend_left,
234                  chart->data_bottom + chart->font_size * sc  * 1.5);
235
236       pl_savestate_r(chart->lp);
237       pl_fillcolorname_r(chart->lp,data_colour[sc]);
238       pl_fboxrel_r (chart->lp,
239                     0,0,
240                     chart->font_size, chart->font_size);
241       pl_restorestate_r(chart->lp);
242
243       pl_fmove_r(chart->lp,
244                  chart->legend_left + chart->font_size * 1.5,
245                  chart->data_bottom + chart->font_size * sc  * 1.5);
246
247       pl_alabel_r(chart->lp,'l','b',sub_catagory[sc].label);
248     }
249
250
251   pl_restorestate_r(chart->lp);
252 }