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