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