1 /* PSPP - draws pie charts of sample statistics
3 Copyright (C) 2004 Free Software Foundation, Inc.
4 Written by John Darrington <john@darrington.wattle.id.au>
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License as
8 published by the Free Software Foundation; either version 2 of the
9 License, or (at your option) any later version.
11 This program is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 #include "value-labels.h"
30 /* Pie charts of course need to know Pi :) */
31 #define M_PI ( 22.0 / 7.0 )
34 #define min(A,B) ((A>B)?B:A)
37 /* Draw a single slice of the pie */
39 draw_segment(struct chart *ch,
40 double centre_x, double centre_y,
42 double start_angle, double segment_angle,
46 /* Draw a pie chart */
48 draw_piechart(struct chart *ch, const struct variable *var)
52 const struct freq_tab *frq_tab = &var->p.frq.tab ;
54 const int n_data = frq_tab->n_valid;
55 const double left_label = ch->data_left +
56 (ch->data_right - ch->data_left)/10.0;
58 const double right_label = ch->data_right -
59 (ch->data_right - ch->data_left)/10.0;
61 const double centre_x = (ch->data_right + ch->data_left ) / 2.0 ;
62 const double centre_y = (ch->data_top + ch->data_bottom ) / 2.0 ;
64 const double radius = min(
65 5.0 / 12.0 * (ch->data_top - ch->data_bottom),
66 1.0 / 4.0 * (ch->data_right - ch->data_left)
70 chart_write_title(ch, var->label ? var->label: var->name);
73 for (i = 0 ; i < n_data ; ++i )
75 static double angle=0.0;
76 const struct freq frq = frq_tab->valid[i];
78 const double segment_angle =
79 frq.c / frq_tab->valid_cases * 2 * M_PI ;
81 char *label = val_labs_find (var->val_labs, frq.v );
85 snprintf(l,20,"%g",frq.v.f);
89 const double label_x = centre_x -
90 radius * sin(angle + segment_angle/2.0);
92 const double label_y = centre_y +
93 radius * cos(angle + segment_angle/2.0);
95 /* Fill the segment */
97 centre_x, centre_y, radius,
101 /* Now add the labels */
102 if ( label_x < centre_x )
104 pl_line_r(ch->lp, label_x, label_y,
105 left_label, label_y );
106 pl_moverel_r(ch->lp,0,5);
107 pl_alabel_r(ch->lp,0,0,label);
115 pl_moverel_r(ch->lp,0,5);
116 pl_alabel_r(ch->lp,'r',0,label);
119 angle += segment_angle;
123 /* Draw an outline to the pie */
124 pl_filltype_r(ch->lp,0);
125 pl_fcircle_r (ch->lp, centre_x, centre_y, radius);
132 fill_segment(struct chart *ch,
133 double x0, double y0,
135 double start_angle, double segment_angle) ;
138 /* Fill a segment with the current fill colour */
140 fill_segment(struct chart *ch,
141 double x0, double y0,
143 double start_angle, double segment_angle)
146 const double start_x = x0 - radius * sin(start_angle);
147 const double start_y = y0 + radius * cos(start_angle);
149 const double stop_x =
150 x0 - radius * sin(start_angle + segment_angle);
152 const double stop_y =
153 y0 + radius * cos(start_angle + segment_angle);
155 assert(segment_angle <= 2 * M_PI);
156 assert(segment_angle >= 0);
158 if ( segment_angle > M_PI )
160 /* Then we must draw it in two halves */
161 fill_segment(ch, x0, y0, radius, start_angle, segment_angle / 2.0 );
162 fill_segment(ch, x0, y0, radius, start_angle + segment_angle / 2.0,
163 segment_angle / 2.0 );
167 pl_move_r(ch->lp, x0, y0);
169 pl_cont_r(ch->lp, stop_x, stop_y);
170 pl_cont_r(ch->lp, start_x, start_y);
178 pl_endpath_r(ch->lp);
184 /* Draw a single slice of the pie */
186 draw_segment(struct chart *ch,
187 double x0, double y0,
189 double start_angle, double segment_angle,
192 const double start_x = x0 - radius * sin(start_angle);
193 const double start_y = y0 + radius * cos(start_angle);
195 pl_savestate_r(ch->lp);
197 pl_savestate_r(ch->lp);
198 pl_colorname_r(ch->lp, colour);
200 pl_pentype_r(ch->lp,1);
201 pl_filltype_r(ch->lp,1);
203 fill_segment(ch, x0, y0, radius, start_angle, segment_angle);
204 pl_restorestate_r(ch->lp);
206 /* Draw line dividing segments */
207 pl_pentype_r(ch->lp, 1);
208 pl_fline_r(ch->lp, x0, y0, start_x, start_y);
211 pl_restorestate_r(ch->lp);