34527e41628edd30adc7635181ea9b399901eac8
[pspp] / src / chart.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 #include <config.h>
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 "chart.h"
31 #include "str.h"
32
33
34 const char *data_colour[] = {
35   "brown",
36   "red",
37   "orange",
38   "yellow",
39   "green",
40   "blue",
41   "violet",
42   "grey",
43   "pink"
44 };
45
46
47
48 int
49 chart_initialise(struct chart *chart)
50 {
51
52   chart->pl_params = pl_newplparams();
53
54   chart->lp = pl_newpl_r ("X",0,stdout,stderr,chart->pl_params);
55
56   if (pl_openpl_r (chart->lp) < 0)      /* open Plotter */
57       return 1;
58
59   pl_fspace_r (chart->lp, 0.0, 0.0, 1000.0, 1000.0); /* set coordinate system */
60   pl_flinewidth_r (chart->lp, 0.25);    /* set line thickness */
61   pl_pencolorname_r (chart->lp, "black"); 
62
63   pl_erase_r (chart->lp);               /* erase graphics display */
64   pl_filltype_r(chart->lp,0);
65
66
67
68   pl_savestate_r(chart->lp);
69
70   /* Set default chartetry */
71   chart->data_top =   900;
72   chart->data_right = 800;
73   chart->data_bottom = 120;
74   chart->data_left = 150;
75   chart->abscissa_top = 70;
76   chart->ordinate_right = 120;
77   chart->title_bottom = 920;
78   chart->legend_left = 810;
79   chart->legend_right = 1000;
80   chart->font_size = 0;
81   strcpy(chart->fill_colour,"red");
82
83
84   /* Get default font size */
85   if ( !chart->font_size) 
86     chart->font_size = pl_fontsize_r(chart->lp, -1);
87
88   /* Draw the data area */
89   pl_box_r(chart->lp, 
90            chart->data_left, chart->data_bottom, 
91            chart->data_right, chart->data_top);
92
93   return 0;
94
95 }
96
97
98
99 /* Draw a tick mark at position
100    If label is non zero, then print it at the tick mark
101 */
102 void
103 draw_tick(struct chart *chart, 
104           enum tick_orientation orientation, 
105           double position, 
106           const char *label, ...)
107 {
108   const int tickSize = 10;
109
110   pl_savestate_r(chart->lp);
111
112   pl_move_r(chart->lp, chart->data_left, chart->data_bottom);
113
114   if ( orientation == TICK_ABSCISSA ) 
115     pl_flinerel_r(chart->lp, position, 0, position, -tickSize);
116   else if (orientation == TICK_ORDINATE ) 
117       pl_flinerel_r(chart->lp, 0, position, -tickSize, position);
118   else
119     assert(0);
120
121   if ( label ) {
122     char buf[10];
123     va_list ap;
124     va_start(ap,label);
125     vsnprintf(buf,10,label,ap);
126
127     if ( orientation == TICK_ABSCISSA ) 
128       pl_alabel_r(chart->lp, 'c','t', buf);
129     else if (orientation == TICK_ORDINATE ) 
130       {
131         if ( fabs(position) < DBL_EPSILON )
132             pl_moverel_r(chart->lp, 0, 10);
133
134         pl_alabel_r(chart->lp, 'r','c', buf);
135       }
136
137     va_end(ap);
138   }
139     
140   pl_restorestate_r(chart->lp);
141 }
142
143
144
145
146 /* Write the title on a chart*/
147 void  
148 chart_write_title(struct chart *chart, const char *title, ...)
149 {
150   va_list ap;
151   char buf[100];
152
153   pl_savestate_r(chart->lp);
154   pl_ffontsize_r(chart->lp,chart->font_size * 1.5);
155   pl_move_r(chart->lp,chart->data_left, chart->title_bottom);
156
157   va_start(ap,title);
158   vsnprintf(buf,100,title,ap);
159   pl_alabel_r(chart->lp,0,0,buf);
160   va_end(ap);
161
162   pl_restorestate_r(chart->lp);
163 }
164
165
166
167 void
168 chart_finalise(struct chart *chart)
169 {
170   pl_restorestate_r(chart->lp);
171
172   if (pl_closepl_r (chart->lp) < 0)     /* close Plotter */
173     {
174       fprintf (stderr, "Couldn't close Plotter\n");
175     }
176
177
178   pl_deletepl_r(chart->lp);
179
180   pl_deleteplparams(chart->pl_params);
181
182 }
183
184
185
186   
187 /* Adjust tick to be a sensible value 
188    ie:  ... 0.1,0.2,0.5,   1,2,5,  10,20,50 ... */
189 double
190 chart_rounded_tick(double tick)
191 {
192
193   int i;
194
195   double diff = DBL_MAX;
196   double t = tick;
197     
198   static const double standard_ticks[] = {1, 2, 5, 10};
199
200   const double factor = pow(10,ceil(log10(standard_ticks[0] / tick))) ;
201
202   for (i = 3  ; i >= 0 ; --i) 
203     {
204       const double d = fabs( tick - standard_ticks[i] / factor ) ;
205
206       if ( d < diff ) 
207         {
208           diff = d;
209           t = standard_ticks[i] / factor ;
210         }
211     }
212
213   return t;
214     
215 }
216