5b6618e518c88bbe87bb55875092c7d4461d80d8
[pspp-builds.git] / src / output / charts / plot-chart.c
1 /* PSPP - computes sample statistics.
2    Copyright (C) 2004 Free Software Foundation, Inc.
3
4    This program is free software; you can redistribute it and/or
5    modify it under the terms of the GNU General Public License as
6    published by the Free Software Foundation; either version 2 of the
7    License, or (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful, but
10    WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    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, write to the Free Software
16    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17    02110-1301, USA. */
18
19 #include <config.h>
20
21 #include <stdio.h>
22 #include <plot.h>
23 #include <stdarg.h>
24 #include <string.h>
25 #include <stdio.h>
26 #include <float.h>
27 #include <assert.h>
28 #include <math.h>
29
30 #include <output/charts/plot-chart.h>
31
32 #include <math/chart-geometry.h>
33
34
35
36 #include <libpspp/str.h>
37 #include <libpspp/alloc.h>
38 #include <libpspp/assertion.h>
39 #include <output/manager.h>
40 #include <output/output.h>
41
42
43 const char *const data_colour[] = {
44   "brown",
45   "red",
46   "orange",
47   "yellow",
48   "green",
49   "blue",
50   "violet",
51   "grey",
52   "pink"
53 };
54
55
56
57 /* Draw a tick mark at position
58    If label is non zero, then print it at the tick mark
59 */
60 void
61 draw_tick(struct chart *chart,
62           enum tick_orientation orientation,
63           double position,
64           const char *label, ...)
65 {
66   const int tickSize = 10;
67
68   assert(chart);
69
70   pl_savestate_r(chart->lp);
71
72   pl_move_r(chart->lp, chart->data_left, chart->data_bottom);
73
74   if ( orientation == TICK_ABSCISSA )
75     pl_flinerel_r(chart->lp, position, 0, position, -tickSize);
76   else if (orientation == TICK_ORDINATE )
77       pl_flinerel_r(chart->lp, 0, position, -tickSize, position);
78   else
79     NOT_REACHED ();
80
81   if ( label ) {
82     char buf[10];
83     va_list ap;
84     va_start(ap,label);
85     vsnprintf(buf,10,label,ap);
86
87     if ( orientation == TICK_ABSCISSA )
88       pl_alabel_r(chart->lp, 'c','t', buf);
89     else if (orientation == TICK_ORDINATE )
90       {
91         if ( fabs(position) < DBL_EPSILON )
92             pl_moverel_r(chart->lp, 0, 10);
93
94         pl_alabel_r(chart->lp, 'r','c', buf);
95       }
96
97     va_end(ap);
98   }
99
100   pl_restorestate_r(chart->lp);
101 }
102
103
104 /* Write the title on a chart*/
105 void
106 chart_write_title(struct chart *chart, const char *title, ...)
107 {
108   va_list ap;
109   char buf[100];
110
111   if ( ! chart )
112           return ;
113
114   pl_savestate_r(chart->lp);
115   pl_ffontsize_r(chart->lp,chart->font_size * 1.5);
116   pl_move_r(chart->lp,chart->data_left, chart->title_bottom);
117
118   va_start(ap,title);
119   vsnprintf(buf,100,title,ap);
120   pl_alabel_r(chart->lp,0,0,buf);
121   va_end(ap);
122
123   pl_restorestate_r(chart->lp);
124 }
125
126
127 /* Set the scale for the abscissa */
128 void
129 chart_write_xscale(struct chart *ch, double min, double max, int ticks)
130 {
131   double x;
132
133   const double tick_interval =
134     chart_rounded_tick( (max - min) / (double) ticks);
135
136   assert ( ch );
137
138
139   ch->x_max = ceil( max / tick_interval ) * tick_interval ;
140   ch->x_min = floor ( min / tick_interval ) * tick_interval ;
141
142
143   ch->abscissa_scale = fabs(ch->data_right - ch->data_left) /
144     fabs(ch->x_max - ch->x_min);
145
146   for(x = ch->x_min ; x <= ch->x_max; x += tick_interval )
147     {
148       draw_tick (ch, TICK_ABSCISSA,
149                  (x - ch->x_min) * ch->abscissa_scale, "%g", x);
150     }
151
152 }
153
154
155 /* Set the scale for the ordinate */
156 void
157 chart_write_yscale(struct chart *ch, double smin, double smax, int ticks)
158 {
159   double y;
160
161   const double tick_interval =
162     chart_rounded_tick( (smax - smin) / (double) ticks);
163
164   if ( !ch )
165           return;
166
167   ch->y_max = ceil  ( smax / tick_interval ) * tick_interval ;
168   ch->y_min = floor ( smin / tick_interval ) * tick_interval ;
169
170   ch->ordinate_scale =
171     fabs(ch->data_top -  ch->data_bottom) / fabs(ch->y_max - ch->y_min) ;
172
173   for(y = ch->y_min ; y <= ch->y_max; y += tick_interval )
174     {
175     draw_tick (ch, TICK_ORDINATE,
176                (y - ch->y_min) * ch->ordinate_scale, "%g", y);
177     }
178 }
179
180
181 /* Write the abscissa label */
182 void
183 chart_write_xlabel(struct chart *ch, const char *label)
184 {
185   if ( ! ch )
186     return ;
187
188   pl_savestate_r(ch->lp);
189
190   pl_move_r(ch->lp,ch->data_left, ch->abscissa_top);
191   pl_alabel_r(ch->lp,0,'t',label);
192
193   pl_restorestate_r(ch->lp);
194
195 }
196
197
198
199 /* Write the ordinate label */
200 void
201 chart_write_ylabel(struct chart *ch, const char *label)
202 {
203   if ( ! ch )
204     return ;
205
206   pl_savestate_r(ch->lp);
207
208   pl_move_r(ch->lp, ch->data_bottom, ch->ordinate_right);
209   pl_textangle_r(ch->lp, 90);
210   pl_alabel_r(ch->lp, 0, 0, label);
211
212   pl_restorestate_r(ch->lp);
213 }