The PLOT subcommand specifies which plots are to be produced if any.
+The COMPARE subcommand is only relevant if producing boxplots, and it is only
+useful there is more than one dependent variable and at least one factor. If
+/COMPARE=GROUPS is specified, then one plot per dependent variable is produced,
+containing boxplots for all the factors.
+If /COMPARE=VARIABLES is specified, then one plot per factor is produced, each
+each containing one boxplot per dependent variable.
+If the /COMPARE subcommand is ommitted, then PSPP uses the default value of
+/COMPARE=GROUPS.
+
The CINTERVAL subcommand specifies the confidence interval to use in
calculation of the descriptives command. The default it 95%.
msgstr ""
"Project-Id-Version: PSPP 0.3.1\n"
"Report-Msgid-Bugs-To: pspp-dev@gnu.org\n"
-"POT-Creation-Date: 2004-12-29 08:18+0800\n"
+"POT-Creation-Date: 2004-12-31 08:53+0800\n"
"PO-Revision-Date: 2004-01-23 13:04+0800\n"
"Last-Translator: John Darrington <john@darrington.wattle.id.au>\n"
"Language-Team: John Darrington <john@darrington.wattle.id.au>\n"
msgid "Only USE ALL is currently implemented."
msgstr ""
-#: src/descript.c:99 src/examine.q:1400 src/frequencies.q:112 src/oneway.q:396
+#: src/descript.c:99 src/examine.q:1420 src/frequencies.q:112 src/oneway.q:396
#: src/t-test.q:690 src/t-test.q:713 src/t-test.q:836 src/t-test.q:1173
msgid "Mean"
msgstr ""
msgid "Std Dev"
msgstr ""
-#: src/descript.c:102 src/examine.q:1478 src/frequencies.q:117
+#: src/descript.c:102 src/examine.q:1498 src/frequencies.q:117
msgid "Variance"
msgstr ""
-#: src/descript.c:103 src/examine.q:1585 src/frequencies.q:118
+#: src/descript.c:103 src/examine.q:1605 src/frequencies.q:118
msgid "Kurtosis"
msgstr ""
msgid "S E Kurt"
msgstr ""
-#: src/descript.c:105 src/examine.q:1565 src/frequencies.q:120
+#: src/descript.c:105 src/examine.q:1585 src/frequencies.q:120
msgid "Skewness"
msgstr ""
msgid "S E Skew"
msgstr ""
-#: src/descript.c:107 src/examine.q:1526 src/frequencies.q:122
+#: src/descript.c:107 src/examine.q:1546 src/frequencies.q:122
msgid "Range"
msgstr ""
-#: src/descript.c:108 src/examine.q:1503 src/frequencies.q:123
+#: src/descript.c:108 src/examine.q:1523 src/frequencies.q:123
#: src/oneway.q:408
msgid "Minimum"
msgstr ""
-#: src/descript.c:109 src/examine.q:1514 src/frequencies.q:124
+#: src/descript.c:109 src/examine.q:1534 src/frequencies.q:124
#: src/oneway.q:409
msgid "Maximum"
msgstr ""
#: src/sysfile-info.c:531 src/vfm.c:875 src/crosstabs.q:1099
#: src/crosstabs.q:1126 src/crosstabs.q:1146 src/crosstabs.q:1168
-#: src/examine.q:1054 src/frequencies.q:1136 src/frequencies.q:1257
+#: src/examine.q:1074 src/frequencies.q:1136 src/frequencies.q:1257
msgid "Value"
msgstr ""
msgid "Summary."
msgstr ""
-#: src/crosstabs.q:802 src/examine.q:838
+#: src/crosstabs.q:802 src/examine.q:858
msgid "Cases"
msgstr ""
-#: src/crosstabs.q:803 src/examine.q:772 src/frequencies.q:1134
+#: src/crosstabs.q:803 src/examine.q:792 src/frequencies.q:1134
#: src/frequencies.q:1507
msgid "Valid"
msgstr ""
-#: src/crosstabs.q:804 src/examine.q:773 src/frequencies.q:1202
+#: src/crosstabs.q:804 src/examine.q:793 src/frequencies.q:1202
#: src/frequencies.q:1508
msgid "Missing"
msgstr ""
#: src/crosstabs.q:805 src/crosstabs.q:1008 src/crosstabs.q:1722
-#: src/examine.q:774 src/frequencies.q:1211 src/oneway.q:307 src/oneway.q:486
+#: src/examine.q:794 src/frequencies.q:1211 src/oneway.q:307 src/oneway.q:486
msgid "Total"
msgstr ""
-#: src/crosstabs.q:815 src/examine.q:850 src/frequencies.q:1506
+#: src/crosstabs.q:815 src/examine.q:870 src/frequencies.q:1506
#: src/oneway.q:395 src/t-test.q:689 src/t-test.q:712 src/t-test.q:837
#: src/t-test.q:1372
msgid "N"
msgstr ""
-#: src/crosstabs.q:816 src/examine.q:853 src/frequencies.q:1138
+#: src/crosstabs.q:816 src/examine.q:873 src/frequencies.q:1138
#: src/frequencies.q:1139 src/frequencies.q:1140
msgid "Percent"
msgstr ""
msgstr ""
#: src/crosstabs.q:1098 src/crosstabs.q:1125 src/crosstabs.q:1145
-#: src/crosstabs.q:1166 src/examine.q:1288
+#: src/crosstabs.q:1166 src/examine.q:1308
msgid "Statistic"
msgstr ""
msgid "%s Dependent"
msgstr ""
-#: src/examine.q:418 src/examine.q:430
+#: src/examine.q:438 src/examine.q:450
#, c-format
msgid "%s and %s are mutually exclusive"
msgstr ""
-#: src/examine.q:832
+#: src/examine.q:852
msgid "Case Processing Summary"
msgstr ""
-#: src/examine.q:1038
+#: src/examine.q:1058
msgid "Extreme Values"
msgstr ""
-#: src/examine.q:1055
+#: src/examine.q:1075
msgid "Case Number"
msgstr ""
-#: src/examine.q:1143
+#: src/examine.q:1163
msgid "Highest"
msgstr ""
-#: src/examine.q:1148
+#: src/examine.q:1168
msgid "Lowest"
msgstr ""
-#: src/examine.q:1289 src/oneway.q:398 src/oneway.q:705
+#: src/examine.q:1309 src/oneway.q:398 src/oneway.q:705
msgid "Std. Error"
msgstr ""
-#: src/examine.q:1291 src/oneway.q:412
+#: src/examine.q:1311 src/oneway.q:412
msgid "Descriptives"
msgstr ""
-#: src/examine.q:1418 src/oneway.q:403
+#: src/examine.q:1438 src/oneway.q:403
#, c-format
msgid "%g%% Confidence Interval for Mean"
msgstr ""
-#: src/examine.q:1424 src/oneway.q:405
+#: src/examine.q:1444 src/oneway.q:405
msgid "Lower Bound"
msgstr ""
-#: src/examine.q:1435 src/oneway.q:406
+#: src/examine.q:1455 src/oneway.q:406
msgid "Upper Bound"
msgstr ""
-#: src/examine.q:1447
+#: src/examine.q:1467
msgid "5% Trimmed Mean"
msgstr ""
-#: src/examine.q:1458 src/frequencies.q:114
+#: src/examine.q:1478 src/frequencies.q:114
msgid "Median"
msgstr ""
-#: src/examine.q:1490 src/oneway.q:397 src/t-test.q:691 src/t-test.q:714
+#: src/examine.q:1510 src/oneway.q:397 src/t-test.q:691 src/t-test.q:714
#: src/t-test.q:838 src/t-test.q:1174
msgid "Std. Deviation"
msgstr ""
-#: src/examine.q:1538
+#: src/examine.q:1558
msgid "Interquartile Range"
msgstr ""
-#: src/examine.q:1628
+#: src/examine.q:1708
+#, c-format
+msgid "Boxplot of %s"
+msgstr ""
+
+#: src/examine.q:1734
+msgid "Boxplot"
+msgstr ""
+
+#: src/examine.q:1773
#, c-format
msgid "Normal Q-Q Plot of %s"
msgstr ""
-#: src/examine.q:1629 src/examine.q:1635
+#: src/examine.q:1774 src/examine.q:1780
msgid "Observed Value"
msgstr ""
-#: src/examine.q:1630
+#: src/examine.q:1775
msgid "Expected Normal"
msgstr ""
-#: src/examine.q:1633
+#: src/examine.q:1778
#, c-format
msgid "Detrended Normal Q-Q Plot of %s"
msgstr ""
-#: src/examine.q:1636
+#: src/examine.q:1781
msgid "Dev from Normal"
msgstr ""
-#: src/examine.q:1757 src/examine.q:1779 src/frequencies.q:1518
+#: src/examine.q:1902 src/examine.q:1924 src/frequencies.q:1518
msgid "Percentiles"
msgstr ""
-#: src/examine.q:1904
+#: src/examine.q:2049
msgid "Tukey's Hinges"
msgstr ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: pspp-dev@gnu.org\n"
-"POT-Creation-Date: 2004-12-29 08:18+0800\n"
+"POT-Creation-Date: 2004-12-31 08:53+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
msgid "Only USE ALL is currently implemented."
msgstr ""
-#: src/descript.c:99 src/examine.q:1400 src/frequencies.q:112 src/oneway.q:396
+#: src/descript.c:99 src/examine.q:1420 src/frequencies.q:112 src/oneway.q:396
#: src/t-test.q:690 src/t-test.q:713 src/t-test.q:836 src/t-test.q:1173
msgid "Mean"
msgstr ""
msgid "Std Dev"
msgstr ""
-#: src/descript.c:102 src/examine.q:1478 src/frequencies.q:117
+#: src/descript.c:102 src/examine.q:1498 src/frequencies.q:117
msgid "Variance"
msgstr ""
-#: src/descript.c:103 src/examine.q:1585 src/frequencies.q:118
+#: src/descript.c:103 src/examine.q:1605 src/frequencies.q:118
msgid "Kurtosis"
msgstr ""
msgid "S E Kurt"
msgstr ""
-#: src/descript.c:105 src/examine.q:1565 src/frequencies.q:120
+#: src/descript.c:105 src/examine.q:1585 src/frequencies.q:120
msgid "Skewness"
msgstr ""
msgid "S E Skew"
msgstr ""
-#: src/descript.c:107 src/examine.q:1526 src/frequencies.q:122
+#: src/descript.c:107 src/examine.q:1546 src/frequencies.q:122
msgid "Range"
msgstr ""
-#: src/descript.c:108 src/examine.q:1503 src/frequencies.q:123
+#: src/descript.c:108 src/examine.q:1523 src/frequencies.q:123
#: src/oneway.q:408
msgid "Minimum"
msgstr ""
-#: src/descript.c:109 src/examine.q:1514 src/frequencies.q:124
+#: src/descript.c:109 src/examine.q:1534 src/frequencies.q:124
#: src/oneway.q:409
msgid "Maximum"
msgstr ""
#: src/sysfile-info.c:531 src/vfm.c:875 src/crosstabs.q:1099
#: src/crosstabs.q:1126 src/crosstabs.q:1146 src/crosstabs.q:1168
-#: src/examine.q:1054 src/frequencies.q:1136 src/frequencies.q:1257
+#: src/examine.q:1074 src/frequencies.q:1136 src/frequencies.q:1257
msgid "Value"
msgstr ""
msgid "Summary."
msgstr ""
-#: src/crosstabs.q:802 src/examine.q:838
+#: src/crosstabs.q:802 src/examine.q:858
msgid "Cases"
msgstr ""
-#: src/crosstabs.q:803 src/examine.q:772 src/frequencies.q:1134
+#: src/crosstabs.q:803 src/examine.q:792 src/frequencies.q:1134
#: src/frequencies.q:1507
msgid "Valid"
msgstr ""
-#: src/crosstabs.q:804 src/examine.q:773 src/frequencies.q:1202
+#: src/crosstabs.q:804 src/examine.q:793 src/frequencies.q:1202
#: src/frequencies.q:1508
msgid "Missing"
msgstr ""
#: src/crosstabs.q:805 src/crosstabs.q:1008 src/crosstabs.q:1722
-#: src/examine.q:774 src/frequencies.q:1211 src/oneway.q:307 src/oneway.q:486
+#: src/examine.q:794 src/frequencies.q:1211 src/oneway.q:307 src/oneway.q:486
msgid "Total"
msgstr ""
-#: src/crosstabs.q:815 src/examine.q:850 src/frequencies.q:1506
+#: src/crosstabs.q:815 src/examine.q:870 src/frequencies.q:1506
#: src/oneway.q:395 src/t-test.q:689 src/t-test.q:712 src/t-test.q:837
#: src/t-test.q:1372
msgid "N"
msgstr ""
-#: src/crosstabs.q:816 src/examine.q:853 src/frequencies.q:1138
+#: src/crosstabs.q:816 src/examine.q:873 src/frequencies.q:1138
#: src/frequencies.q:1139 src/frequencies.q:1140
msgid "Percent"
msgstr ""
msgstr ""
#: src/crosstabs.q:1098 src/crosstabs.q:1125 src/crosstabs.q:1145
-#: src/crosstabs.q:1166 src/examine.q:1288
+#: src/crosstabs.q:1166 src/examine.q:1308
msgid "Statistic"
msgstr ""
msgid "%s Dependent"
msgstr ""
-#: src/examine.q:418 src/examine.q:430
+#: src/examine.q:438 src/examine.q:450
#, c-format
msgid "%s and %s are mutually exclusive"
msgstr ""
-#: src/examine.q:832
+#: src/examine.q:852
msgid "Case Processing Summary"
msgstr ""
-#: src/examine.q:1038
+#: src/examine.q:1058
msgid "Extreme Values"
msgstr ""
-#: src/examine.q:1055
+#: src/examine.q:1075
msgid "Case Number"
msgstr ""
-#: src/examine.q:1143
+#: src/examine.q:1163
msgid "Highest"
msgstr ""
-#: src/examine.q:1148
+#: src/examine.q:1168
msgid "Lowest"
msgstr ""
-#: src/examine.q:1289 src/oneway.q:398 src/oneway.q:705
+#: src/examine.q:1309 src/oneway.q:398 src/oneway.q:705
msgid "Std. Error"
msgstr ""
-#: src/examine.q:1291 src/oneway.q:412
+#: src/examine.q:1311 src/oneway.q:412
msgid "Descriptives"
msgstr ""
-#: src/examine.q:1418 src/oneway.q:403
+#: src/examine.q:1438 src/oneway.q:403
#, c-format
msgid "%g%% Confidence Interval for Mean"
msgstr ""
-#: src/examine.q:1424 src/oneway.q:405
+#: src/examine.q:1444 src/oneway.q:405
msgid "Lower Bound"
msgstr ""
-#: src/examine.q:1435 src/oneway.q:406
+#: src/examine.q:1455 src/oneway.q:406
msgid "Upper Bound"
msgstr ""
-#: src/examine.q:1447
+#: src/examine.q:1467
msgid "5% Trimmed Mean"
msgstr ""
-#: src/examine.q:1458 src/frequencies.q:114
+#: src/examine.q:1478 src/frequencies.q:114
msgid "Median"
msgstr ""
-#: src/examine.q:1490 src/oneway.q:397 src/t-test.q:691 src/t-test.q:714
+#: src/examine.q:1510 src/oneway.q:397 src/t-test.q:691 src/t-test.q:714
#: src/t-test.q:838 src/t-test.q:1174
msgid "Std. Deviation"
msgstr ""
-#: src/examine.q:1538
+#: src/examine.q:1558
msgid "Interquartile Range"
msgstr ""
-#: src/examine.q:1628
+#: src/examine.q:1708
+#, c-format
+msgid "Boxplot of %s"
+msgstr ""
+
+#: src/examine.q:1734
+msgid "Boxplot"
+msgstr ""
+
+#: src/examine.q:1773
#, c-format
msgid "Normal Q-Q Plot of %s"
msgstr ""
-#: src/examine.q:1629 src/examine.q:1635
+#: src/examine.q:1774 src/examine.q:1780
msgid "Observed Value"
msgstr ""
-#: src/examine.q:1630
+#: src/examine.q:1775
msgid "Expected Normal"
msgstr ""
-#: src/examine.q:1633
+#: src/examine.q:1778
#, c-format
msgid "Detrended Normal Q-Q Plot of %s"
msgstr ""
-#: src/examine.q:1636
+#: src/examine.q:1781
msgid "Dev from Normal"
msgstr ""
-#: src/examine.q:1757 src/examine.q:1779 src/frequencies.q:1518
+#: src/examine.q:1902 src/examine.q:1924 src/frequencies.q:1518
msgid "Percentiles"
msgstr ""
-#: src/examine.q:1904
+#: src/examine.q:2049
msgid "Tukey's Hinges"
msgstr ""
+Fri Dec 31 16:47:45 WST 2004 John Darrington <john@darrington.wattle.id.au>
+
+ * examine.q box-whisker.c chart.h Implemented boxplots in EXAMINE
+
+ * percentiles.c Fixed some bugs when calculating percentiles when
+ there's a small number of cases.
+
Wed Dec 29 08:18:08 WST 2004 John Darrington <john@darrington.wattle.id.au>
* percentiles.[ch] Added. Calculates percentiles and Tukey hinges
#include "chart.h"
#include <math.h>
+#include "misc.h"
-/* Draw a box-and-whiskers plot
-*/
-
-struct data_stats
-{
- double ptile0 ;
- double ptile25 ;
- double median ;
- double ptile75 ;
-
- double ptile100;
-
- double outlier ;
-};
-
-
-const struct data_stats stats1 = {
- 40,
- 45,
- 54,
- 60,
- 70,
-
- 33
-};
-
-const struct data_stats stats2 = {
- 30,
- 40,
- 45,
- 54,
- 60,
-
-
- 72
-};
-
-
-
-
-
-static const double y_min = 25;
-static const double y_max = 75;
-static const double y_tick = 10;
+#include "factor_stats.h"
+/* Draw a box-and-whiskers plot
+*/
-#define min(A,B) ((A>B)?B:A)
-
-
-void draw_box_and_whiskers(struct chart *ch,
- double box_centre, const struct data_stats *s,
- const char *name);
-
+/* Draw an outlier on the plot CH
+ * at CENTRELINE
+ * The outlier is in (*wvp)[idx]
+ * If EXTREME is non zero, then consider it to be an extreme
+ * value
+ */
+void
+draw_outlier(struct chart *ch, double centreline,
+ struct weighted_value **wvp,
+ int idx,
+ short extreme);
-static double ordinate_scale;
-void
-draw_box_whisker_chart(struct chart *ch, const char *title)
+void
+draw_outlier(struct chart *ch, double centreline,
+ struct weighted_value **wvp,
+ int idx,
+ short extreme
+ )
{
- double d;
+ char label[10];
- ordinate_scale = fabs(ch->data_top - ch->data_bottom) / fabs(y_max - y_min) ;
+#define MARKER_CIRCLE 4
+#define MARKER_STAR 3
+ pl_fmarker_r(ch->lp,
+ centreline,
+ ch->data_bottom +
+ (wvp[idx]->v.f - ch->y_min ) * ch->ordinate_scale,
+ extreme?MARKER_STAR:MARKER_CIRCLE,
+ 20);
- chart_write_title(ch, title);
+ pl_moverel_r(ch->lp, 10,0);
+ snprintf(label, 10, "%d", wvp[idx]->case_nos->num);
-
- /* Move to data bottom-left */
- pl_move_r(ch->lp,
- ch->data_left, ch->data_bottom);
-
- for ( d = y_min; d <= y_max ; d += y_tick )
- {
- draw_tick (ch, TICK_ORDINATE, (d - y_min ) * ordinate_scale, "%g", d);
- }
-
- draw_box_and_whiskers(ch,
- ch->data_left + 1.0/4.0 * (ch->data_right - ch->data_left) ,
- &stats1,"Stats1"
- );
-
- draw_box_and_whiskers(ch,
- ch->data_left + 3.0/4.0 * (ch->data_right - ch->data_left),
- &stats2,"Stats2"
- );
-
+ pl_alabel_r(ch->lp, 'l', 'c', label);
}
void
-draw_box_and_whiskers(struct chart *ch,
- double box_centre, const struct data_stats *s,
- const char *name)
+boxplot_draw_boxplot(struct chart *ch,
+ double box_centre,
+ double box_width,
+ struct metrics *m,
+ /*
+ const double hinge[3],
+ struct weighted_value **wvp,
+ int n_data,
+ */
+ const char *name)
{
+ double whisker[2];
+ int i;
+
+
+ const double *hinge = m->hinge;
+ struct weighted_value **wvp = m->wvp;
+ const int n_data = m->n_data;
+
+ const double step = (hinge[2] - hinge[0]) * 1.5;
- const double box_width = (ch->data_right - ch->data_left) / 4.0;
const double box_left = box_centre - box_width / 2.0;
const double box_bottom =
- ch->data_bottom + ( s->ptile25 - y_min ) * ordinate_scale;
+ ch->data_bottom + ( hinge[0] - ch->y_min ) * ch->ordinate_scale;
const double box_top =
- ch->data_bottom + ( s->ptile75 - y_min ) * ordinate_scale;
+ ch->data_bottom + ( hinge[2] - ch->y_min ) * ch->ordinate_scale;
+ whisker[1] = hinge[2];
+ whisker[0] = wvp[0]->v.f;
- const double iq_range = s->ptile75 - s->ptile25;
+ for ( i = 0 ; i < n_data ; ++i )
+ {
+ if ( hinge[2] + step > wvp[i]->v.f)
+ whisker[1] = wvp[i]->v.f;
+ if ( hinge[0] - step > wvp[i]->v.f)
+ whisker[0] = wvp[i]->v.f;
+
+ }
+
+
const double bottom_whisker =
- ch->data_bottom + (min(s->ptile0,s->ptile25 + iq_range*1.5) - y_min ) *
- ordinate_scale;
+ ch->data_bottom + ( whisker[0] - ch->y_min ) * ch->ordinate_scale;
+
+ const double top_whisker =
+ ch->data_bottom + ( whisker[1] - ch->y_min ) * ch->ordinate_scale;
- const double top_whisker =
- ch->data_bottom + (min(s->ptile100,s->ptile75 + iq_range*1.5) - y_min ) *
- ordinate_scale;
pl_savestate_r(ch->lp);
pl_linewidth_r(ch->lp,5);
pl_fline_r(ch->lp,
box_left,
- ch->data_bottom + ( s->median - y_min ) * ordinate_scale,
+ ch->data_bottom + ( hinge[1] - ch->y_min ) * ch->ordinate_scale,
box_right,
- ch->data_bottom + ( s->median - y_min ) * ordinate_scale);
+ ch->data_bottom + ( hinge[1] - ch->y_min ) * ch->ordinate_scale);
pl_restorestate_r(ch->lp);
top_whisker);
+
/* Draw centre line.
(bottom half) */
pl_fline_r(ch->lp,
box_centre, top_whisker,
box_centre, box_top);
-
- /* Draw an outlier */
- pl_fcircle_r(ch->lp,
- box_centre,
- ch->data_bottom + (s->outlier - y_min ) * ordinate_scale,
- 5);
-
- pl_moverel_r(ch->lp, 10,0);
- pl_alabel_r(ch->lp,'l','c',"123");
+ /* Draw outliers */
+ for ( i = 0 ; i < n_data ; ++i )
+ {
+ if ( wvp[i]->v.f >= hinge[2] + step )
+ draw_outlier(ch, box_centre, wvp, i,
+ ( wvp[i]->v.f > hinge[2] + 2 * step )
+ );
+
+ if ( wvp[i]->v.f <= hinge[0] - step )
+ draw_outlier(ch, box_centre, wvp, i,
+ ( wvp[i]->v.f < hinge[0] - 2 * step )
+ );
+ }
/* Draw tick mark on x axis */
}
+
+
+void
+boxplot_draw_yscale(struct chart *ch , double y_max, double y_min)
+{
+ double y_tick;
+ double d;
+
+ ch->y_max = y_max;
+ ch->y_min = y_min;
+
+ y_tick = chart_rounded_tick(fabs(ch->y_max - ch->y_min) / 5.0);
+
+ ch->y_min = (ceil( ch->y_min / y_tick ) - 1.0 ) * y_tick;
+
+ ch->y_max = ( floor( ch->y_max / y_tick ) + 1.0 ) * y_tick;
+
+ ch->ordinate_scale = fabs(ch->data_top - ch->data_bottom)
+ / fabs(ch->y_max - ch->y_min) ;
+
+
+ /* Move to data bottom-left */
+ pl_move_r(ch->lp,
+ ch->data_left, ch->data_bottom);
+
+ for ( d = ch->y_min; d <= ch->y_max ; d += y_tick )
+ {
+ draw_tick (ch, TICK_ORDINATE, (d - ch->y_min ) * ch->ordinate_scale, "%g", d);
+ }
+
+}
char fill_colour[10];
- /* Stuff Particular to Cartesians */
+ /* Stuff Particular to Cartesians (and Boxplots ) */
double ordinate_scale;
double abscissa_scale;
double x_min;
void chart_datum(struct chart *ch, int dataset, double x, double y);
+struct metrics;
+void boxplot_draw_boxplot(struct chart *ch,
+ double box_centre,
+ double box_width,
+ struct metrics *m,
+ const char *name);
+
+
+void boxplot_draw_yscale(struct chart *ch , double y_max, double y_min);
+
enum CHART_DIM
{
incl:include/!exclude;
+compare=cmp:variables/!groups;
+percentiles=custom;
+ +id=var;
+plot[plt_]=stemleaf,boxplot,npplot,:spreadlevel(*d:n),histogram,all,none;
+cinterval=double;
+statistics[st_]=descriptives,:extreme(*d:n),all,none.
+
void np_plot(const struct metrics *m, const char *factorname);
+void box_plot_group(const struct factor *fctr,
+ const struct variable **vars, int n_vars,
+ const struct variable *id
+ ) ;
+
+
+void box_plot_variables(const struct factor *fctr,
+ struct variable **vars, int n_vars,
+ const struct variable *id
+ );
+
+
/* Per Split function */
static void run_examine(const struct casefile *cf, void *cmd_);
double weight, int case_missing);
+/* Represent a factor as a string, so it can be
+ printed in a human readable fashion */
+const char * factor_to_string(const struct factor *fctr,
+ struct factor_statistics *fs,
+ const struct variable *var);
+
+
+/* Represent a factor as a string, so it can be
+ printed in a human readable fashion,
+ but sacrificing some readablility for the sake of brevity */
+const char *factor_to_string_concise(const struct factor *fctr,
+ struct factor_statistics *fs);
+
+
+
+
/* Function to use for testing for missing values */
static is_missing_func value_is_missing;
if ( ! cmd.sbc_cinterval)
cmd.n_cinterval[0] = 95.0;
-
/* If descriptives have been requested, make sure the
quartiles are calculated */
if ( cmd.a_statistics[XMN_ST_DESCRIPTIVES] )
np_plot(&totals[v], var_to_string(dependent_vars[v]));
}
+ if ( cmd.a_plot[XMN_PLT_BOXPLOT] )
+ {
+ if ( cmd.cmp == XMN_GROUPS )
+ {
+ box_plot_group(0, dependent_vars, n_dependent_vars,
+ cmd.v_id);
+ }
+ else
+ box_plot_variables(0, dependent_vars, n_dependent_vars,
+ cmd.v_id);
+ }
+
if ( cmd.a_plot[XMN_PLT_HISTOGRAM] )
{
for ( v = 0 ; v < n_dependent_vars; ++v )
struct factor_statistics **fs = fctr->fs ;
+ if ( cmd.a_plot[XMN_PLT_BOXPLOT] )
+ {
+ if ( cmd.cmp == XMN_VARIABLES )
+ box_plot_variables(fctr, dependent_vars, n_dependent_vars,
+ cmd.v_id);
+ else
+ box_plot_group(fctr, dependent_vars, n_dependent_vars,
+ cmd.v_id);
+ }
+
for ( v = 0 ; v < n_dependent_vars; ++v )
{
for ( fs = fctr->fs ; *fs ; ++fs )
{
- char buf1[100];
- char buf2[100];
- sprintf(buf1, "%s (",
- var_to_string(dependent_vars[v]));
-
- snprintf(buf2, 100, "%s = %s",
- var_to_string(fctr->indep_var[0]),
- value_to_string(&(*fs)->id[0],fctr->indep_var[0]));
-
- strcat(buf1, buf2);
-
- if ( fctr->indep_var[1] )
- {
- sprintf(buf2, "; %s = %s)",
- var_to_string(fctr->indep_var[1]),
- value_to_string(&(*fs)->id[1],
- fctr->indep_var[1]));
- strcat(buf1, buf2);
- }
- else
- {
- strcat(buf1, ")");
- }
+ const char *s = factor_to_string(fctr, *fs, dependent_vars[v]);
if ( cmd.a_plot[XMN_PLT_NPPLOT] )
- np_plot(&(*fs)->m[v],buf1);
+ np_plot(&(*fs)->m[v], s);
-
if ( cmd.a_plot[XMN_PLT_HISTOGRAM] )
{
struct normal_curve normal;
normal.stddev = (*fs)->m[v].stddev;
histogram_plot((*fs)->m[v].histogram,
- buf1, &normal, 0);
+ s, &normal, 0);
}
} /* for ( fs .... */
if ( value_is_missing(val,var) || case_missing )
val = 0;
-
- metrics_calc( &(*foo)->m[v], val, weight, case_no );
+
+ metrics_calc( &(*foo)->m[v], val, weight, case_no);
+
}
fctr = fctr->next;
if ( value_is_missing(val,var) || case_missing )
val = 0;
- metrics_calc(&totals[v], val, weight, case_no );
+ metrics_calc(&totals[v], val, weight, case_no);
}
tab_title (tbl, 0, _("Extreme Values"));
-
tab_vline (tbl, TAL_2, n_cols - 2, 0, n_rows -1);
tab_vline (tbl, TAL_1, n_cols - 1, 0, n_rows -1);
tab_text (tbl, n_cols - 1, 0, TAB_CENTER | TAT_TITLE, _("Value"));
tab_text (tbl, n_cols - 2, 0, TAB_CENTER | TAT_TITLE, _("Case Number"));
-
-
-
for ( i = 0 ; i < n_dep_var ; ++i )
{
-
-
-
-
-
-
-
/* Fill in the descriptives data */
void
populate_descriptives(struct tab_table *tbl, int col, int row,
}
+
+void
+box_plot_variables(const struct factor *fctr,
+ struct variable **vars, int n_vars,
+ const struct variable *id)
+{
+ int i;
+ struct factor_statistics **fs ;
+
+ if ( ! fctr )
+ {
+ box_plot_group(fctr, vars, n_vars, id);
+ return;
+ }
+
+ for ( fs = fctr->fs ; *fs ; ++fs )
+ {
+ double y_min = DBL_MAX;
+ double y_max = -DBL_MAX;
+ struct chart ch;
+
+ chart_initialise(&ch);
+
+ const char *s = factor_to_string(fctr, *fs, 0 );
+
+ chart_write_title(&ch, s);
+
+ for ( i = 0 ; i < n_vars ; ++i )
+ {
+ y_max = max(y_max, (*fs)->m[i].max);
+ y_min = min(y_min, (*fs)->m[i].min);
+ }
+
+ boxplot_draw_yscale(&ch, y_max, y_min);
+
+ for ( i = 0 ; i < n_vars ; ++i )
+ {
+
+ const double box_width = (ch.data_right - ch.data_left)
+ / (n_vars * 2.0 ) ;
+
+ const double box_centre = ( i * 2 + 1) * box_width
+ + ch.data_left;
+
+ boxplot_draw_boxplot(&ch,
+ box_centre, box_width,
+ &(*fs)->m[i],
+ var_to_string(vars[i]));
+
+
+ }
+
+ chart_finalise(&ch);
+
+ }
+
+}
+
+
+
+/* Do a box plot, grouping all factors into one plot ;
+ each dependent variable has its own plot.
+*/
+void
+box_plot_group(const struct factor *fctr,
+ const struct variable **vars,
+ int n_vars,
+ const struct variable *id)
+{
+ int i;
+
+ for ( i = 0 ; i < n_vars ; ++i )
+ {
+ struct factor_statistics **fs ;
+ struct chart ch;
+
+ chart_initialise(&ch);
+
+ boxplot_draw_yscale(&ch, totals[i].max, totals[i].min);
+
+ if ( fctr )
+ {
+ int n_factors = 0;
+ int f=0;
+ for ( fs = fctr->fs ; *fs ; ++fs )
+ ++n_factors;
+
+ chart_write_title(&ch, _("Boxplot of %s vs. %s"),
+ var_to_string(vars[i]), var_to_string(fctr->indep_var[0]) );
+
+ for ( fs = fctr->fs ; *fs ; ++fs )
+ {
+
+ const char *s = factor_to_string_concise(fctr, *fs);
+
+ const double box_width = (ch.data_right - ch.data_left)
+ / (n_factors * 2.0 ) ;
+
+ const double box_centre = ( f++ * 2 + 1) * box_width
+ + ch.data_left;
+
+ boxplot_draw_boxplot(&ch,
+ box_centre, box_width,
+ &(*fs)->m[i],
+ s);
+ }
+ }
+ else
+ {
+ const double box_width = (ch.data_right - ch.data_left) / 3.0;
+ const double box_centre = (ch.data_right + ch.data_left) / 2.0;
+
+ chart_write_title(&ch, _("Boxplot"));
+
+ boxplot_draw_boxplot(&ch,
+ box_centre, box_width,
+ &totals[i],
+ var_to_string(vars[i]) );
+
+ }
+
+ chart_finalise(&ch);
+ }
+
+}
+
+
/* Plot the normal and detrended normal plots for m
Label the plots with factorname */
void
if ( (*p)->p == 25 )
tab_float(tbl, col + i + 1 , row + 1,
TAB_CENTER,
- m->hinges[0], 8, 2);
+ m->hinge[0], 8, 2);
if ( (*p)->p == 50 )
tab_float(tbl, col + i + 1 , row + 1,
TAB_CENTER,
- m->hinges[1], 8, 2);
+ m->hinge[1], 8, 2);
if ( (*p)->p == 75 )
tab_float(tbl, col + i + 1 , row + 1,
TAB_CENTER,
- m->hinges[2], 8, 2);
+ m->hinge[2], 8, 2);
i++;
p++;
}
+}
+
+const char *
+factor_to_string(const struct factor *fctr,
+ struct factor_statistics *fs,
+ const struct variable *var)
+{
+
+ static char buf1[100];
+ char buf2[100];
+ strcpy(buf1,"");
+
+ if (var)
+ sprintf(buf1, "%s (",var_to_string(var) );
+
+
+ snprintf(buf2, 100, "%s = %s",
+ var_to_string(fctr->indep_var[0]),
+ value_to_string(&fs->id[0],fctr->indep_var[0]));
+
+ strcat(buf1, buf2);
+
+ if ( fctr->indep_var[1] )
+ {
+ sprintf(buf2, "; %s = %s)",
+ var_to_string(fctr->indep_var[1]),
+ value_to_string(&fs->id[1],
+ fctr->indep_var[1]));
+ strcat(buf1, buf2);
+ }
+ else
+ {
+ if ( var )
+ strcat(buf1, ")");
+ }
+
+ return buf1;
}
+
+
+const char *
+factor_to_string_concise(const struct factor *fctr,
+ struct factor_statistics *fs)
+
+{
+
+ static char buf[100];
+
+ char buf2[100];
+
+ snprintf(buf, 100, "%s",
+ value_to_string(&fs->id[0], fctr->indep_var[0]));
+
+ if ( fctr->indep_var[1] )
+ {
+ sprintf(buf2, ",%s)", value_to_string(&fs->id[1], fctr->indep_var[1]) );
+ strcat(buf, buf2);
+ }
+
+
+ return buf;
+}
/* Calculate the percentiles */
ptiles(m->ptile_hash, m->wvp, m->n_data, m->n, m->ptile_alg);
- tukey_hinges(m->wvp, m->n_data, m->n, m->hinges);
+ tukey_hinges(m->wvp, m->n_data, m->n, m->hinge);
/* Special case here */
if ( k1 + 1 == k2 )
enum pc_alg ptile_alg;
/* Tukey's Hinges */
- double hinges[3];
+ double hinge[3];
};
-
-
void metrics_precalc(struct metrics *m);
void metrics_calc(struct metrics *m, const union value *f, double weight,
const struct ptile_params *par)
{
double x;
+ double a=0;
+
+ if ( par->k1 >= 0 )
+ a = wv[par->k1]->v.f;
if ( wv[par->k1 + 1]->w >= 1 )
{
if ( par->g1_star < 0.5 )
- x = wv[par->k1]->v.f;
+ x = a;
else
x = wv[par->k1 + 1]->v.f;
}
else
{
if ( par->g1 < 0.5 )
- x = wv[par->k1]->v.f;
+ x = a;
else
x = wv[par->k1 + 1]->v.f;
ptile_haverage(const struct weighted_value **wv,
const struct ptile_params *par)
{
+
+ double a=0;
+
if ( par->g2_star >= 1.0 )
return wv[par->k2 + 1]->v.f ;
return wv[par->k2]->v.f;
}
- assert(par->k2 >= 0);
+ /* Ditto for k2 < 0 */
+ if ( par->k2 >= 0 )
+ {
+ a = wv[par->k2]->v.f;
+ }
if ( wv[par->k2 + 1]->w >= 1.0 )
- return ( (1 - par->g2_star) * wv[par->k2]->v.f
- +
+ return ( (1 - par->g2_star) * a +
par->g2_star * wv[par->k2 + 1]->v.f);
else
- return ( (1 - par->g2) * wv[par->k2]->v.f
- +
+ return ( (1 - par->g2) * a +
par->g2 * wv[par->k2 + 1]->v.f);
}
ptile_waverage(const struct weighted_value **wv,
const struct ptile_params *par)
{
+ double a=0;
+
if ( par->g1_star >= 1.0 )
return wv[par->k1 + 1]->v.f ;
+ if ( par->k1 >= 0 )
+ {
+ a = wv[par->k1]->v.f;
+ }
+
if ( wv[par->k1 + 1]->w >= 1.0 )
- return ( (1 - par->g1_star) * wv[par->k1]->v.f
- +
+ return ( (1 - par->g1_star) * a +
par->g1_star * wv[par->k1 + 1]->v.f);
else
- return ( (1 - par->g1) * wv[par->k1]->v.f
- +
+ return ( (1 - par->g1) * a +
par->g1 * wv[par->k1 + 1]->v.f);
}
tukey_hinges(const struct weighted_value **wv,
int n_data,
double w,
- double hinges[3])
+ double hinge[3]
+ )
{
int i;
double c_star = DBL_MAX;
if ( a_star >= 1.0 )
{
- hinges[i] = wv[h[i] + 1]->v.f ;
+ hinge[i] = wv[h[i] + 1]->v.f ;
continue;
}
if ( wv[h[i]+1]->w >= 1)
{
- hinges[i] = ( 1 - a_star)* wv[h[i]]->v.f
+ hinge[i] = ( 1 - a_star)* wv[h[i]]->v.f
+ a_star * wv[h[i]+1]->v.f;
continue;
}
- hinges[i] = ( 1 - a)* wv[h[i]]->v.f + a * wv[h[i]+1]->v.f;
+ hinge[i] = ( 1 - a)* wv[h[i]]->v.f + a * wv[h[i]+1]->v.f;
}
- assert(hinges[0] <= hinges[1]);
- assert(hinges[1] <= hinges[2]);
+ assert(hinge[0] <= hinge[1]);
+ assert(hinge[1] <= hinge[2]);
}
+
int
ptile_compare(const struct percentile *p1,
const struct percentile *p2,
enum pc_alg algorithm);
-/* Calculate Tukey's Hinges */
+/* Calculate Tukey's Hinges and the Whiskers for the box plot*/
void tukey_hinges(const struct weighted_value **wv,
int n_data,
double w,
#include <stdio.h>
#include "str.h"
#include "value-labels.h"
+#include "misc.h"
/* Pie charts of course need to know Pi :) */
#endif
-#define min(A,B) ((A>B)?B:A)
-
/* Draw a single slice of the pie */
static void
{
dump (0, "p->%sv_%s = parse_variable ();",
st_lower (sbc->prefix), st_lower (sbc->name));
- dump (1, "if (p->%sv_%s)",
+ dump (1, "if (!p->%sv_%s)",
st_lower (sbc->prefix), st_lower (sbc->name));
dump (0, "goto lossage;");
outdent ();
command/erase.sh \
command/examine.sh \
command/examine-extremes.sh \
+ command/examine-percentiles.sh \
command/file-label.sh \
command/filter.sh \
command/flip.sh \
--- /dev/null
+#!/bin/sh
+
+# This program tests the PERCENTILES subcommand of the EXAMINE command.
+# In particular it tests that it behaves properly when there are only
+# a few cases
+
+TEMPDIR=/tmp/pspp-tst-$$
+
+here=`pwd`;
+
+# ensure that top_srcdir is absolute
+cd $top_srcdir; top_srcdir=`pwd`
+
+export STAT_CONFIG_PATH=$top_srcdir/config
+
+
+cleanup()
+{
+ rm -rf $TEMPDIR
+}
+
+
+fail()
+{
+ echo $activity
+ echo FAILED
+ cleanup;
+ exit 1;
+}
+
+
+no_result()
+{
+ echo $activity
+ echo NO RESULT;
+ cleanup;
+ exit 2;
+}
+
+pass()
+{
+ cleanup;
+ exit 0;
+}
+
+mkdir -p $TEMPDIR
+
+cd $TEMPDIR
+
+activity="create program"
+cat > $TEMPDIR/out.stat <<EOF
+DATA LIST LIST /x *.
+BEGIN DATA.
+2.00
+8.00
+5.00
+END DATA.
+
+EXAMINE /x
+ /PERCENTILES=HAVERAGE.
+
+EXAMINE /x
+ /PERCENTILES=WAVERAGE.
+
+EXAMINE /x
+ /PERCENTILES=ROUND.
+
+EXAMINE /x
+ /PERCENTILES=EMPIRICAL.
+
+EXAMINE /x
+ /PERCENTILES=AEMPIRICAL.
+EOF
+if [ $? -ne 0 ] ; then no_result ; fi
+
+activity="run program"
+$SUPERVISOR $here/../src/pspp -o raw-ascii $TEMPDIR/out.stat
+if [ $? -ne 0 ] ; then no_result ; fi
+
+
+activity="compare results"
+diff $TEMPDIR/pspp.list - << EOF
+1.1 DATA LIST. Reading free-form data from the command file.
++--------+------+
+|Variable|Format|
+#========#======#
+|X |F8.0 |
++--------+------+
+
+2.1 EXAMINE. Case Processing Summary
+#=#=============================#
+# # Cases #
+# #---------+---------+---------#
+# # Valid | Missing | Total #
+# #-+-------+-+-------+-+-------#
+# #N|Percent|N|Percent|N|Percent#
+#=#=#=======#=#=======#=#=======#
+#X#3| 100%|0| 0%|3| 100%#
+#=#=#=======#=#=======#=#=======#
+
+2.2 EXAMINE. Percentiles
+#================#================================#
+# # Percentiles #
+# #---+---+----+----+----+----+----#
+# # 5 | 10| 25 | 50 | 75 | 90 | 95 #
+#=#==============#===#===#====#====#====#====#====#
+#X|HAverage #.40|.80|2.00|5.00|8.00|8.00|8.00#
+# |Tukey's Hinges# | |3.50|5.00|6.50| | #
+#=#==============#===#===#====#====#====#====#====#
+
+3.1 EXAMINE. Case Processing Summary
+#=#=============================#
+# # Cases #
+# #---------+---------+---------#
+# # Valid | Missing | Total #
+# #-+-------+-+-------+-+-------#
+# #N|Percent|N|Percent|N|Percent#
+#=#=#=======#=#=======#=#=======#
+#X#3| 100%|0| 0%|3| 100%#
+#=#=#=======#=#=======#=#=======#
+
+3.2 EXAMINE. Percentiles
+#==================#================================#
+# # Percentiles #
+# #---+---+----+----+----+----+----#
+# # 5 | 10| 25 | 50 | 75 | 90 | 95 #
+#=#================#===#===#====#====#====#====#====#
+#X|Weighted Average#.30|.60|1.50|3.50|5.75|7.10|7.55#
+# |Tukey's Hinges # | |3.50|5.00|6.50| | #
+#=#================#===#===#====#====#====#====#====#
+
+4.1 EXAMINE. Case Processing Summary
+#=#=============================#
+# # Cases #
+# #---------+---------+---------#
+# # Valid | Missing | Total #
+# #-+-------+-+-------+-+-------#
+# #N|Percent|N|Percent|N|Percent#
+#=#=#=======#=#=======#=#=======#
+#X#3| 100%|0| 0%|3| 100%#
+#=#=#=======#=#=======#=#=======#
+
+4.2 EXAMINE. Percentiles
+#================#================================#
+# # Percentiles #
+# #---+---+----+----+----+----+----#
+# # 5 | 10| 25 | 50 | 75 | 90 | 95 #
+#=#==============#===#===#====#====#====#====#====#
+#X|Rounded #.00|.00|2.00|5.00|5.00|8.00|8.00#
+# |Tukey's Hinges# | |3.50|5.00|6.50| | #
+#=#==============#===#===#====#====#====#====#====#
+
+5.1 EXAMINE. Case Processing Summary
+#=#=============================#
+# # Cases #
+# #---------+---------+---------#
+# # Valid | Missing | Total #
+# #-+-------+-+-------+-+-------#
+# #N|Percent|N|Percent|N|Percent#
+#=#=#=======#=#=======#=#=======#
+#X#3| 100%|0| 0%|3| 100%#
+#=#=#=======#=#=======#=#=======#
+
+5.2 EXAMINE. Percentiles
+#================#==================================#
+# # Percentiles #
+# #----+----+----+----+----+----+----#
+# # 5 | 10 | 25 | 50 | 75 | 90 | 95 #
+#=#==============#====#====#====#====#====#====#====#
+#X|Empirical #2.00|2.00|2.00|5.00|8.00|8.00|8.00#
+# |Tukey's Hinges# | |3.50|5.00|6.50| | #
+#=#==============#====#====#====#====#====#====#====#
+
+6.1 EXAMINE. Case Processing Summary
+#=#=============================#
+# # Cases #
+# #---------+---------+---------#
+# # Valid | Missing | Total #
+# #-+-------+-+-------+-+-------#
+# #N|Percent|N|Percent|N|Percent#
+#=#=#=======#=#=======#=#=======#
+#X#3| 100%|0| 0%|3| 100%#
+#=#=#=======#=#=======#=#=======#
+
+6.2 EXAMINE. Percentiles
+#==========================#==================================#
+# # Percentiles #
+# #----+----+----+----+----+----+----#
+# # 5 | 10 | 25 | 50 | 75 | 90 | 95 #
+#=#========================#====#====#====#====#====#====#====#
+#X|Empirical with averaging#2.00|2.00|2.00|5.00|8.00|8.00|8.00#
+# |Tukey's Hinges # | |3.50|5.00|6.50| | #
+#=#========================#====#====#====#====#====#====#====#
+
+EOF
+if [ $? -ne 0 ] ; then fail ; fi
+
+pass