1 /* PSPP - draws pie charts of sample statistics
3 Copyright (C) 2004 Free Software Foundation, Inc.
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.
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.
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
29 #include <output/charts/piechart.h>
30 #include <output/charts/plot-chart.h>
32 #include <output/chart.h>
33 #include <libpspp/str.h>
34 #include <data/value-labels.h>
39 /* Pie charts of course need to know Pi :) */
41 #define M_PI ( 22.0 / 7.0 )
46 /* Draw a single slice of the pie */
48 draw_segment(struct chart *ch,
49 double centre_x, double centre_y,
51 double start_angle, double segment_angle,
58 piechart_plot(const char *title, const struct slice *slices, int n_slices)
61 double total_magnetude=0;
63 struct chart *ch = chart_create();
65 const double left_label = ch->data_left +
66 (ch->data_right - ch->data_left)/10.0;
68 const double right_label = ch->data_right -
69 (ch->data_right - ch->data_left)/10.0;
71 const double centre_x = (ch->data_right + ch->data_left ) / 2.0 ;
72 const double centre_y = (ch->data_top + ch->data_bottom ) / 2.0 ;
74 const double radius = MIN(
75 5.0 / 12.0 * (ch->data_top - ch->data_bottom),
76 1.0 / 4.0 * (ch->data_right - ch->data_left)
80 chart_write_title(ch, title);
82 for (i = 0 ; i < n_slices ; ++i )
83 total_magnetude += slices[i].magnetude;
85 for (i = 0 ; i < n_slices ; ++i )
87 static double angle=0.0;
89 const double segment_angle =
90 slices[i].magnetude / total_magnetude * 2 * M_PI ;
92 const double label_x = centre_x -
93 radius * sin(angle + segment_angle/2.0);
95 const double label_y = centre_y +
96 radius * cos(angle + segment_angle/2.0);
98 /* Fill the segment */
100 centre_x, centre_y, radius,
101 angle, segment_angle,
104 /* Now add the labels */
105 if ( label_x < centre_x )
107 pl_line_r(ch->lp, label_x, label_y,
108 left_label, label_y );
109 pl_moverel_r(ch->lp,0,5);
110 pl_alabel_r(ch->lp,0,0,slices[i].label);
118 pl_moverel_r(ch->lp,0,5);
119 pl_alabel_r(ch->lp,'r',0,slices[i].label);
122 angle += segment_angle;
126 /* Draw an outline to the pie */
127 pl_filltype_r(ch->lp,0);
128 pl_fcircle_r (ch->lp, centre_x, centre_y, radius);
134 fill_segment(struct chart *ch,
135 double x0, double y0,
137 double start_angle, double segment_angle) ;
140 /* Fill a segment with the current fill colour */
142 fill_segment(struct chart *ch,
143 double x0, double y0,
145 double start_angle, double segment_angle)
148 const double start_x = x0 - radius * sin(start_angle);
149 const double start_y = y0 + radius * cos(start_angle);
151 const double stop_x =
152 x0 - radius * sin(start_angle + segment_angle);
154 const double stop_y =
155 y0 + radius * cos(start_angle + segment_angle);
157 assert(segment_angle <= 2 * M_PI);
158 assert(segment_angle >= 0);
160 if ( segment_angle > M_PI )
162 /* Then we must draw it in two halves */
163 fill_segment(ch, x0, y0, radius, start_angle, segment_angle / 2.0 );
164 fill_segment(ch, x0, y0, radius, start_angle + segment_angle / 2.0,
165 segment_angle / 2.0 );
169 pl_move_r(ch->lp, x0, y0);
171 pl_cont_r(ch->lp, stop_x, stop_y);
172 pl_cont_r(ch->lp, start_x, start_y);
180 pl_endpath_r(ch->lp);
186 /* Draw a single slice of the pie */
188 draw_segment(struct chart *ch,
189 double x0, double y0,
191 double start_angle, double segment_angle,
194 const double start_x = x0 - radius * sin(start_angle);
195 const double start_y = y0 + radius * cos(start_angle);
197 pl_savestate_r(ch->lp);
199 pl_savestate_r(ch->lp);
200 pl_colorname_r(ch->lp, colour);
202 pl_pentype_r(ch->lp,1);
203 pl_filltype_r(ch->lp,1);
205 fill_segment(ch, x0, y0, radius, start_angle, segment_angle);
206 pl_restorestate_r(ch->lp);
208 /* Draw line dividing segments */
209 pl_pentype_r(ch->lp, 1);
210 pl_fline_r(ch->lp, x0, y0, start_x, start_y);
213 pl_restorestate_r(ch->lp);