1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2004, 2008 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 <libpspp/misc.h>
24 #include <output/charts/box-whisker.h>
25 #include <output/charts/plot-chart.h>
27 #include <output/chart.h>
28 #include <math/chart-geometry.h>
29 #include <math/box-whisker.h>
31 /* Draw a box-and-whiskers plot
34 /* Draw an OUTLIER on the plot CH
38 draw_case (struct chart *ch, double centreline,
39 const struct outlier *outlier)
42 #define MARKER_CIRCLE 4
47 ch->data_bottom + (outlier->value - ch->y_min) * ch->ordinate_scale,
48 outlier->extreme ? MARKER_STAR : MARKER_CIRCLE,
51 pl_moverel_r(ch->lp, 10,0);
53 pl_alabel_r(ch->lp, 'l', 'c', ds_cstr (&outlier->label));
58 boxplot_draw_boxplot (struct chart *ch,
61 const struct box_whisker *bw,
67 const struct ll_list *outliers;
69 const double box_left = box_centre - box_width / 2.0;
71 const double box_right = box_centre + box_width / 2.0;
75 double bottom_whisker ;
78 box_whisker_whiskers (bw, whisker);
79 box_whisker_hinges (bw, hinge);
81 box_bottom = ch->data_bottom + (hinge[0] - ch->y_min ) * ch->ordinate_scale;
83 box_top = ch->data_bottom + (hinge[2] - ch->y_min ) * ch->ordinate_scale;
85 bottom_whisker = ch->data_bottom + (whisker[0] - ch->y_min) *
88 top_whisker = ch->data_bottom + (whisker[1] - ch->y_min) * ch->ordinate_scale;
90 pl_savestate_r(ch->lp);
93 pl_savestate_r (ch->lp);
94 pl_fillcolorname_r (ch->lp, ch->fill_colour);
95 pl_filltype_r (ch->lp,1);
102 pl_restorestate_r (ch->lp);
104 /* Draw the median */
105 pl_savestate_r (ch->lp);
106 pl_linewidth_r (ch->lp, 5);
109 ch->data_bottom + (hinge[1] - ch->y_min) * ch->ordinate_scale,
111 ch->data_bottom + (hinge[1] - ch->y_min) * ch->ordinate_scale);
112 pl_restorestate_r (ch->lp);
114 /* Draw the bottom whisker */
121 /* Draw top whisker */
132 box_centre, bottom_whisker,
133 box_centre, box_bottom);
137 box_centre, top_whisker,
138 box_centre, box_top);
140 outliers = box_whisker_outliers (bw);
141 for (struct ll *ll = ll_head (outliers);
142 ll != ll_null (outliers); ll = ll_next (ll))
144 const struct outlier *outlier = ll_data (ll, struct outlier, ll);
145 draw_case (ch, box_centre, outlier);
148 /* Draw tick mark on x axis */
149 draw_tick(ch, TICK_ABSCISSA, box_centre - ch->data_left, name);
151 pl_restorestate_r(ch->lp);
155 boxplot_draw_yscale (struct chart *ch, double y_max, double y_min)
166 y_tick = chart_rounded_tick (fabs(ch->y_max - ch->y_min) / 5.0);
168 ch->y_min = (ceil( ch->y_min / y_tick ) - 1.0 ) * y_tick;
170 ch->y_max = ( floor( ch->y_max / y_tick ) + 1.0 ) * y_tick;
172 ch->ordinate_scale = fabs(ch->data_top - ch->data_bottom)
173 / fabs(ch->y_max - ch->y_min) ;
175 /* Move to data bottom-left */
177 ch->data_left, ch->data_bottom);
179 for ( d = ch->y_min; d <= ch->y_max ; d += y_tick )
181 draw_tick (ch, TICK_ORDINATE, (d - ch->y_min ) * ch->ordinate_scale, "%g", d);