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