1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2004 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
22 #include <gsl/gsl_math.h>
27 #include <output/charts/piechart.h>
28 #include <output/charts/plot-chart.h>
30 #include <output/chart.h>
31 #include <libpspp/str.h>
32 #include <data/value-labels.h>
36 /* Draw a single slice of the pie */
38 draw_segment(struct chart *ch,
39 double centre_x, double centre_y,
41 double start_angle, double segment_angle,
48 piechart_plot(const char *title, const struct slice *slices, int n_slices)
51 double total_magnetude=0;
53 struct chart *ch = chart_create();
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, title);
72 for (i = 0 ; i < n_slices ; ++i )
73 total_magnetude += slices[i].magnetude;
75 for (i = 0 ; i < n_slices ; ++i )
77 static double angle=0.0;
79 const double segment_angle =
80 slices[i].magnetude / total_magnetude * 2 * M_PI ;
82 const double label_x = centre_x -
83 radius * sin(angle + segment_angle/2.0);
85 const double label_y = centre_y +
86 radius * cos(angle + segment_angle/2.0);
88 /* Fill the segment */
90 centre_x, centre_y, radius,
92 data_colour[i % N_CHART_COLOURS]);
94 /* Now add the labels */
95 if ( label_x < centre_x )
97 pl_line_r(ch->lp, label_x, label_y,
98 left_label, label_y );
99 pl_moverel_r(ch->lp,0,5);
100 pl_alabel_r (ch->lp, 0, 0, ds_cstr (&slices[i].label));
108 pl_moverel_r(ch->lp,0,5);
109 pl_alabel_r (ch->lp, 'r', 0, ds_cstr (&slices[i].label));
112 angle += segment_angle;
116 /* Draw an outline to the pie */
117 pl_filltype_r(ch->lp,0);
118 pl_fcircle_r (ch->lp, centre_x, centre_y, radius);
124 fill_segment(struct chart *ch,
125 double x0, double y0,
127 double start_angle, double segment_angle) ;
130 /* Fill a segment with the current fill colour */
132 fill_segment(struct chart *ch,
133 double x0, double y0,
135 double start_angle, double segment_angle)
138 const double start_x = x0 - radius * sin(start_angle);
139 const double start_y = y0 + radius * cos(start_angle);
141 const double stop_x =
142 x0 - radius * sin(start_angle + segment_angle);
144 const double stop_y =
145 y0 + radius * cos(start_angle + segment_angle);
147 assert(segment_angle <= 2 * M_PI);
148 assert(segment_angle >= 0);
150 if ( segment_angle > M_PI )
152 /* Then we must draw it in two halves */
153 fill_segment(ch, x0, y0, radius, start_angle, segment_angle / 2.0 );
154 fill_segment(ch, x0, y0, radius, start_angle + segment_angle / 2.0,
155 segment_angle / 2.0 );
159 pl_move_r(ch->lp, x0, y0);
161 pl_cont_r(ch->lp, stop_x, stop_y);
162 pl_cont_r(ch->lp, start_x, start_y);
170 pl_endpath_r(ch->lp);
176 /* Draw a single slice of the pie */
178 draw_segment(struct chart *ch,
179 double x0, double y0,
181 double start_angle, double segment_angle,
184 const double start_x = x0 - radius * sin(start_angle);
185 const double start_y = y0 + radius * cos(start_angle);
187 pl_savestate_r(ch->lp);
189 pl_savestate_r(ch->lp);
190 pl_colorname_r(ch->lp, colour);
192 pl_pentype_r(ch->lp,1);
193 pl_filltype_r(ch->lp,1);
195 fill_segment(ch, x0, y0, radius, start_angle, segment_angle);
196 pl_restorestate_r(ch->lp);
198 /* Draw line dividing segments */
199 pl_pentype_r(ch->lp, 1);
200 pl_fline_r(ch->lp, x0, y0, start_x, start_y);
203 pl_restorestate_r(ch->lp);