Read dictionary encoding from data files.
[pspp] / src / language / stats / examine.q
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2004, 2008, 2009 Free Software Foundation, Inc.
3
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.
8
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.
13
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/>. */
16
17 #include <config.h>
18
19 #include <gsl/gsl_cdf.h>
20 #include <libpspp/message.h>
21 #include <math.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24
25 #include <math/sort.h>
26 #include <math/order-stats.h>
27 #include <math/percentiles.h>
28 #include <math/tukey-hinges.h>
29 #include <math/box-whisker.h>
30 #include <math/trimmed-mean.h>
31 #include <math/extrema.h>
32 #include <math/np.h>
33 #include <data/case.h>
34 #include <data/casegrouper.h>
35 #include <data/casereader.h>
36 #include <data/casewriter.h>
37 #include <data/dictionary.h>
38 #include <data/procedure.h>
39 #include <data/subcase.h>
40 #include <data/value-labels.h>
41 #include <data/variable.h>
42 #include <language/command.h>
43 #include <language/dictionary/split-file.h>
44 #include <language/lexer/lexer.h>
45 #include <libpspp/compiler.h>
46 #include <libpspp/hash.h>
47 #include <libpspp/message.h>
48 #include <libpspp/misc.h>
49 #include <libpspp/str.h>
50 #include <math/moments.h>
51 #include <output/charts/box-whisker.h>
52 #include <output/charts/cartesian.h>
53 #include <output/manager.h>
54 #include <output/table.h>
55
56 #include "minmax.h"
57 #include "xalloc.h"
58
59 #include "gettext.h"
60 #define _(msgid) gettext (msgid)
61 #define N_(msgid) msgid
62
63 /* (headers) */
64 #include <output/chart.h>
65 #include <output/charts/plot-hist.h>
66 #include <output/charts/plot-chart.h>
67 #include <math/histogram.h>
68
69 /* (specification)
70    "EXAMINE" (xmn_):
71    *^variables=custom;
72    +total=custom;
73    +nototal=custom;
74    missing=miss:pairwise/!listwise,
75    rep:report/!noreport,
76    incl:include/!exclude;
77    +compare=cmp:variables/!groups;
78    +percentiles=custom;
79    +id=var;
80    +plot[plt_]=stemleaf,boxplot,npplot,:spreadlevel(*d:n),histogram,all,none;
81    +cinterval=double;
82    +statistics[st_]=descriptives,:extreme(*d:n),all,none.
83 */
84
85 /* (declarations) */
86
87 /* (functions) */
88
89
90 static struct cmd_examine cmd;
91
92 static const struct variable **dependent_vars;
93 static size_t n_dependent_vars;
94
95 /* PERCENTILES */
96
97 static subc_list_double percentile_list;
98 static enum pc_alg percentile_algorithm;
99
100 struct factor_metrics
101 {
102   struct moments1 *moments;
103
104   struct percentile **ptl;
105   size_t n_ptiles;
106
107   struct statistic *tukey_hinges;
108   struct statistic *box_whisker;
109   struct statistic *trimmed_mean;
110   struct statistic *histogram;
111   struct order_stats *np;
112
113   /* Three quartiles indexing into PTL */
114   struct percentile **quartiles;
115
116   /* A reader sorted in ASCENDING order */
117   struct casereader *up_reader;
118
119   /* The minimum value of all the weights */
120   double cmin;
121
122   /* Sum of all weights, including those for missing values */
123   double n;
124
125   /* Sum of weights of non_missing values */
126   double n_valid;
127
128   double mean;
129
130   double variance;
131
132   double skewness;
133
134   double kurtosis;
135
136   double se_mean;
137
138   struct extrema *minima;
139   struct extrema *maxima;
140 };
141
142 struct factor_result
143 {
144   struct ll ll;
145
146   union value *value[2];
147
148   /* An array of factor metrics, one for each variable */
149   struct factor_metrics *metrics;
150 };
151
152 struct xfactor
153 {
154   /* We need to make a list of this structure */
155   struct ll ll;
156
157   /* The independent variable */
158   const struct variable const* indep_var[2];
159
160   /* A list of results for this factor */
161   struct ll_list result_list ;
162 };
163
164
165 static void
166 factor_destroy (struct xfactor *fctr)
167 {
168   struct ll *ll = ll_head (&fctr->result_list);
169   while (ll != ll_null (&fctr->result_list))
170     {
171       int v;
172       struct factor_result *result =
173         ll_data (ll, struct factor_result, ll);
174
175       for (v = 0; v < n_dependent_vars; ++v)
176         {
177           int i;
178           moments1_destroy (result->metrics[v].moments);
179           extrema_destroy (result->metrics[v].minima);
180           extrema_destroy (result->metrics[v].maxima);
181           statistic_destroy (result->metrics[v].trimmed_mean);
182           statistic_destroy (result->metrics[v].tukey_hinges);
183           statistic_destroy (result->metrics[v].box_whisker);
184           statistic_destroy (result->metrics[v].histogram);
185           for (i = 0 ; i < result->metrics[v].n_ptiles; ++i)
186             statistic_destroy ((struct statistic *) result->metrics[v].ptl[i]);
187           free (result->metrics[v].ptl);
188           free (result->metrics[v].quartiles);
189           casereader_destroy (result->metrics[v].up_reader);
190         }
191
192       free (result->value[0]);
193       free (result->value[1]);
194       free (result->metrics);
195       ll = ll_next (ll);
196       free (result);
197     }
198 }
199
200 static struct xfactor level0_factor;
201 static struct ll_list factor_list = LL_INITIALIZER (factor_list);
202
203 /* Parse the clause specifying the factors */
204 static int examine_parse_independent_vars (struct lexer *lexer,
205                                            const struct dictionary *dict,
206                                            struct cmd_examine *cmd);
207
208 /* Output functions */
209 static void show_summary (const struct variable **dependent_var, int n_dep_var,
210                           const struct xfactor *f);
211
212
213 static void show_descriptives (const struct variable **dependent_var,
214                                int n_dep_var,
215                                const struct xfactor *f);
216
217
218 static void show_percentiles (const struct variable **dependent_var,
219                                int n_dep_var,
220                                const struct xfactor *f);
221
222
223 static void show_extremes (const struct variable **dependent_var,
224                            int n_dep_var,
225                            const struct xfactor *f);
226
227
228
229
230 /* Per Split function */
231 static void run_examine (struct cmd_examine *, struct casereader *,
232                          struct dataset *);
233
234 static void output_examine (void);
235
236
237 void factor_calc (const struct ccase *c, int case_no,
238                   double weight, bool case_missing);
239
240
241 /* Represent a factor as a string, so it can be
242    printed in a human readable fashion */
243 static void factor_to_string (const struct xfactor *fctr,
244                               const struct factor_result *result,
245                               struct string *str);
246
247 /* Represent a factor as a string, so it can be
248    printed in a human readable fashion,
249    but sacrificing some readablility for the sake of brevity */
250 static void
251 factor_to_string_concise (const struct xfactor *fctr,
252                           const struct factor_result *result,
253                           struct string *str
254                           );
255
256
257
258 /* Categories of missing values to exclude. */
259 static enum mv_class exclude_values;
260
261 int
262 cmd_examine (struct lexer *lexer, struct dataset *ds)
263 {
264   struct casegrouper *grouper;
265   struct casereader *group;
266   bool ok;
267
268   subc_list_double_create (&percentile_list);
269   percentile_algorithm = PC_HAVERAGE;
270
271   if ( !parse_examine (lexer, ds, &cmd, NULL) )
272     {
273       subc_list_double_destroy (&percentile_list);
274       return CMD_FAILURE;
275     }
276
277   /* If /MISSING=INCLUDE is set, then user missing values are ignored */
278   exclude_values = cmd.incl == XMN_INCLUDE ? MV_SYSTEM : MV_ANY;
279
280   if ( cmd.st_n == SYSMIS )
281     cmd.st_n = 5;
282
283   if ( ! cmd.sbc_cinterval)
284     cmd.n_cinterval[0] = 95.0;
285
286   /* If descriptives have been requested, make sure the
287      quartiles are calculated */
288   if ( cmd.a_statistics[XMN_ST_DESCRIPTIVES] )
289     {
290       subc_list_double_push (&percentile_list, 25);
291       subc_list_double_push (&percentile_list, 50);
292       subc_list_double_push (&percentile_list, 75);
293     }
294
295   grouper = casegrouper_create_splits (proc_open (ds), dataset_dict (ds));
296
297   while (casegrouper_get_next_group (grouper, &group))
298     {
299       struct casereader *reader =
300         casereader_create_arithmetic_sequence (group, 1, 1);
301
302       run_examine (&cmd, reader, ds);
303     }
304
305   ok = casegrouper_destroy (grouper);
306   ok = proc_commit (ds) && ok;
307
308   if ( dependent_vars )
309     free (dependent_vars);
310
311   subc_list_double_destroy (&percentile_list);
312
313   return ok ? CMD_SUCCESS : CMD_CASCADING_FAILURE;
314 };
315
316
317 /* Plot the normal and detrended normal plots for RESULT.
318    Label the plots with LABEL */
319 static void
320 np_plot (struct np *np, const char *label)
321 {
322   double yfirst = 0, ylast = 0;
323
324   double x_lower;
325   double x_upper;
326   double slack;
327
328   /* Normal Plot */
329   struct chart *np_chart;
330
331   /* Detrended Normal Plot */
332   struct chart *dnp_chart;
333
334   /* The slope and intercept of the ideal normal probability line */
335   const double slope = 1.0 / np->stddev;
336   const double intercept = -np->mean / np->stddev;
337
338   if ( np->n < 1.0 )
339     {
340       msg (MW, _("Not creating plot because data set is empty."));
341       return ;
342     }
343
344   np_chart = chart_create ();
345   dnp_chart = chart_create ();
346
347   if ( !np_chart || ! dnp_chart )
348     return ;
349
350   chart_write_title (np_chart, _("Normal Q-Q Plot of %s"), label);
351   chart_write_xlabel (np_chart, _("Observed Value"));
352   chart_write_ylabel (np_chart, _("Expected Normal"));
353
354   chart_write_title (dnp_chart, _("Detrended Normal Q-Q Plot of %s"),
355                      label);
356   chart_write_xlabel (dnp_chart, _("Observed Value"));
357   chart_write_ylabel (dnp_chart, _("Dev from Normal"));
358
359   yfirst = gsl_cdf_ugaussian_Pinv (1 / (np->n + 1));
360   ylast = gsl_cdf_ugaussian_Pinv (np->n / (np->n + 1));
361
362   /* Need to make sure that both the scatter plot and the ideal fit into the
363      plot */
364   x_lower = MIN (np->y_min, (yfirst - intercept) / slope) ;
365   x_upper = MAX (np->y_max, (ylast  - intercept) / slope) ;
366   slack = (x_upper - x_lower)  * 0.05 ;
367
368   chart_write_xscale (np_chart, x_lower - slack, x_upper + slack, 5);
369   chart_write_xscale (dnp_chart, np->y_min, np->y_max, 5);
370
371   chart_write_yscale (np_chart, yfirst, ylast, 5);
372   chart_write_yscale (dnp_chart, np->dns_min, np->dns_max, 5);
373
374   {
375     struct casereader *reader = casewriter_make_reader (np->writer);
376     struct ccase *c;
377     while ((c = casereader_read (reader)) != NULL)
378       {
379         chart_datum (np_chart, 0, case_data_idx (c, NP_IDX_Y)->f, case_data_idx (c, NP_IDX_NS)->f);
380         chart_datum (dnp_chart, 0, case_data_idx (c, NP_IDX_Y)->f, case_data_idx (c, NP_IDX_DNS)->f);
381
382         case_unref (c);
383       }
384     casereader_destroy (reader);
385   }
386
387   chart_line (dnp_chart, 0, 0, np->y_min, np->y_max , CHART_DIM_X);
388   chart_line (np_chart, slope, intercept, yfirst, ylast , CHART_DIM_Y);
389
390   chart_submit (np_chart);
391   chart_submit (dnp_chart);
392 }
393
394
395 static void
396 show_npplot (const struct variable **dependent_var,
397              int n_dep_var,
398              const struct xfactor *fctr)
399 {
400   int v;
401
402   for (v = 0; v < n_dep_var; ++v)
403     {
404       struct ll *ll;
405       for (ll = ll_head (&fctr->result_list);
406            ll != ll_null (&fctr->result_list);
407            ll = ll_next (ll))
408         {
409           struct string str;
410           const struct factor_result *result =
411             ll_data (ll, struct factor_result, ll);
412
413           ds_init_empty (&str);
414           ds_put_format (&str, "%s ", var_get_name (dependent_var[v]));
415
416           factor_to_string (fctr, result, &str);
417
418           np_plot ((struct np*) result->metrics[v].np, ds_cstr(&str));
419
420           statistic_destroy ((struct statistic *)result->metrics[v].np);
421
422           ds_destroy (&str);
423         }
424     }
425 }
426
427
428 static void
429 show_histogram (const struct variable **dependent_var,
430                 int n_dep_var,
431                 const struct xfactor *fctr)
432 {
433   int v;
434
435   for (v = 0; v < n_dep_var; ++v)
436     {
437       struct ll *ll;
438       for (ll = ll_head (&fctr->result_list);
439            ll != ll_null (&fctr->result_list);
440            ll = ll_next (ll))
441         {
442           struct string str;
443           const struct factor_result *result =
444             ll_data (ll, struct factor_result, ll);
445
446           ds_init_empty (&str);
447           ds_put_format (&str, "%s ", var_get_name (dependent_var[v]));
448
449           factor_to_string (fctr, result, &str);
450
451           histogram_plot ((struct histogram *) result->metrics[v].histogram,
452                           ds_cstr (&str),
453                           (struct moments1 *) result->metrics[v].moments);
454
455           ds_destroy (&str);
456         }
457     }
458 }
459
460
461
462 static void
463 show_boxplot_groups (const struct variable **dependent_var,
464                      int n_dep_var,
465                      const struct xfactor *fctr)
466 {
467   int v;
468
469   for (v = 0; v < n_dep_var; ++v)
470     {
471       struct ll *ll;
472       int f = 0;
473       struct chart *ch = chart_create ();
474       double y_min = DBL_MAX;
475       double y_max = -DBL_MAX;
476
477       for (ll = ll_head (&fctr->result_list);
478            ll != ll_null (&fctr->result_list);
479            ll = ll_next (ll))
480         {
481           const struct extremum  *max, *min;
482           const struct factor_result *result =
483             ll_data (ll, struct factor_result, ll);
484
485           const struct ll_list *max_list =
486             extrema_list (result->metrics[v].maxima);
487
488           const struct ll_list *min_list =
489             extrema_list (result->metrics[v].minima);
490
491           if ( ll_is_empty (max_list))
492             {
493               msg (MW, _("Not creating plot because data set is empty."));
494               continue;
495             }
496
497           max = (const struct extremum *)
498             ll_data (ll_head(max_list), struct extremum, ll);
499
500           min = (const struct extremum *)
501             ll_data (ll_head (min_list), struct extremum, ll);
502
503           y_max = MAX (y_max, max->value);
504           y_min = MIN (y_min, min->value);
505         }
506
507       boxplot_draw_yscale (ch, y_max, y_min);
508
509       if ( fctr->indep_var[0])
510         chart_write_title (ch, _("Boxplot of %s vs. %s"),
511                            var_to_string (dependent_var[v]),
512                            var_to_string (fctr->indep_var[0]) );
513       else
514         chart_write_title (ch, _("Boxplot of %s"),
515                            var_to_string (dependent_var[v]));
516
517       for (ll = ll_head (&fctr->result_list);
518            ll != ll_null (&fctr->result_list);
519            ll = ll_next (ll))
520         {
521           const struct factor_result *result =
522             ll_data (ll, struct factor_result, ll);
523
524           struct string str;
525           const double box_width = (ch->data_right - ch->data_left)
526             / (ll_count (&fctr->result_list) * 2.0 ) ;
527
528           const double box_centre = (f++ * 2 + 1) * box_width + ch->data_left;
529
530           ds_init_empty (&str);
531           factor_to_string_concise (fctr, result, &str);
532
533           boxplot_draw_boxplot (ch,
534                                 box_centre, box_width,
535                                 (const struct box_whisker *)
536                                  result->metrics[v].box_whisker,
537                                 ds_cstr (&str));
538
539           ds_destroy (&str);
540         }
541
542       chart_submit (ch);
543     }
544 }
545
546
547
548 static void
549 show_boxplot_variables (const struct variable **dependent_var,
550                         int n_dep_var,
551                         const struct xfactor *fctr
552                         )
553
554 {
555   int v;
556   struct ll *ll;
557   const struct ll_list *result_list = &fctr->result_list;
558
559   for (ll = ll_head (result_list);
560        ll != ll_null (result_list);
561        ll = ll_next (ll))
562
563     {
564       struct string title;
565       struct chart *ch = chart_create ();
566       double y_min = DBL_MAX;
567       double y_max = -DBL_MAX;
568
569       const struct factor_result *result =
570         ll_data (ll, struct factor_result, ll);
571
572       const double box_width = (ch->data_right - ch->data_left)
573         / (n_dep_var * 2.0 ) ;
574
575       for (v = 0; v < n_dep_var; ++v)
576         {
577           const struct ll *max_ll =
578             ll_head (extrema_list (result->metrics[v].maxima));
579           const struct ll *min_ll =
580             ll_head (extrema_list (result->metrics[v].minima));
581
582           const struct extremum  *max =
583             (const struct extremum *) ll_data (max_ll, struct extremum, ll);
584
585           const struct extremum  *min =
586             (const struct extremum *) ll_data (min_ll, struct extremum, ll);
587
588           y_max = MAX (y_max, max->value);
589           y_min = MIN (y_min, min->value);
590         }
591
592
593       boxplot_draw_yscale (ch, y_max, y_min);
594
595       ds_init_empty (&title);
596       factor_to_string (fctr, result, &title);
597
598 #if 0
599       ds_put_format (&title, "%s = ", var_get_name (fctr->indep_var[0]));
600       var_append_value_name (fctr->indep_var[0], result->value[0], &title);
601 #endif
602
603       chart_write_title (ch, ds_cstr (&title));
604       ds_destroy (&title);
605
606       for (v = 0; v < n_dep_var; ++v)
607         {
608           struct string str;
609           const double box_centre = (v * 2 + 1) * box_width + ch->data_left;
610
611           ds_init_empty (&str);
612           ds_init_cstr (&str, var_get_name (dependent_var[v]));
613
614           boxplot_draw_boxplot (ch,
615                                 box_centre, box_width,
616                                 (const struct box_whisker *) result->metrics[v].box_whisker,
617                                 ds_cstr (&str));
618
619           ds_destroy (&str);
620         }
621
622       chart_submit (ch);
623     }
624 }
625
626
627 /* Show all the appropriate tables */
628 static void
629 output_examine (void)
630 {
631   struct ll *ll;
632
633   show_summary (dependent_vars, n_dependent_vars, &level0_factor);
634
635   if ( cmd.a_statistics[XMN_ST_EXTREME] )
636     show_extremes (dependent_vars, n_dependent_vars, &level0_factor);
637
638   if ( cmd.a_statistics[XMN_ST_DESCRIPTIVES] )
639     show_descriptives (dependent_vars, n_dependent_vars, &level0_factor);
640
641   if ( cmd.sbc_percentiles)
642     show_percentiles (dependent_vars, n_dependent_vars, &level0_factor);
643
644   if ( cmd.sbc_plot)
645     {
646       if (cmd.a_plot[XMN_PLT_BOXPLOT])
647         show_boxplot_groups (dependent_vars, n_dependent_vars, &level0_factor);
648
649       if (cmd.a_plot[XMN_PLT_HISTOGRAM])
650         show_histogram (dependent_vars, n_dependent_vars, &level0_factor);
651
652       if (cmd.a_plot[XMN_PLT_NPPLOT])
653         show_npplot (dependent_vars, n_dependent_vars, &level0_factor);
654     }
655
656   for (ll = ll_head (&factor_list);
657        ll != ll_null (&factor_list); ll = ll_next (ll))
658     {
659       struct xfactor *factor = ll_data (ll, struct xfactor, ll);
660       show_summary (dependent_vars, n_dependent_vars, factor);
661
662       if ( cmd.a_statistics[XMN_ST_EXTREME] )
663         show_extremes (dependent_vars, n_dependent_vars, factor);
664
665       if ( cmd.a_statistics[XMN_ST_DESCRIPTIVES] )
666         show_descriptives (dependent_vars, n_dependent_vars, factor);
667
668       if ( cmd.sbc_percentiles)
669         show_percentiles (dependent_vars, n_dependent_vars, factor);
670
671       if (cmd.a_plot[XMN_PLT_BOXPLOT] &&
672           cmd.cmp == XMN_GROUPS)
673         show_boxplot_groups (dependent_vars, n_dependent_vars, factor);
674
675
676       if (cmd.a_plot[XMN_PLT_BOXPLOT] &&
677           cmd.cmp == XMN_VARIABLES)
678         show_boxplot_variables (dependent_vars, n_dependent_vars,
679                                 factor);
680
681       if (cmd.a_plot[XMN_PLT_HISTOGRAM])
682         show_histogram (dependent_vars, n_dependent_vars, factor);
683
684       if (cmd.a_plot[XMN_PLT_NPPLOT])
685         show_npplot (dependent_vars, n_dependent_vars, factor);
686     }
687 }
688
689 /* Parse the PERCENTILES subcommand */
690 static int
691 xmn_custom_percentiles (struct lexer *lexer, struct dataset *ds UNUSED,
692                         struct cmd_examine *p UNUSED, void *aux UNUSED)
693 {
694   lex_match (lexer, '=');
695
696   lex_match (lexer, '(');
697
698   while ( lex_is_number (lexer) )
699     {
700       subc_list_double_push (&percentile_list, lex_number (lexer));
701
702       lex_get (lexer);
703
704       lex_match (lexer, ',') ;
705     }
706   lex_match (lexer, ')');
707
708   lex_match (lexer, '=');
709
710   if ( lex_match_id (lexer, "HAVERAGE"))
711     percentile_algorithm = PC_HAVERAGE;
712
713   else if ( lex_match_id (lexer, "WAVERAGE"))
714     percentile_algorithm = PC_WAVERAGE;
715
716   else if ( lex_match_id (lexer, "ROUND"))
717     percentile_algorithm = PC_ROUND;
718
719   else if ( lex_match_id (lexer, "EMPIRICAL"))
720     percentile_algorithm = PC_EMPIRICAL;
721
722   else if ( lex_match_id (lexer, "AEMPIRICAL"))
723     percentile_algorithm = PC_AEMPIRICAL;
724
725   else if ( lex_match_id (lexer, "NONE"))
726     percentile_algorithm = PC_NONE;
727
728
729   if ( 0 == subc_list_double_count (&percentile_list))
730     {
731       subc_list_double_push (&percentile_list, 5);
732       subc_list_double_push (&percentile_list, 10);
733       subc_list_double_push (&percentile_list, 25);
734       subc_list_double_push (&percentile_list, 50);
735       subc_list_double_push (&percentile_list, 75);
736       subc_list_double_push (&percentile_list, 90);
737       subc_list_double_push (&percentile_list, 95);
738     }
739
740   return 1;
741 }
742
743 /* TOTAL and NOTOTAL are simple, mutually exclusive flags */
744 static int
745 xmn_custom_total (struct lexer *lexer UNUSED, struct dataset *ds UNUSED,
746                   struct cmd_examine *p, void *aux UNUSED)
747 {
748   if ( p->sbc_nototal )
749     {
750       msg (SE, _("%s and %s are mutually exclusive"),"TOTAL","NOTOTAL");
751       return 0;
752     }
753
754   return 1;
755 }
756
757 static int
758 xmn_custom_nototal (struct lexer *lexer UNUSED, struct dataset *ds UNUSED,
759                     struct cmd_examine *p, void *aux UNUSED)
760 {
761   if ( p->sbc_total )
762     {
763       msg (SE, _("%s and %s are mutually exclusive"), "TOTAL", "NOTOTAL");
764       return 0;
765     }
766
767   return 1;
768 }
769
770
771
772 /* Parser for the variables sub command
773    Returns 1 on success */
774 static int
775 xmn_custom_variables (struct lexer *lexer, struct dataset *ds,
776                       struct cmd_examine *cmd,
777                       void *aux UNUSED)
778 {
779   const struct dictionary *dict = dataset_dict (ds);
780   lex_match (lexer, '=');
781
782   if ( (lex_token (lexer) != T_ID || dict_lookup_var (dict, lex_tokid (lexer)) == NULL)
783        && lex_token (lexer) != T_ALL)
784     {
785       return 2;
786     }
787
788   if (!parse_variables_const (lexer, dict, &dependent_vars, &n_dependent_vars,
789                               PV_NO_DUPLICATE | PV_NUMERIC | PV_NO_SCRATCH) )
790     {
791       free (dependent_vars);
792       return 0;
793     }
794
795   assert (n_dependent_vars);
796
797
798   if ( lex_match (lexer, T_BY))
799     {
800       int success ;
801       success =  examine_parse_independent_vars (lexer, dict, cmd);
802       if ( success != 1 )
803         {
804           free (dependent_vars);
805         }
806       return success;
807     }
808
809   return 1;
810 }
811
812
813
814 /* Parse the clause specifying the factors */
815 static int
816 examine_parse_independent_vars (struct lexer *lexer,
817                                 const struct dictionary *dict,
818                                 struct cmd_examine *cmd)
819 {
820   int success;
821   struct xfactor *sf = xmalloc (sizeof *sf);
822
823   ll_init (&sf->result_list);
824
825   if ( (lex_token (lexer) != T_ID ||
826         dict_lookup_var (dict, lex_tokid (lexer)) == NULL)
827        && lex_token (lexer) != T_ALL)
828     {
829       free ( sf ) ;
830       return 2;
831     }
832
833   sf->indep_var[0] = parse_variable (lexer, dict);
834   sf->indep_var[1] = NULL;
835
836   if ( lex_token (lexer) == T_BY )
837     {
838       lex_match (lexer, T_BY);
839
840       if ( (lex_token (lexer) != T_ID ||
841             dict_lookup_var (dict, lex_tokid (lexer)) == NULL)
842            && lex_token (lexer) != T_ALL)
843         {
844           free (sf);
845           return 2;
846         }
847
848       sf->indep_var[1] = parse_variable (lexer, dict);
849
850       ll_push_tail (&factor_list, &sf->ll);
851     }
852   else
853     ll_push_tail (&factor_list, &sf->ll);
854
855   lex_match (lexer, ',');
856
857   if ( lex_token (lexer) == '.' || lex_token (lexer) == '/' )
858     return 1;
859
860   success =  examine_parse_independent_vars (lexer, dict, cmd);
861
862   if ( success != 1 )
863     free ( sf ) ;
864
865   return success;
866 }
867
868 static void
869 examine_group (struct cmd_examine *cmd, struct casereader *reader, int level,
870                const struct dictionary *dict, struct xfactor *factor)
871 {
872   struct ccase *c;
873   const struct variable *wv = dict_get_weight (dict);
874   int v;
875   int n_extrema = 1;
876   struct factor_result *result = xzalloc (sizeof (*result));
877
878   result->metrics = xcalloc (n_dependent_vars, sizeof (*result->metrics));
879
880   if ( cmd->a_statistics[XMN_ST_EXTREME] )
881     n_extrema = cmd->st_n;
882
883
884   c = casereader_peek (reader, 0);
885   if (c != NULL)
886     {
887       if ( level > 0)
888         {
889           result->value[0] =
890             value_dup (case_data (c, factor->indep_var[0]),
891                        var_get_width (factor->indep_var[0]));
892
893           if ( level > 1)
894             result->value[1] =
895               value_dup (case_data (c, factor->indep_var[1]),
896                          var_get_width (factor->indep_var[1]));
897         }
898       case_unref (c);
899     }
900
901   for (v = 0; v < n_dependent_vars; ++v)
902     {
903       struct casewriter *writer;
904       struct casereader *input = casereader_clone (reader);
905
906       result->metrics[v].moments = moments1_create (MOMENT_KURTOSIS);
907       result->metrics[v].minima = extrema_create (n_extrema, EXTREME_MINIMA);
908       result->metrics[v].maxima = extrema_create (n_extrema, EXTREME_MAXIMA);
909       result->metrics[v].cmin = DBL_MAX;
910
911       if (cmd->a_statistics[XMN_ST_DESCRIPTIVES] ||
912           cmd->a_plot[XMN_PLT_BOXPLOT] ||
913           cmd->a_plot[XMN_PLT_NPPLOT] ||
914           cmd->sbc_percentiles)
915         {
916           /* In this case, we need to sort the data, so we create a sorting
917              casewriter */
918           struct subcase up_ordering;
919           subcase_init_var (&up_ordering, dependent_vars[v], SC_ASCEND);
920           writer = sort_create_writer (&up_ordering,
921                                        casereader_get_value_cnt (reader));
922           subcase_destroy (&up_ordering);
923         }
924       else
925         {
926           /* but in this case, sorting is unnecessary, so an ordinary
927              casewriter is sufficient */
928           writer =
929             autopaging_writer_create (casereader_get_value_cnt (reader));
930         }
931
932
933       /* Sort or just iterate, whilst calculating moments etc */
934       while ((c = casereader_read (input)) != NULL)
935         {
936           const casenumber loc =
937               case_data_idx (c, casereader_get_value_cnt (reader) - 1)->f;
938
939           const double weight = wv ? case_data (c, wv)->f : 1.0;
940           const union value *value = case_data (c, dependent_vars[v]);
941
942           if (weight != SYSMIS)
943             minimize (&result->metrics[v].cmin, weight);
944
945           moments1_add (result->metrics[v].moments,
946                         value->f,
947                         weight);
948
949           result->metrics[v].n += weight;
950
951           if ( ! var_is_value_missing (dependent_vars[v], value, MV_ANY) )
952             result->metrics[v].n_valid += weight;
953
954           extrema_add (result->metrics[v].maxima,
955                        value->f,
956                        weight,
957                        loc);
958
959           extrema_add (result->metrics[v].minima,
960                        value->f,
961                        weight,
962                        loc);
963
964           casewriter_write (writer, c);
965         }
966       casereader_destroy (input);
967       result->metrics[v].up_reader = casewriter_make_reader (writer);
968     }
969
970   /* If percentiles or descriptives have been requested, then a
971      second pass through the data (which has now been sorted)
972      is necessary */
973   if ( cmd->a_statistics[XMN_ST_DESCRIPTIVES] ||
974        cmd->a_plot[XMN_PLT_BOXPLOT] ||
975        cmd->a_plot[XMN_PLT_NPPLOT] ||
976        cmd->sbc_percentiles)
977     {
978       for (v = 0; v < n_dependent_vars; ++v)
979         {
980           int i;
981           int n_os;
982           struct order_stats **os ;
983           struct factor_metrics *metric = &result->metrics[v];
984
985           metric->n_ptiles = percentile_list.n_data;
986
987           metric->ptl = xcalloc (metric->n_ptiles,
988                                  sizeof (struct percentile *));
989
990           metric->quartiles = xcalloc (3, sizeof (*metric->quartiles));
991
992           for (i = 0 ; i < metric->n_ptiles; ++i)
993             {
994               metric->ptl[i] = (struct percentile *)
995                 percentile_create (percentile_list.data[i] / 100.0, metric->n_valid);
996
997               if ( percentile_list.data[i] == 25)
998                 metric->quartiles[0] = metric->ptl[i];
999               else if ( percentile_list.data[i] == 50)
1000                 metric->quartiles[1] = metric->ptl[i];
1001               else if ( percentile_list.data[i] == 75)
1002                 metric->quartiles[2] = metric->ptl[i];
1003             }
1004
1005           metric->tukey_hinges = tukey_hinges_create (metric->n, metric->cmin);
1006           metric->trimmed_mean = trimmed_mean_create (metric->n, 0.05);
1007
1008           n_os = metric->n_ptiles + 2;
1009
1010          if ( cmd->a_plot[XMN_PLT_NPPLOT] )
1011             {
1012               metric->np = np_create (metric->moments);
1013               n_os ++;
1014             }
1015
1016           os = xcalloc (sizeof (struct order_stats *), n_os);
1017
1018           for (i = 0 ; i < metric->n_ptiles ; ++i )
1019             {
1020               os[i] = (struct order_stats *) metric->ptl[i];
1021             }
1022
1023           os[i] = (struct order_stats *) metric->tukey_hinges;
1024           os[i+1] = (struct order_stats *) metric->trimmed_mean;
1025
1026           if (cmd->a_plot[XMN_PLT_NPPLOT])
1027             os[i+2] = metric->np;
1028
1029           order_stats_accumulate (os, n_os,
1030                                   casereader_clone (metric->up_reader),
1031                                   wv, dependent_vars[v], MV_ANY);
1032           free (os);
1033         }
1034     }
1035
1036   /* FIXME: Do this in the above loop */
1037   if ( cmd->a_plot[XMN_PLT_HISTOGRAM] )
1038     {
1039       struct ccase *c;
1040       struct casereader *input = casereader_clone (reader);
1041
1042       for (v = 0; v < n_dependent_vars; ++v)
1043         {
1044           const struct extremum  *max, *min;
1045           struct factor_metrics *metric = &result->metrics[v];
1046
1047           const struct ll_list *max_list =
1048             extrema_list (result->metrics[v].maxima);
1049
1050           const struct ll_list *min_list =
1051             extrema_list (result->metrics[v].minima);
1052
1053           if ( ll_is_empty (max_list))
1054             {
1055               msg (MW, _("Not creating plot because data set is empty."));
1056               continue;
1057             }
1058
1059           assert (! ll_is_empty (min_list));
1060
1061           max = (const struct extremum *)
1062             ll_data (ll_head(max_list), struct extremum, ll);
1063
1064           min = (const struct extremum *)
1065             ll_data (ll_head (min_list), struct extremum, ll);
1066
1067           metric->histogram = histogram_create (10, min->value, max->value);
1068         }
1069
1070       while ((c = casereader_read (input)) != NULL)
1071         {
1072           const double weight = wv ? case_data (c, wv)->f : 1.0;
1073
1074           for (v = 0; v < n_dependent_vars; ++v)
1075             {
1076               struct factor_metrics *metric = &result->metrics[v];
1077               if ( metric->histogram)
1078                 histogram_add ((struct histogram *) metric->histogram,
1079                                case_data (c, dependent_vars[v])->f, weight);
1080             }
1081           case_unref (c);
1082         }
1083       casereader_destroy (input);
1084     }
1085
1086   /* In this case, a third iteration is required */
1087   if (cmd->a_plot[XMN_PLT_BOXPLOT])
1088     {
1089       for (v = 0; v < n_dependent_vars; ++v)
1090         {
1091           struct factor_metrics *metric = &result->metrics[v];
1092
1093           metric->box_whisker =
1094             box_whisker_create ((struct tukey_hinges *) metric->tukey_hinges,
1095                                 cmd->v_id,
1096                                 casereader_get_value_cnt (metric->up_reader)
1097                                 - 1);
1098
1099           order_stats_accumulate ((struct order_stats **) &metric->box_whisker,
1100                                   1,
1101                                   casereader_clone (metric->up_reader),
1102                                   wv, dependent_vars[v], MV_ANY);
1103         }
1104     }
1105
1106   ll_push_tail (&factor->result_list, &result->ll);
1107   casereader_destroy (reader);
1108 }
1109
1110
1111 static void
1112 run_examine (struct cmd_examine *cmd, struct casereader *input,
1113              struct dataset *ds)
1114 {
1115   struct ll *ll;
1116   const struct dictionary *dict = dataset_dict (ds);
1117   struct ccase *c;
1118   struct casereader *level0 = casereader_clone (input);
1119
1120   c = casereader_peek (input, 0);
1121   if (c == NULL)
1122     {
1123       casereader_destroy (input);
1124       return;
1125     }
1126
1127   output_split_file_values (ds, c);
1128   case_unref (c);
1129
1130   ll_init (&level0_factor.result_list);
1131
1132   examine_group (cmd, level0, 0, dict, &level0_factor);
1133
1134   for (ll = ll_head (&factor_list);
1135        ll != ll_null (&factor_list);
1136        ll = ll_next (ll))
1137     {
1138       struct xfactor *factor = ll_data (ll, struct xfactor, ll);
1139
1140       struct casereader *group = NULL;
1141       struct casereader *level1;
1142       struct casegrouper *grouper1 = NULL;
1143
1144       level1 = casereader_clone (input);
1145       level1 = sort_execute_1var (level1, factor->indep_var[0]);
1146       grouper1 = casegrouper_create_vars (level1, &factor->indep_var[0], 1);
1147
1148       while (casegrouper_get_next_group (grouper1, &group))
1149         {
1150           struct casereader *group_copy = casereader_clone (group);
1151
1152           if ( !factor->indep_var[1])
1153             examine_group (cmd, group_copy, 1, dict, factor);
1154           else
1155             {
1156               int n_groups = 0;
1157               struct casereader *group2 = NULL;
1158               struct casegrouper *grouper2 = NULL;
1159
1160               group_copy = sort_execute_1var (group_copy,
1161                                               factor->indep_var[1]);
1162
1163               grouper2 = casegrouper_create_vars (group_copy,
1164                                                   &factor->indep_var[1], 1);
1165
1166               while (casegrouper_get_next_group (grouper2, &group2))
1167                 {
1168                   examine_group (cmd, group2, 2, dict, factor);
1169                   n_groups++;
1170                 }
1171               casegrouper_destroy (grouper2);
1172             }
1173
1174           casereader_destroy (group);
1175         }
1176       casegrouper_destroy (grouper1);
1177     }
1178
1179   casereader_destroy (input);
1180
1181   output_examine ();
1182
1183   factor_destroy (&level0_factor);
1184
1185   {
1186     struct ll *ll;
1187     for (ll = ll_head (&factor_list);
1188          ll != ll_null (&factor_list);
1189          ll = ll_next (ll))
1190       {
1191         struct xfactor *f = ll_data (ll, struct xfactor, ll);
1192         factor_destroy (f);
1193       }
1194   }
1195
1196 }
1197
1198
1199 static void
1200 show_summary (const struct variable **dependent_var, int n_dep_var,
1201               const struct xfactor *fctr)
1202 {
1203   static const char *subtitle[]=
1204     {
1205       N_("Valid"),
1206       N_("Missing"),
1207       N_("Total")
1208     };
1209
1210   int v, j;
1211   int heading_columns = 1;
1212   int n_cols;
1213   const int heading_rows = 3;
1214   struct tab_table *tbl;
1215
1216   int n_rows ;
1217   n_rows = n_dep_var;
1218
1219   assert (fctr);
1220
1221   if ( fctr->indep_var[0] )
1222     {
1223       heading_columns = 2;
1224
1225       if ( fctr->indep_var[1] )
1226         {
1227           heading_columns = 3;
1228         }
1229     }
1230
1231   n_rows *= ll_count (&fctr->result_list);
1232   n_rows += heading_rows;
1233
1234   n_cols = heading_columns + 6;
1235
1236   tbl = tab_create (n_cols, n_rows, 0);
1237   tab_headers (tbl, heading_columns, 0, heading_rows, 0);
1238
1239   tab_dim (tbl, tab_natural_dimensions);
1240
1241   /* Outline the box */
1242   tab_box (tbl,
1243            TAL_2, TAL_2,
1244            -1, -1,
1245            0, 0,
1246            n_cols - 1, n_rows - 1);
1247
1248   /* Vertical lines for the data only */
1249   tab_box (tbl,
1250            -1, -1,
1251            -1, TAL_1,
1252            heading_columns, 0,
1253            n_cols - 1, n_rows - 1);
1254
1255
1256   tab_hline (tbl, TAL_2, 0, n_cols - 1, heading_rows );
1257   tab_hline (tbl, TAL_1, heading_columns, n_cols - 1, 1 );
1258   tab_hline (tbl, TAL_1, heading_columns, n_cols - 1, heading_rows -1 );
1259
1260   tab_vline (tbl, TAL_2, heading_columns, 0, n_rows - 1);
1261
1262
1263   tab_title (tbl, _("Case Processing Summary"));
1264
1265   tab_joint_text (tbl, heading_columns, 0,
1266                   n_cols -1, 0,
1267                   TAB_CENTER | TAT_TITLE,
1268                   _("Cases"));
1269
1270   /* Remove lines ... */
1271   tab_box (tbl,
1272            -1, -1,
1273            TAL_0, TAL_0,
1274            heading_columns, 0,
1275            n_cols - 1, 0);
1276
1277   for (j = 0 ; j < 3 ; ++j)
1278     {
1279       tab_text (tbl, heading_columns + j * 2 , 2, TAB_CENTER | TAT_TITLE,
1280                 _("N"));
1281
1282       tab_text (tbl, heading_columns + j * 2 + 1, 2, TAB_CENTER | TAT_TITLE,
1283                 _("Percent"));
1284
1285       tab_joint_text (tbl, heading_columns + j * 2 , 1,
1286                       heading_columns + j * 2 + 1, 1,
1287                       TAB_CENTER | TAT_TITLE,
1288                       subtitle[j]);
1289
1290       tab_box (tbl, -1, -1,
1291                TAL_0, TAL_0,
1292                heading_columns + j * 2, 1,
1293                heading_columns + j * 2 + 1, 1);
1294     }
1295
1296
1297   /* Titles for the independent variables */
1298   if ( fctr->indep_var[0] )
1299     {
1300       tab_text (tbl, 1, heading_rows - 1, TAB_CENTER | TAT_TITLE,
1301                 var_to_string (fctr->indep_var[0]));
1302
1303       if ( fctr->indep_var[1] )
1304         {
1305           tab_text (tbl, 2, heading_rows - 1, TAB_CENTER | TAT_TITLE,
1306                     var_to_string (fctr->indep_var[1]));
1307         }
1308     }
1309
1310   for (v = 0 ; v < n_dep_var ; ++v)
1311     {
1312       int j = 0;
1313       struct ll *ll;
1314       union value *last_value = NULL;
1315
1316       if ( v > 0 )
1317         tab_hline (tbl, TAL_1, 0, n_cols -1 ,
1318                    v * ll_count (&fctr->result_list)
1319                    + heading_rows);
1320
1321       tab_text (tbl,
1322                 0,
1323                 v * ll_count (&fctr->result_list) + heading_rows,
1324                 TAB_LEFT | TAT_TITLE,
1325                 var_to_string (dependent_var[v])
1326                 );
1327
1328
1329       for (ll = ll_head (&fctr->result_list);
1330            ll != ll_null (&fctr->result_list); ll = ll_next (ll))
1331         {
1332           double n;
1333           const struct factor_result *result =
1334             ll_data (ll, struct factor_result, ll);
1335
1336           if ( fctr->indep_var[0] )
1337             {
1338
1339               if ( last_value == NULL ||
1340                    compare_values_short (last_value, result->value[0],
1341                                          fctr->indep_var[0]))
1342                 {
1343                   struct string str;
1344
1345                   last_value = result->value[0];
1346                   ds_init_empty (&str);
1347
1348                   var_append_value_name (fctr->indep_var[0], result->value[0],
1349                                          &str);
1350
1351                   tab_text (tbl, 1,
1352                             heading_rows + j +
1353                             v * ll_count (&fctr->result_list),
1354                             TAB_LEFT | TAT_TITLE,
1355                             ds_cstr (&str));
1356
1357                   ds_destroy (&str);
1358
1359                   if ( fctr->indep_var[1] && j > 0)
1360                     tab_hline (tbl, TAL_1, 1, n_cols - 1,
1361                                heading_rows + j +
1362                                v * ll_count (&fctr->result_list));
1363                 }
1364
1365               if ( fctr->indep_var[1])
1366                 {
1367                   struct string str;
1368
1369                   ds_init_empty (&str);
1370
1371                   var_append_value_name (fctr->indep_var[1],
1372                                          result->value[1], &str);
1373
1374                   tab_text (tbl, 2,
1375                             heading_rows + j +
1376                             v * ll_count (&fctr->result_list),
1377                             TAB_LEFT | TAT_TITLE,
1378                             ds_cstr (&str));
1379
1380                   ds_destroy (&str);
1381                 }
1382             }
1383
1384
1385           moments1_calculate (result->metrics[v].moments,
1386                               &n, &result->metrics[v].mean,
1387                               &result->metrics[v].variance,
1388                               &result->metrics[v].skewness,
1389                               &result->metrics[v].kurtosis);
1390
1391           result->metrics[v].se_mean = sqrt (result->metrics[v].variance / n) ;
1392
1393           /* Total Valid */
1394           tab_float (tbl, heading_columns,
1395                      heading_rows + j + v * ll_count (&fctr->result_list),
1396                      TAB_LEFT,
1397                      n, 8, 0);
1398
1399           tab_text (tbl, heading_columns + 1,
1400                     heading_rows + j + v * ll_count (&fctr->result_list),
1401                     TAB_RIGHT | TAT_PRINTF,
1402                     "%g%%", n * 100.0 / result->metrics[v].n);
1403
1404           /* Total Missing */
1405           tab_float (tbl, heading_columns + 2,
1406                      heading_rows + j + v * ll_count (&fctr->result_list),
1407                      TAB_LEFT,
1408                      result->metrics[v].n - n,
1409                      8, 0);
1410
1411           tab_text (tbl, heading_columns + 3,
1412                     heading_rows + j + v * ll_count (&fctr->result_list),
1413                     TAB_RIGHT | TAT_PRINTF,
1414                     "%g%%",
1415                     (result->metrics[v].n - n) * 100.0 / result->metrics[v].n
1416                     );
1417
1418           /* Total Valid + Missing */
1419           tab_float (tbl, heading_columns + 4,
1420                      heading_rows + j + v * ll_count (&fctr->result_list),
1421                      TAB_LEFT,
1422                      result->metrics[v].n,
1423                      8, 0);
1424
1425           tab_text (tbl, heading_columns + 5,
1426                     heading_rows + j + v * ll_count (&fctr->result_list),
1427                     TAB_RIGHT | TAT_PRINTF,
1428                     "%g%%",
1429                     (result->metrics[v].n) * 100.0 / result->metrics[v].n
1430                     );
1431
1432           ++j;
1433         }
1434     }
1435
1436
1437   tab_submit (tbl);
1438 }
1439
1440 #define DESCRIPTIVE_ROWS 13
1441
1442 static void
1443 show_descriptives (const struct variable **dependent_var,
1444                    int n_dep_var,
1445                    const struct xfactor *fctr)
1446 {
1447   int v;
1448   int heading_columns = 3;
1449   int n_cols;
1450   const int heading_rows = 1;
1451   struct tab_table *tbl;
1452
1453   int n_rows ;
1454   n_rows = n_dep_var;
1455
1456   assert (fctr);
1457
1458   if ( fctr->indep_var[0] )
1459     {
1460       heading_columns = 4;
1461
1462       if ( fctr->indep_var[1] )
1463         {
1464           heading_columns = 5;
1465         }
1466     }
1467
1468   n_rows *= ll_count (&fctr->result_list) * DESCRIPTIVE_ROWS;
1469   n_rows += heading_rows;
1470
1471   n_cols = heading_columns + 2;
1472
1473   tbl = tab_create (n_cols, n_rows, 0);
1474   tab_headers (tbl, heading_columns, 0, heading_rows, 0);
1475
1476   tab_dim (tbl, tab_natural_dimensions);
1477
1478   /* Outline the box */
1479   tab_box (tbl,
1480            TAL_2, TAL_2,
1481            -1, -1,
1482            0, 0,
1483            n_cols - 1, n_rows - 1);
1484
1485
1486   tab_hline (tbl, TAL_2, 0, n_cols - 1, heading_rows );
1487   tab_hline (tbl, TAL_2, 1, n_cols - 1, heading_rows );
1488
1489   tab_vline (tbl, TAL_1, n_cols - 1, 0, n_rows - 1);
1490
1491
1492   if ( fctr->indep_var[0])
1493     tab_text (tbl, 1, 0, TAT_TITLE, var_to_string (fctr->indep_var[0]));
1494
1495   if ( fctr->indep_var[1])
1496     tab_text (tbl, 2, 0, TAT_TITLE, var_to_string (fctr->indep_var[1]));
1497
1498   for (v = 0 ; v < n_dep_var ; ++v )
1499     {
1500       struct ll *ll;
1501       int i = 0;
1502
1503       const int row_var_start =
1504         v * DESCRIPTIVE_ROWS * ll_count(&fctr->result_list);
1505
1506       tab_text (tbl,
1507                 0,
1508                 heading_rows + row_var_start,
1509                 TAB_LEFT | TAT_TITLE,
1510                 var_to_string (dependent_var[v])
1511                 );
1512
1513       for (ll = ll_head (&fctr->result_list);
1514            ll != ll_null (&fctr->result_list); i++, ll = ll_next (ll))
1515         {
1516           const struct factor_result *result =
1517             ll_data (ll, struct factor_result, ll);
1518
1519           const double t =
1520             gsl_cdf_tdist_Qinv ((1 - cmd.n_cinterval[0] / 100.0) / 2.0,
1521                                       result->metrics[v].n - 1);
1522
1523           if ( i > 0 || v > 0 )
1524             {
1525               const int left_col = (i == 0) ? 0 : 1;
1526               tab_hline (tbl, TAL_1, left_col, n_cols - 1,
1527                          heading_rows + row_var_start + i * DESCRIPTIVE_ROWS);
1528             }
1529
1530           if ( fctr->indep_var[0])
1531             {
1532               struct string vstr;
1533               ds_init_empty (&vstr);
1534               var_append_value_name (fctr->indep_var[0],
1535                                      result->value[0], &vstr);
1536
1537               tab_text (tbl, 1,
1538                         heading_rows + row_var_start + i * DESCRIPTIVE_ROWS,
1539                         TAB_LEFT,
1540                         ds_cstr (&vstr)
1541                         );
1542
1543               ds_destroy (&vstr);
1544             }
1545
1546
1547           tab_text (tbl, n_cols - 4,
1548                     heading_rows + row_var_start + i * DESCRIPTIVE_ROWS,
1549                     TAB_LEFT,
1550                     _("Mean"));
1551
1552           tab_text (tbl, n_cols - 4,
1553                     heading_rows + row_var_start + 1 + i * DESCRIPTIVE_ROWS,
1554                     TAB_LEFT | TAT_PRINTF,
1555                     _("%g%% Confidence Interval for Mean"),
1556                     cmd.n_cinterval[0]);
1557
1558           tab_text (tbl, n_cols - 3,
1559                     heading_rows + row_var_start + 1 + i * DESCRIPTIVE_ROWS,
1560                     TAB_LEFT,
1561                     _("Lower Bound"));
1562
1563           tab_text (tbl, n_cols - 3,
1564                     heading_rows + row_var_start + 2 + i * DESCRIPTIVE_ROWS,
1565                     TAB_LEFT,
1566                     _("Upper Bound"));
1567
1568           tab_text (tbl, n_cols - 4,
1569                     heading_rows + row_var_start + 3 + i * DESCRIPTIVE_ROWS,
1570                     TAB_LEFT | TAT_PRINTF,
1571                     _("5%% Trimmed Mean"));
1572
1573           tab_text (tbl, n_cols - 4,
1574                     heading_rows + row_var_start + 4 + i * DESCRIPTIVE_ROWS,
1575                     TAB_LEFT,
1576                     _("Median"));
1577
1578           tab_text (tbl, n_cols - 4,
1579                     heading_rows + row_var_start + 5 + i * DESCRIPTIVE_ROWS,
1580                     TAB_LEFT,
1581                     _("Variance"));
1582
1583           tab_text (tbl, n_cols - 4,
1584                     heading_rows + row_var_start + 6 + i * DESCRIPTIVE_ROWS,
1585                     TAB_LEFT,
1586                     _("Std. Deviation"));
1587
1588           tab_text (tbl, n_cols - 4,
1589                     heading_rows + row_var_start + 7 + i * DESCRIPTIVE_ROWS,
1590                     TAB_LEFT,
1591                     _("Minimum"));
1592
1593           tab_text (tbl, n_cols - 4,
1594                     heading_rows + row_var_start + 8 + i * DESCRIPTIVE_ROWS,
1595                     TAB_LEFT,
1596                     _("Maximum"));
1597
1598           tab_text (tbl, n_cols - 4,
1599                     heading_rows + row_var_start + 9 + i * DESCRIPTIVE_ROWS,
1600                     TAB_LEFT,
1601                     _("Range"));
1602
1603           tab_text (tbl, n_cols - 4,
1604                     heading_rows + row_var_start + 10 + i * DESCRIPTIVE_ROWS,
1605                     TAB_LEFT,
1606                     _("Interquartile Range"));
1607
1608
1609           tab_text (tbl, n_cols - 4,
1610                     heading_rows + row_var_start + 11 + i * DESCRIPTIVE_ROWS,
1611                     TAB_LEFT,
1612                     _("Skewness"));
1613
1614           tab_text (tbl, n_cols - 4,
1615                     heading_rows + row_var_start + 12 + i * DESCRIPTIVE_ROWS,
1616                     TAB_LEFT,
1617                     _("Kurtosis"));
1618
1619
1620           /* Now the statistics ... */
1621
1622           tab_float (tbl, n_cols - 2,
1623                     heading_rows + row_var_start + i * DESCRIPTIVE_ROWS,
1624                      TAB_CENTER,
1625                      result->metrics[v].mean,
1626                      8, 2);
1627
1628           tab_float (tbl, n_cols - 1,
1629                     heading_rows + row_var_start + i * DESCRIPTIVE_ROWS,
1630                      TAB_CENTER,
1631                      result->metrics[v].se_mean,
1632                      8, 3);
1633
1634
1635           tab_float (tbl, n_cols - 2,
1636                      heading_rows + row_var_start + 1 + i * DESCRIPTIVE_ROWS,
1637                      TAB_CENTER,
1638                      result->metrics[v].mean - t *
1639                       result->metrics[v].se_mean,
1640                      8, 3);
1641
1642           tab_float (tbl, n_cols - 2,
1643                      heading_rows + row_var_start + 2 + i * DESCRIPTIVE_ROWS,
1644                      TAB_CENTER,
1645                      result->metrics[v].mean + t *
1646                       result->metrics[v].se_mean,
1647                      8, 3);
1648
1649
1650           tab_float (tbl, n_cols - 2,
1651                      heading_rows + row_var_start + 3 + i * DESCRIPTIVE_ROWS,
1652                      TAB_CENTER,
1653                      trimmed_mean_calculate ((struct trimmed_mean *) result->metrics[v].trimmed_mean),
1654                      8, 2);
1655
1656
1657           tab_float (tbl, n_cols - 2,
1658                      heading_rows + row_var_start + 4 + i * DESCRIPTIVE_ROWS,
1659                      TAB_CENTER,
1660                      percentile_calculate (result->metrics[v].quartiles[1], percentile_algorithm),
1661                      8, 2);
1662
1663
1664           tab_float (tbl, n_cols - 2,
1665                      heading_rows + row_var_start + 5 + i * DESCRIPTIVE_ROWS,
1666                      TAB_CENTER,
1667                      result->metrics[v].variance,
1668                      8, 3);
1669
1670           tab_float (tbl, n_cols - 2,
1671                      heading_rows + row_var_start + 6 + i * DESCRIPTIVE_ROWS,
1672                      TAB_CENTER,
1673                      sqrt (result->metrics[v].variance),
1674                      8, 3);
1675
1676           tab_float (tbl, n_cols - 2,
1677                      heading_rows + row_var_start + 10 + i * DESCRIPTIVE_ROWS,
1678                      TAB_CENTER,
1679                      percentile_calculate (result->metrics[v].quartiles[2],
1680                                            percentile_algorithm) -
1681                      percentile_calculate (result->metrics[v].quartiles[0],
1682                                            percentile_algorithm),
1683                      8, 2);
1684
1685
1686           tab_float (tbl, n_cols - 2,
1687                      heading_rows + row_var_start + 11 + i * DESCRIPTIVE_ROWS,
1688                      TAB_CENTER,
1689                      result->metrics[v].skewness,
1690                      8, 3);
1691
1692           tab_float (tbl, n_cols - 2,
1693                      heading_rows + row_var_start + 12 + i * DESCRIPTIVE_ROWS,
1694                      TAB_CENTER,
1695                      result->metrics[v].kurtosis,
1696                      8, 3);
1697
1698           tab_float (tbl, n_cols - 1,
1699                      heading_rows + row_var_start + 11 + i * DESCRIPTIVE_ROWS,
1700                      TAB_CENTER,
1701                      calc_seskew (result->metrics[v].n),
1702                      8, 3);
1703
1704           tab_float (tbl, n_cols - 1,
1705                      heading_rows + row_var_start + 12 + i * DESCRIPTIVE_ROWS,
1706                      TAB_CENTER,
1707                      calc_sekurt (result->metrics[v].n),
1708                      8, 3);
1709
1710           {
1711             struct extremum *minimum, *maximum ;
1712
1713             struct ll *max_ll = ll_head (extrema_list (result->metrics[v].maxima));
1714             struct ll *min_ll = ll_head (extrema_list (result->metrics[v].minima));
1715
1716             maximum = ll_data (max_ll, struct extremum, ll);
1717             minimum = ll_data (min_ll, struct extremum, ll);
1718
1719             tab_float (tbl, n_cols - 2,
1720                        heading_rows + row_var_start + 7 + i * DESCRIPTIVE_ROWS,
1721                        TAB_CENTER,
1722                        minimum->value,
1723                        8, 3);
1724
1725             tab_float (tbl, n_cols - 2,
1726                        heading_rows + row_var_start + 8 + i * DESCRIPTIVE_ROWS,
1727                        TAB_CENTER,
1728                        maximum->value,
1729                        8, 3);
1730
1731             tab_float (tbl, n_cols - 2,
1732                        heading_rows + row_var_start + 9 + i * DESCRIPTIVE_ROWS,
1733                        TAB_CENTER,
1734                        maximum->value - minimum->value,
1735                        8, 3);
1736           }
1737         }
1738     }
1739
1740   tab_vline (tbl, TAL_2, heading_columns, 0, n_rows - 1);
1741
1742   tab_title (tbl, _("Descriptives"));
1743
1744   tab_text (tbl, n_cols - 2, 0, TAB_CENTER | TAT_TITLE,
1745             _("Statistic"));
1746
1747   tab_text (tbl, n_cols - 1, 0, TAB_CENTER | TAT_TITLE,
1748             _("Std. Error"));
1749
1750   tab_submit (tbl);
1751 }
1752
1753
1754
1755 static void
1756 show_extremes (const struct variable **dependent_var,
1757                int n_dep_var,
1758                const struct xfactor *fctr)
1759 {
1760   int v;
1761   int heading_columns = 3;
1762   int n_cols;
1763   const int heading_rows = 1;
1764   struct tab_table *tbl;
1765
1766   int n_rows ;
1767   n_rows = n_dep_var;
1768
1769   assert (fctr);
1770
1771   if ( fctr->indep_var[0] )
1772     {
1773       heading_columns = 4;
1774
1775       if ( fctr->indep_var[1] )
1776         {
1777           heading_columns = 5;
1778         }
1779     }
1780
1781   n_rows *= ll_count (&fctr->result_list) * cmd.st_n * 2;
1782   n_rows += heading_rows;
1783
1784   n_cols = heading_columns + 2;
1785
1786   tbl = tab_create (n_cols, n_rows, 0);
1787   tab_headers (tbl, heading_columns, 0, heading_rows, 0);
1788
1789   tab_dim (tbl, tab_natural_dimensions);
1790
1791   /* Outline the box */
1792   tab_box (tbl,
1793            TAL_2, TAL_2,
1794            -1, -1,
1795            0, 0,
1796            n_cols - 1, n_rows - 1);
1797
1798
1799   tab_hline (tbl, TAL_2, 0, n_cols - 1, heading_rows );
1800   tab_hline (tbl, TAL_2, 1, n_cols - 1, heading_rows );
1801   tab_vline (tbl, TAL_1, n_cols - 1, 0, n_rows - 1);
1802
1803   if ( fctr->indep_var[0])
1804     tab_text (tbl, 1, 0, TAT_TITLE, var_to_string (fctr->indep_var[0]));
1805
1806   if ( fctr->indep_var[1])
1807     tab_text (tbl, 2, 0, TAT_TITLE, var_to_string (fctr->indep_var[1]));
1808
1809   for (v = 0 ; v < n_dep_var ; ++v )
1810     {
1811       struct ll *ll;
1812       int i = 0;
1813       const int row_var_start = v * cmd.st_n * 2 * ll_count(&fctr->result_list);
1814
1815       tab_text (tbl,
1816                 0,
1817                 heading_rows + row_var_start,
1818                 TAB_LEFT | TAT_TITLE,
1819                 var_to_string (dependent_var[v])
1820                 );
1821
1822       for (ll = ll_head (&fctr->result_list);
1823            ll != ll_null (&fctr->result_list); i++, ll = ll_next (ll))
1824         {
1825           int e ;
1826           struct ll *min_ll;
1827           struct ll *max_ll;
1828           const int row_result_start = i * cmd.st_n * 2;
1829
1830           const struct factor_result *result =
1831             ll_data (ll, struct factor_result, ll);
1832
1833           if (i > 0 || v > 0)
1834             tab_hline (tbl, TAL_1, 1, n_cols - 1,
1835                        heading_rows + row_var_start + row_result_start);
1836
1837           tab_hline (tbl, TAL_1, heading_columns - 2, n_cols - 1,
1838                      heading_rows + row_var_start + row_result_start + cmd.st_n);
1839
1840           for ( e = 1; e <= cmd.st_n; ++e )
1841             {
1842               tab_text (tbl, n_cols - 3,
1843                         heading_rows + row_var_start + row_result_start + e - 1,
1844                         TAB_RIGHT | TAT_PRINTF,
1845                         _("%d"), e);
1846
1847               tab_text (tbl, n_cols - 3,
1848                         heading_rows + row_var_start + row_result_start + cmd.st_n + e - 1,
1849                         TAB_RIGHT | TAT_PRINTF,
1850                         _("%d"), e);
1851             }
1852
1853
1854           min_ll = ll_head (extrema_list (result->metrics[v].minima));
1855           for (e = 0; e < cmd.st_n;)
1856             {
1857               struct extremum *minimum = ll_data (min_ll, struct extremum, ll);
1858               double weight = minimum->weight;
1859
1860               while (weight-- > 0 && e < cmd.st_n)
1861                 {
1862                   tab_float (tbl, n_cols - 1,
1863                              heading_rows + row_var_start + row_result_start + cmd.st_n + e,
1864                              TAB_RIGHT,
1865                              minimum->value,
1866                              8, 2);
1867
1868
1869                   tab_float (tbl, n_cols - 2,
1870                              heading_rows + row_var_start + row_result_start + cmd.st_n + e,
1871                              TAB_RIGHT,
1872                              minimum->location,
1873                              8, 0);
1874                   ++e;
1875                 }
1876
1877               min_ll = ll_next (min_ll);
1878             }
1879
1880
1881           max_ll = ll_head (extrema_list (result->metrics[v].maxima));
1882           for (e = 0; e < cmd.st_n;)
1883             {
1884               struct extremum *maximum = ll_data (max_ll, struct extremum, ll);
1885               double weight = maximum->weight;
1886
1887               while (weight-- > 0 && e < cmd.st_n)
1888                 {
1889                   tab_float (tbl, n_cols - 1,
1890                              heading_rows + row_var_start + row_result_start + e,
1891                              TAB_RIGHT,
1892                              maximum->value,
1893                              8, 2);
1894
1895
1896                   tab_float (tbl, n_cols - 2,
1897                              heading_rows + row_var_start + row_result_start + e,
1898                              TAB_RIGHT,
1899                              maximum->location,
1900                              8, 0);
1901                   ++e;
1902                 }
1903
1904               max_ll = ll_next (max_ll);
1905             }
1906
1907
1908           if ( fctr->indep_var[0])
1909             {
1910               struct string vstr;
1911               ds_init_empty (&vstr);
1912               var_append_value_name (fctr->indep_var[0],
1913                                      result->value[0], &vstr);
1914
1915               tab_text (tbl, 1,
1916                         heading_rows + row_var_start + row_result_start,
1917                         TAB_LEFT,
1918                         ds_cstr (&vstr)
1919                         );
1920
1921               ds_destroy (&vstr);
1922             }
1923
1924
1925           tab_text (tbl, n_cols - 4,
1926                     heading_rows + row_var_start + row_result_start,
1927                     TAB_RIGHT,
1928                     _("Highest"));
1929
1930           tab_text (tbl, n_cols - 4,
1931                     heading_rows + row_var_start + row_result_start + cmd.st_n,
1932                     TAB_RIGHT,
1933                     _("Lowest"));
1934         }
1935     }
1936
1937   tab_vline (tbl, TAL_2, heading_columns, 0, n_rows - 1);
1938
1939
1940   tab_title (tbl, _("Extreme Values"));
1941
1942
1943   tab_text (tbl, n_cols - 2, 0, TAB_CENTER | TAT_TITLE,
1944             _("Case Number"));
1945
1946
1947   tab_text (tbl, n_cols - 1, 0, TAB_CENTER | TAT_TITLE,
1948             _("Value"));
1949
1950   tab_submit (tbl);
1951 }
1952
1953 #define PERCENTILE_ROWS 2
1954
1955 static void
1956 show_percentiles (const struct variable **dependent_var,
1957                   int n_dep_var,
1958                   const struct xfactor *fctr)
1959 {
1960   int i;
1961   int v;
1962   int heading_columns = 2;
1963   int n_cols;
1964   const int n_percentiles = subc_list_double_count (&percentile_list);
1965   const int heading_rows = 2;
1966   struct tab_table *tbl;
1967
1968   int n_rows ;
1969   n_rows = n_dep_var;
1970
1971   assert (fctr);
1972
1973   if ( fctr->indep_var[0] )
1974     {
1975       heading_columns = 3;
1976
1977       if ( fctr->indep_var[1] )
1978         {
1979           heading_columns = 4;
1980         }
1981     }
1982
1983   n_rows *= ll_count (&fctr->result_list) * PERCENTILE_ROWS;
1984   n_rows += heading_rows;
1985
1986   n_cols = heading_columns + n_percentiles;
1987
1988   tbl = tab_create (n_cols, n_rows, 0);
1989   tab_headers (tbl, heading_columns, 0, heading_rows, 0);
1990
1991   tab_dim (tbl, tab_natural_dimensions);
1992
1993   /* Outline the box */
1994   tab_box (tbl,
1995            TAL_2, TAL_2,
1996            -1, -1,
1997            0, 0,
1998            n_cols - 1, n_rows - 1);
1999
2000
2001   tab_hline (tbl, TAL_2, 0, n_cols - 1, heading_rows );
2002   tab_hline (tbl, TAL_2, 1, n_cols - 1, heading_rows );
2003
2004   if ( fctr->indep_var[0])
2005     tab_text (tbl, 1, 1, TAT_TITLE, var_to_string (fctr->indep_var[0]));
2006
2007   if ( fctr->indep_var[1])
2008     tab_text (tbl, 2, 1, TAT_TITLE, var_to_string (fctr->indep_var[1]));
2009
2010   for (v = 0 ; v < n_dep_var ; ++v )
2011     {
2012       double hinges[3];
2013       struct ll *ll;
2014       int i = 0;
2015
2016       const int row_var_start =
2017         v * PERCENTILE_ROWS * ll_count(&fctr->result_list);
2018
2019       tab_text (tbl,
2020                 0,
2021                 heading_rows + row_var_start,
2022                 TAB_LEFT | TAT_TITLE,
2023                 var_to_string (dependent_var[v])
2024                 );
2025
2026       for (ll = ll_head (&fctr->result_list);
2027            ll != ll_null (&fctr->result_list); i++, ll = ll_next (ll))
2028         {
2029           int j;
2030           const struct factor_result *result =
2031             ll_data (ll, struct factor_result, ll);
2032
2033           if ( i > 0 || v > 0 )
2034             {
2035               const int left_col = (i == 0) ? 0 : 1;
2036               tab_hline (tbl, TAL_1, left_col, n_cols - 1,
2037                          heading_rows + row_var_start + i * PERCENTILE_ROWS);
2038             }
2039
2040           if ( fctr->indep_var[0])
2041             {
2042               struct string vstr;
2043               ds_init_empty (&vstr);
2044               var_append_value_name (fctr->indep_var[0],
2045                                      result->value[0], &vstr);
2046
2047               tab_text (tbl, 1,
2048                         heading_rows + row_var_start + i * PERCENTILE_ROWS,
2049                         TAB_LEFT,
2050                         ds_cstr (&vstr)
2051                         );
2052
2053               ds_destroy (&vstr);
2054             }
2055
2056
2057           tab_text (tbl, n_cols - n_percentiles - 1,
2058                     heading_rows + row_var_start + i * PERCENTILE_ROWS,
2059                     TAB_LEFT,
2060                     ptile_alg_desc [percentile_algorithm]);
2061
2062
2063           tab_text (tbl, n_cols - n_percentiles - 1,
2064                     heading_rows + row_var_start + 1 + i * PERCENTILE_ROWS,
2065                     TAB_LEFT,
2066                     _("Tukey's Hinges"));
2067
2068
2069           tab_vline (tbl, TAL_1, n_cols - n_percentiles -1, heading_rows, n_rows - 1);
2070
2071           tukey_hinges_calculate ((struct tukey_hinges *) result->metrics[v].tukey_hinges,
2072                                   hinges);
2073
2074           for (j = 0; j < n_percentiles; ++j)
2075             {
2076               double hinge = SYSMIS;
2077               tab_float (tbl, n_cols - n_percentiles + j,
2078                          heading_rows + row_var_start + i * PERCENTILE_ROWS,
2079                          TAB_CENTER,
2080                          percentile_calculate (result->metrics[v].ptl[j],
2081                                                percentile_algorithm),
2082                          8, 2
2083                          );
2084
2085               if ( result->metrics[v].ptl[j]->ptile == 0.5)
2086                 hinge = hinges[1];
2087               else if ( result->metrics[v].ptl[j]->ptile == 0.25)
2088                 hinge = hinges[0];
2089               else if ( result->metrics[v].ptl[j]->ptile == 0.75)
2090                 hinge = hinges[2];
2091
2092               if ( hinge != SYSMIS)
2093                 tab_float (tbl, n_cols - n_percentiles + j,
2094                            heading_rows + row_var_start + 1 + i * PERCENTILE_ROWS,
2095                            TAB_CENTER,
2096                            hinge,
2097                            8, 2
2098                            );
2099
2100             }
2101         }
2102     }
2103
2104   tab_vline (tbl, TAL_2, heading_columns, 0, n_rows - 1);
2105
2106   tab_title (tbl, _("Percentiles"));
2107
2108
2109   for (i = 0 ; i < n_percentiles; ++i )
2110     {
2111       tab_text (tbl, n_cols - n_percentiles + i, 1,
2112                 TAB_CENTER | TAT_TITLE | TAT_PRINTF,
2113                 _("%g"),
2114                 subc_list_double_at (&percentile_list, i)
2115                 );
2116
2117
2118     }
2119
2120   tab_joint_text (tbl,
2121                   n_cols - n_percentiles, 0,
2122                   n_cols - 1, 0,
2123                   TAB_CENTER | TAT_TITLE,
2124                   _("Percentiles"));
2125
2126   /* Vertical lines for the data only */
2127   tab_box (tbl,
2128            -1, -1,
2129            -1, TAL_1,
2130            n_cols - n_percentiles, 1,
2131            n_cols - 1, n_rows - 1);
2132
2133   tab_hline (tbl, TAL_1, n_cols - n_percentiles, n_cols - 1, 1);
2134
2135
2136   tab_submit (tbl);
2137 }
2138
2139
2140 static void
2141 factor_to_string_concise (const struct xfactor *fctr,
2142                           const struct factor_result *result,
2143                           struct string *str
2144                           )
2145 {
2146   if (fctr->indep_var[0])
2147     {
2148       var_append_value_name (fctr->indep_var[0], result->value[0], str);
2149
2150       if ( fctr->indep_var[1] )
2151         {
2152           ds_put_cstr (str, ",");
2153
2154           var_append_value_name (fctr->indep_var[1], result->value[1], str);
2155
2156           ds_put_cstr (str, ")");
2157         }
2158     }
2159 }
2160
2161
2162 static void
2163 factor_to_string (const struct xfactor *fctr,
2164                   const struct factor_result *result,
2165                   struct string *str
2166                   )
2167 {
2168   if (fctr->indep_var[0])
2169     {
2170       ds_put_format (str, "(%s = ", var_get_name (fctr->indep_var[0]));
2171
2172       var_append_value_name (fctr->indep_var[0], result->value[0], str);
2173
2174       if ( fctr->indep_var[1] )
2175         {
2176           ds_put_cstr (str, ",");
2177           ds_put_format (str, "%s = ", var_get_name (fctr->indep_var[1]));
2178
2179           var_append_value_name (fctr->indep_var[1], result->value[1], str);
2180         }
2181       ds_put_cstr (str, ")");
2182     }
2183 }
2184
2185
2186
2187
2188 /*
2189   Local Variables:
2190   mode: c
2191   End:
2192 */