7fc7467811d34e8d0a444314790ff38e2ef2b08c
[pspp-builds.git] / src / cartesian.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., 59 Temple Place - Suite 330, Boston, MA
18    02111-1307, USA. */
19
20
21 #include <math.h>
22 #include "chart.h"
23 #include <assert.h>
24
25
26
27 static const    double y_min = 15;
28 static const    double y_max = 120.0;
29 static const    double y_tick = 20.0;
30
31
32
33 static const double x_min = -11.0;
34 static const double x_max = 19.0;
35 static const double x_tick = 5.0;
36
37
38 struct datum 
39 {
40   double x;
41   double y;
42 };
43
44
45 static const struct datum data1[]=
46   {
47     { -8.0, 29 },
48     { -3.7, 45 },
49     { -3.3, 67 },
50     { -0.8, 89 },
51     { -0.2, 93 },
52     { 1.0,  100},
53     { 2.3,  103},
54     { 4.0,  103.4},
55     { 5.2,  104},
56     { 5.9,  106},
57     { 10.3, 106},
58     { 13.8, 108},
59     { 15.8, 109},
60   };
61
62
63
64
65 static const struct datum data2[]=
66   {
67     { -9.1, 20 },
68     { -8.2, 17 },
69     { -5.0, 19 },
70     { -3.7, 25 },
71     { -1.6, 49 },
72     { -1.3, 61 },
73     { -1.1, 81 },
74     { 3.5,  91},
75     { 5.4,  93},
76     { 9.3,  94},
77     { 14.3,  92}
78   };
79
80
81
82
83 struct dataset
84 {
85   const struct datum *data;
86   int n_data;
87   char *label;
88 };
89
90
91
92 #define DATASETS 2
93
94 static const struct dataset dataset[DATASETS] = 
95   {
96     {data1, 13, "male"},
97     {data2, 11, "female"},
98   };
99
100
101
102 typedef void (*plot_func) (struct chart *ch,  const struct dataset *dataset);
103
104
105 void plot_line(struct chart *ch,  const struct dataset *dataset);
106
107 void plot_scatter(struct chart *ch,  const struct dataset *dataset);
108
109
110
111 static void
112 write_legend(struct chart *chart, const char *heading, int n);
113
114 void draw_cartesian(struct chart *ch, const char *title, 
115                     const char *xlabel, const char *ylabel, plot_func pf);
116
117
118
119 void
120 draw_scatterplot(struct chart *ch, const char *title, 
121                  const char *xlabel, const char *ylabel)
122 {
123   draw_cartesian(ch, title, xlabel, ylabel, plot_scatter);
124 }
125
126
127 void
128 draw_lineplot(struct chart *ch, const char *title, 
129                  const char *xlabel, const char *ylabel)
130 {
131   draw_cartesian(ch, title, xlabel, ylabel, plot_scatter);
132 }
133
134
135 void
136 draw_cartesian(struct chart *ch, const char *title, 
137                  const char *xlabel, const char *ylabel, plot_func pf)
138 {
139   double x;
140   double y;
141   
142
143   int d;
144
145
146   const double ordinate_scale = 
147     fabs(ch->data_top -  ch->data_bottom) 
148     / fabs(y_max - y_min) ;
149
150
151   const double abscissa_scale =
152     fabs(ch->data_right - ch->data_left) 
153     / 
154     fabs(x_max - x_min);
155
156
157   /* Move to data bottom-left */
158   pl_move_r(ch->lp, ch->data_left, ch->data_bottom);
159
160   pl_savestate_r(ch->lp);
161
162
163   for(x = x_tick * ceil(x_min / x_tick )  ; 
164       x < x_max;    
165       x += x_tick )
166       draw_tick (ch, TICK_ABSCISSA, (x - x_min) * abscissa_scale, "%g", x);
167
168   for(y = y_tick * ceil(y_min / y_tick )  ; 
169       y < y_max;    
170       y += y_tick )
171       draw_tick (ch, TICK_ORDINATE, (y - y_min) * ordinate_scale, "%g", y);
172
173   pl_savestate_r(ch->lp);
174
175   for (d = 0 ; d < DATASETS ; ++d ) 
176     {
177       pl_pencolorname_r(ch->lp,data_colour[d]);
178       pf(ch, &dataset[d]);
179     }
180   
181   pl_restorestate_r(ch->lp);
182
183   /* Write the abscissa label */
184   pl_move_r(ch->lp,ch->data_left, ch->abscissa_top);
185   pl_alabel_r(ch->lp,0,'t',xlabel);
186
187  
188   /* Write the ordinate label */
189   pl_savestate_r(ch->lp);
190   pl_move_r(ch->lp,ch->data_bottom, ch->ordinate_right);
191   pl_textangle_r(ch->lp,90);
192   pl_alabel_r(ch->lp,0,0,ylabel);
193   pl_restorestate_r(ch->lp);
194
195
196   chart_write_title(ch, title);
197
198   write_legend(ch,"Key:",DATASETS);
199
200   pl_restorestate_r(ch->lp);
201
202 }
203
204
205
206
207 static void
208 write_legend(struct chart *chart, const char *heading, 
209              int n)
210 {
211   int ds;
212
213   pl_savestate_r(chart->lp);
214
215   pl_filltype_r(chart->lp,1);
216
217   pl_move_r(chart->lp, chart->legend_left, 
218             chart->data_bottom + chart->font_size * n * 1.5);
219
220   pl_alabel_r(chart->lp,0,'b',heading);
221
222   for (ds = 0 ; ds < n ; ++ds ) 
223     {
224       pl_fmove_r(chart->lp,
225                  chart->legend_left,
226                  chart->data_bottom + chart->font_size * ds  * 1.5);
227
228       pl_savestate_r(chart->lp);    
229       pl_fillcolorname_r(chart->lp,data_colour[ds]);
230       pl_fboxrel_r (chart->lp,
231                     0,0,
232                     chart->font_size, chart->font_size);
233       pl_restorestate_r(chart->lp);    
234
235       pl_fmove_r(chart->lp,
236                  chart->legend_left + chart->font_size * 1.5,
237                  chart->data_bottom + chart->font_size * ds  * 1.5);
238
239       pl_alabel_r(chart->lp,'l','b',dataset[ds].label);
240     }
241
242
243   pl_restorestate_r(chart->lp);    
244 }
245
246
247
248 void
249 plot_line(struct chart *ch,  const struct dataset *dataset)
250 {
251   int i;
252
253   const struct datum *data = dataset->data;
254
255   const double ordinate_scale = 
256     fabs(ch->data_top -  ch->data_bottom) 
257     / fabs(y_max - y_min) ;
258
259
260   const double abscissa_scale =
261     fabs(ch->data_right - ch->data_left) 
262     / 
263     fabs(x_max - x_min);
264
265
266   for( i = 0 ; i < dataset->n_data ; ++i ) 
267     {
268       const double x = 
269         (data[i].x - x_min) * abscissa_scale + ch->data_left ; 
270       const double y = 
271         (data[i].y - y_min) * ordinate_scale + ch->data_bottom;
272
273       if (i == 0 ) 
274         pl_move_r(ch->lp, x, y );
275       else
276         pl_fcont_r(ch->lp, x, y);
277     }
278   pl_endpath_r(ch->lp);
279
280 }
281
282
283
284
285 void
286 plot_scatter(struct chart *ch,  const struct dataset *dataset)
287 {
288   int i;
289
290   const struct datum *data = dataset->data;
291
292   const double ordinate_scale = 
293     fabs(ch->data_top -  ch->data_bottom) 
294     / fabs(y_max - y_min) ;
295
296
297   const double abscissa_scale =
298     fabs(ch->data_right - ch->data_left) 
299     / 
300     fabs(x_max - x_min);
301
302
303   for( i = 0 ; i < dataset->n_data ; ++i ) 
304     {
305       const double x = 
306         (data[i].x - x_min) * abscissa_scale + ch->data_left ; 
307       const double y = 
308         (data[i].y - y_min) * ordinate_scale + ch->data_bottom;
309
310       pl_fmarker_r(ch->lp, x, y, 6, 15);
311     }
312   
313 }