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