1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2004, 2009 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/>. */
20 #include <output/charts/piechart.h>
24 #include <gsl/gsl_math.h>
28 #include <data/value-labels.h>
29 #include <libpspp/cast.h>
30 #include <libpspp/str.h>
31 #include <output/charts/plot-chart.h>
32 #include <output/chart-provider.h>
44 static const struct chart_class piechart_class;
46 /* Draw a single slice of the pie */
48 draw_segment(cairo_t *,
49 double centre_x, double centre_y,
51 double start_angle, double segment_angle,
52 const struct chart_colour *) ;
56 /* Creates and returns a chart that will render a piechart with
57 the given TITLE and the N_SLICES described in SLICES. */
59 piechart_create (const char *title, const struct slice *slices, int n_slices)
64 pie = xmalloc (sizeof *pie);
65 chart_init (&pie->chart, &piechart_class);
66 pie->title = xstrdup (title);
67 pie->slices = xnmalloc (n_slices, sizeof *pie->slices);
68 for (i = 0; i < n_slices; i++)
70 const struct slice *src = &slices[i];
71 struct slice *dst = &pie->slices[i];
73 ds_init_string (&dst->label, &src->label);
74 dst->magnitude = src->magnitude;
76 pie->n_slices = n_slices;
81 piechart_draw (const struct chart *chart, cairo_t *cr,
82 struct chart_geometry *geom)
84 const struct piechart *pie = UP_CAST (chart, struct piechart, chart);
85 double total_magnitude;
86 double left_label, right_label;
87 double centre_x, centre_y;
92 centre_x = (geom->data_right + geom->data_left) / 2.0 ;
93 centre_y = (geom->data_top + geom->data_bottom) / 2.0 ;
95 left_label = geom->data_left + (geom->data_right - geom->data_left)/10.0;
96 right_label = geom->data_right - (geom->data_right - geom->data_left)/10.0;
98 radius = MIN (5.0 / 12.0 * (geom->data_top - geom->data_bottom),
99 1.0 / 4.0 * (geom->data_right - geom->data_left));
101 radius = MIN (5.0 / 12.0 * (geom->data_top - geom->data_bottom),
102 1.0 / 4.0 * (geom->data_right - geom->data_left));
104 chart_write_title (cr, geom, "%s", pie->title);
106 total_magnitude = 0.0;
107 for (i = 0; i < pie->n_slices; i++)
108 total_magnitude += pie->slices[i].magnitude;
111 for (i = 0; i < pie->n_slices ; ++i )
113 const double segment_angle =
114 pie->slices[i].magnitude / total_magnitude * 2 * M_PI ;
116 const double label_x = centre_x -
117 radius * sin(angle + segment_angle/2.0);
119 const double label_y = centre_y +
120 radius * cos(angle + segment_angle/2.0);
122 /* Fill the segment */
124 centre_x, centre_y, radius,
125 angle, segment_angle,
126 &data_colour[i % N_CHART_COLOURS]);
128 /* Now add the labels */
129 if ( label_x < centre_x )
131 cairo_move_to (cr, label_x, label_y);
132 cairo_line_to (cr, left_label, label_y);
134 cairo_move_to (cr, left_label, label_y + 5);
135 chart_label (cr, 'l', 'x', geom->font_size,
136 ds_cstr (&pie->slices[i].label));
140 cairo_move_to (cr, label_x, label_y);
141 cairo_line_to (cr, right_label, label_y);
143 cairo_move_to (cr, right_label, label_y + 5);
144 chart_label (cr, 'r', 'x', geom->font_size,
145 ds_cstr (&pie->slices[i].label));
148 angle += segment_angle;
151 /* Draw an outline to the pie */
152 cairo_arc (cr, centre_x, centre_y, radius, 0, 2 * M_PI);
156 /* Draw a single slice of the pie */
158 draw_segment(cairo_t *cr,
159 double x0, double y0,
161 double start_angle, double segment_angle,
162 const struct chart_colour *colour)
164 cairo_move_to (cr, x0, y0);
165 cairo_arc (cr, x0, y0, radius, start_angle, start_angle + segment_angle);
166 cairo_line_to (cr, x0, y0);
168 cairo_set_source_rgb (cr,
170 colour->green / 255.0,
171 colour->blue / 255.0);
172 cairo_fill_preserve (cr);
178 piechart_destroy (struct chart *chart)
180 struct piechart *pie = UP_CAST (chart, struct piechart, chart);
184 for (i = 0; i < pie->n_slices; i++)
186 struct slice *slice = &pie->slices[i];
187 ds_destroy (&slice->label);
193 static const struct chart_class piechart_class =