Delete trailing whitespace at end of lines.
[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
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 02110-1301, USA. */
19
20 #include <config.h>
21
22 #include <gsl/gsl_cdf.h>
23 #include <libpspp/message.h>
24 #include <math.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27
28 #include <data/case.h>
29 #include <data/casegrouper.h>
30 #include <data/casereader.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 const 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 (const struct variable **dependent_var, int n_dep_var,
121                          const struct factor *f);
122
123 static void show_extremes (const struct variable **dependent_var,
124                           int n_dep_var,
125                           const struct factor *factor,
126                           int n_extremities);
127
128 static void show_descriptives (const struct variable **dependent_var,
129                               int n_dep_var,
130                               struct factor *factor);
131
132 static void show_percentiles (const 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 void run_examine (struct cmd_examine *, struct casereader *,
157                          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 /* Categories of missing values to exclude. */
183 static enum mv_class exclude_values;
184
185 /* PERCENTILES */
186
187 static subc_list_double percentile_list;
188
189 static enum pc_alg percentile_algorithm;
190
191 static short sbc_percentile;
192
193
194 int
195 cmd_examine (struct lexer *lexer, struct dataset *ds)
196 {
197   struct casegrouper *grouper;
198   struct casereader *group;
199   bool ok;
200
201   subc_list_double_create (&percentile_list);
202   percentile_algorithm = PC_HAVERAGE;
203
204   if ( !parse_examine (lexer, ds, &cmd, NULL) )
205     {
206       subc_list_double_destroy (&percentile_list);
207       return CMD_FAILURE;
208     }
209
210   /* If /MISSING=INCLUDE is set, then user missing values are ignored */
211   exclude_values = cmd.incl == XMN_INCLUDE ? MV_SYSTEM : MV_ANY;
212
213   if ( cmd.st_n == SYSMIS )
214     cmd.st_n = 5;
215
216   if ( ! cmd.sbc_cinterval)
217     cmd.n_cinterval[0] = 95.0;
218
219   /* If descriptives have been requested, make sure the
220      quartiles are calculated */
221   if ( cmd.a_statistics[XMN_ST_DESCRIPTIVES] )
222     {
223       subc_list_double_push (&percentile_list, 25);
224       subc_list_double_push (&percentile_list, 50);
225       subc_list_double_push (&percentile_list, 75);
226     }
227
228   grouper = casegrouper_create_splits (proc_open (ds), dataset_dict (ds));
229   while (casegrouper_get_next_group (grouper, &group))
230     run_examine (&cmd, group, ds);
231   ok = casegrouper_destroy (grouper);
232   ok = proc_commit (ds) && ok;
233
234   if ( totals )
235     {
236       free ( totals );
237     }
238
239   if ( dependent_vars )
240     free (dependent_vars);
241
242   {
243     struct factor *f = factors ;
244     while ( f )
245       {
246         struct factor *ff = f;
247
248         f = f->next;
249         free ( ff->fs );
250         hsh_destroy ( ff->fstats ) ;
251         free ( ff ) ;
252       }
253     factors = 0;
254   }
255
256   subc_list_double_destroy (&percentile_list);
257
258   return ok ? CMD_SUCCESS : CMD_CASCADING_FAILURE;
259 };
260
261
262
263 /* Show all the appropriate tables */
264 static void
265 output_examine (void)
266 {
267   struct factor *fctr;
268
269   /* Show totals if appropriate */
270   if ( ! cmd.sbc_nototal || factors == 0 )
271     {
272       show_summary (dependent_vars, n_dependent_vars, 0);
273
274       if ( cmd.sbc_statistics )
275         {
276           if ( cmd.a_statistics[XMN_ST_EXTREME])
277             show_extremes (dependent_vars, n_dependent_vars, 0, cmd.st_n);
278
279           if ( cmd.a_statistics[XMN_ST_DESCRIPTIVES])
280             show_descriptives (dependent_vars, n_dependent_vars, 0);
281
282         }
283       if ( sbc_percentile )
284         show_percentiles (dependent_vars, n_dependent_vars, 0);
285
286       if ( cmd.sbc_plot)
287         {
288           int v;
289           if ( cmd.a_plot[XMN_PLT_STEMLEAF] )
290             msg (SW, _ ("%s is not currently supported."), "STEMLEAF");
291
292           if ( cmd.a_plot[XMN_PLT_SPREADLEVEL] )
293             msg (SW, _ ("%s is not currently supported."), "SPREADLEVEL");
294
295           if ( cmd.a_plot[XMN_PLT_NPPLOT] )
296             {
297               for ( v = 0 ; v < n_dependent_vars; ++v )
298                 np_plot (&totals[v], var_to_string (dependent_vars[v]));
299             }
300
301           if ( cmd.a_plot[XMN_PLT_BOXPLOT] )
302             {
303               if ( cmd.cmp == XMN_GROUPS )
304                 {
305                   box_plot_group (0, (const struct variable **) dependent_vars,
306                                   n_dependent_vars, cmd.v_id);
307                 }
308               else
309                 box_plot_variables (0,
310                                     (const struct variable **) dependent_vars,
311                                     n_dependent_vars, cmd.v_id);
312             }
313
314           if ( cmd.a_plot[XMN_PLT_HISTOGRAM] )
315             {
316               for ( v = 0 ; v < n_dependent_vars; ++v )
317                 {
318                   struct normal_curve normal;
319
320                   normal.N      = totals[v].n;
321                   normal.mean   = totals[v].mean;
322                   normal.stddev = totals[v].stddev;
323
324                   histogram_plot (totals[v].histogram,
325                                  var_to_string (dependent_vars[v]),
326                                  &normal, 0);
327                 }
328             }
329
330         }
331
332     }
333
334
335   /* Show grouped statistics  as appropriate */
336   fctr = factors;
337   while ( fctr )
338     {
339       show_summary (dependent_vars, n_dependent_vars, fctr);
340
341       if ( cmd.sbc_statistics )
342         {
343           if ( cmd.a_statistics[XMN_ST_EXTREME])
344             show_extremes (dependent_vars, n_dependent_vars, fctr, cmd.st_n);
345
346           if ( cmd.a_statistics[XMN_ST_DESCRIPTIVES])
347             show_descriptives (dependent_vars, n_dependent_vars, fctr);
348         }
349
350       if ( sbc_percentile )
351         show_percentiles (dependent_vars, n_dependent_vars, fctr);
352
353
354       if ( cmd.sbc_plot)
355         {
356           size_t v;
357
358           struct factor_statistics **fs = fctr->fs ;
359
360           if ( cmd.a_plot[XMN_PLT_BOXPLOT] )
361             {
362               if ( cmd.cmp == XMN_VARIABLES )
363                 box_plot_variables (fctr,
364                                     (const struct variable **) dependent_vars,
365                                     n_dependent_vars, cmd.v_id);
366               else
367                 box_plot_group (fctr,
368                                 (const struct variable **) dependent_vars,
369                                 n_dependent_vars, cmd.v_id);
370             }
371
372           for ( v = 0 ; v < n_dependent_vars; ++v )
373             {
374
375               for ( fs = fctr->fs ; *fs ; ++fs )
376                 {
377                   const char *s = factor_to_string (fctr, *fs, dependent_vars[v]);
378
379                   if ( cmd.a_plot[XMN_PLT_NPPLOT] )
380                     np_plot (& (*fs)->m[v], s);
381
382                   if ( cmd.a_plot[XMN_PLT_HISTOGRAM] )
383                     {
384                       struct normal_curve normal;
385
386                       normal.N      = (*fs)->m[v].n;
387                       normal.mean   = (*fs)->m[v].mean;
388                       normal.stddev = (*fs)->m[v].stddev;
389
390                       histogram_plot ((*fs)->m[v].histogram,
391                                      s,  &normal, 0);
392                     }
393
394                 } /* for ( fs .... */
395
396             } /* for ( v = 0 ..... */
397
398         }
399
400       fctr = fctr->next;
401     }
402
403 }
404
405
406 /* Create a hash table of percentiles and their values from the list of
407    percentiles */
408 static struct hsh_table *
409 list_to_ptile_hash (const subc_list_double *l)
410 {
411   int i;
412
413   struct hsh_table *h ;
414
415   h = hsh_create (subc_list_double_count (l),
416                  (hsh_compare_func *) ptile_compare,
417                  (hsh_hash_func *) ptile_hash,
418                  (hsh_free_func *) free,
419                  0);
420
421
422   for ( i = 0 ; i < subc_list_double_count (l) ; ++i )
423     {
424       struct percentile *p = xmalloc (sizeof *p);
425
426       p->p = subc_list_double_at (l,i);
427       p->v = SYSMIS;
428
429       hsh_insert (h, p);
430
431     }
432
433   return h;
434
435 }
436
437 /* Parse the PERCENTILES subcommand */
438 static int
439 xmn_custom_percentiles (struct lexer *lexer, struct dataset *ds UNUSED,
440                        struct cmd_examine *p UNUSED, void *aux UNUSED)
441 {
442   sbc_percentile = 1;
443
444   lex_match (lexer, '=');
445
446   lex_match (lexer, '(');
447
448   while ( lex_is_number (lexer) )
449     {
450       subc_list_double_push (&percentile_list, lex_number (lexer));
451
452       lex_get (lexer);
453
454       lex_match (lexer, ',') ;
455     }
456   lex_match (lexer, ')');
457
458   lex_match (lexer, '=');
459
460   if ( lex_match_id (lexer, "HAVERAGE"))
461     percentile_algorithm = PC_HAVERAGE;
462
463   else if ( lex_match_id (lexer, "WAVERAGE"))
464     percentile_algorithm = PC_WAVERAGE;
465
466   else if ( lex_match_id (lexer, "ROUND"))
467     percentile_algorithm = PC_ROUND;
468
469   else if ( lex_match_id (lexer, "EMPIRICAL"))
470     percentile_algorithm = PC_EMPIRICAL;
471
472   else if ( lex_match_id (lexer, "AEMPIRICAL"))
473     percentile_algorithm = PC_AEMPIRICAL;
474
475   else if ( lex_match_id (lexer, "NONE"))
476     percentile_algorithm = PC_NONE;
477
478
479   if ( 0 == subc_list_double_count (&percentile_list))
480     {
481       subc_list_double_push (&percentile_list, 5);
482       subc_list_double_push (&percentile_list, 10);
483       subc_list_double_push (&percentile_list, 25);
484       subc_list_double_push (&percentile_list, 50);
485       subc_list_double_push (&percentile_list, 75);
486       subc_list_double_push (&percentile_list, 90);
487       subc_list_double_push (&percentile_list, 95);
488     }
489
490   return 1;
491 }
492
493 /* TOTAL and NOTOTAL are simple, mutually exclusive flags */
494 static int
495 xmn_custom_total (struct lexer *lexer UNUSED, struct dataset *ds UNUSED, struct cmd_examine *p, void *aux UNUSED)
496 {
497   if ( p->sbc_nototal )
498     {
499       msg (SE, _ ("%s and %s are mutually exclusive"),"TOTAL","NOTOTAL");
500       return 0;
501     }
502
503   return 1;
504 }
505
506 static int
507 xmn_custom_nototal (struct lexer *lexer UNUSED, struct dataset *ds UNUSED,
508                     struct cmd_examine *p, void *aux UNUSED)
509 {
510   if ( p->sbc_total )
511     {
512       msg (SE, _ ("%s and %s are mutually exclusive"),"TOTAL","NOTOTAL");
513       return 0;
514     }
515
516   return 1;
517 }
518
519
520
521 /* Parser for the variables sub command
522    Returns 1 on success */
523 static int
524 xmn_custom_variables (struct lexer *lexer, struct dataset *ds, struct cmd_examine *cmd, void *aux UNUSED)
525 {
526   const struct dictionary *dict = dataset_dict (ds);
527   lex_match (lexer, '=');
528
529   if ( (lex_token (lexer) != T_ID || dict_lookup_var (dict, lex_tokid (lexer)) == NULL)
530       && lex_token (lexer) != T_ALL)
531     {
532       return 2;
533     }
534
535   if (!parse_variables_const (lexer, dict, &dependent_vars, &n_dependent_vars,
536                         PV_NO_DUPLICATE | PV_NUMERIC | PV_NO_SCRATCH) )
537     {
538       free (dependent_vars);
539       return 0;
540     }
541
542   assert (n_dependent_vars);
543
544   totals = xnmalloc (n_dependent_vars, sizeof *totals);
545
546   if ( lex_match (lexer, T_BY))
547     {
548       int success ;
549       success =  examine_parse_independent_vars (lexer, dict, cmd);
550       if ( success != 1 ) {
551         free (dependent_vars);
552         free (totals) ;
553       }
554       return success;
555     }
556
557   return 1;
558 }
559
560
561
562 /* Parse the clause specifying the factors */
563 static int
564 examine_parse_independent_vars (struct lexer *lexer, const struct dictionary *dict, struct cmd_examine *cmd)
565 {
566   int success;
567   struct factor *sf = xmalloc (sizeof *sf);
568
569   if ( (lex_token (lexer) != T_ID || dict_lookup_var (dict, lex_tokid (lexer)) == NULL)
570       && lex_token (lexer) != T_ALL)
571     {
572       free ( sf ) ;
573       return 2;
574     }
575
576
577   sf->indep_var[0] = parse_variable (lexer, dict);
578   sf->indep_var[1] = 0;
579
580   if ( lex_token (lexer) == T_BY )
581     {
582
583       lex_match (lexer, T_BY);
584
585       if ( (lex_token (lexer) != T_ID || dict_lookup_var (dict, lex_tokid (lexer)) == NULL)
586           && lex_token (lexer) != T_ALL)
587         {
588           free ( sf ) ;
589           return 2;
590         }
591
592       sf->indep_var[1] = parse_variable (lexer, dict);
593
594     }
595
596
597   sf->fstats = hsh_create (4,
598                           (hsh_compare_func *) factor_statistics_compare,
599                           (hsh_hash_func *) factor_statistics_hash,
600                           (hsh_free_func *) factor_statistics_free,
601                           0);
602
603   sf->next = factors;
604   factors = sf;
605
606   lex_match (lexer, ',');
607
608   if ( lex_token (lexer) == '.' || lex_token (lexer) == '/' )
609     return 1;
610
611   success =  examine_parse_independent_vars (lexer, dict, cmd);
612
613   if ( success != 1 )
614     free ( sf ) ;
615
616   return success;
617 }
618
619
620
621
622 void populate_percentiles (struct tab_table *tbl, int col, int row,
623                           const struct metrics *m);
624
625 void populate_descriptives (struct tab_table *t, int col, int row,
626                            const struct metrics *fs);
627
628 void populate_extremes (struct tab_table *t, int col, int row, int n,
629                        const struct metrics *m);
630
631 void populate_summary (struct tab_table *t, int col, int row,
632                       const struct metrics *m);
633
634
635
636
637 /* Perform calculations for the sub factors */
638 void
639 factor_calc (const struct ccase *c, int case_no, double weight,
640              int case_missing)
641 {
642   size_t v;
643   struct factor *fctr = factors;
644
645   while ( fctr)
646     {
647       struct factor_statistics **foo ;
648       union value *indep_vals[2] ;
649
650       indep_vals[0] = value_dup (
651                                  case_data (c, fctr->indep_var[0]),
652                                  var_get_width (fctr->indep_var[0])
653                                  );
654
655       if ( fctr->indep_var[1] )
656         indep_vals[1] = value_dup (
657                                    case_data (c, fctr->indep_var[1]),
658                                    var_get_width (fctr->indep_var[1])
659                                    );
660       else
661         {
662           const union value sm = {SYSMIS};
663           indep_vals[1] = value_dup (&sm, 0);
664         }
665
666       assert (fctr->fstats);
667
668       foo = ( struct factor_statistics ** )
669         hsh_probe (fctr->fstats, (void *) &indep_vals);
670
671       if ( !*foo )
672         {
673
674           *foo = create_factor_statistics (n_dependent_vars,
675                                           indep_vals[0],
676                                           indep_vals[1]);
677
678           for ( v =  0 ; v  < n_dependent_vars ; ++v )
679             {
680               metrics_precalc ( & (*foo)->m[v] );
681             }
682
683         }
684       else
685         {
686           free (indep_vals[0]);
687           free (indep_vals[1]);
688         }
689
690       for ( v =  0 ; v  < n_dependent_vars ; ++v )
691         {
692           const struct variable *var = dependent_vars[v];
693           union value *val = value_dup (
694                                         case_data (c, var),
695                                         var_get_width (var)
696                                         );
697
698           if (case_missing || var_is_value_missing (var, val, exclude_values))
699             {
700               free (val);
701               continue;
702             }
703
704           metrics_calc ( & (*foo)->m[v], val, weight, case_no);
705
706           free (val);
707         }
708
709       fctr = fctr->next;
710     }
711 }
712
713 static void
714 run_examine (struct cmd_examine *cmd, struct casereader *input,
715              struct dataset *ds)
716 {
717   struct dictionary *dict = dataset_dict (ds);
718   casenumber case_no;
719   struct ccase c;
720   int v;
721   bool ok;
722
723   struct factor *fctr;
724
725   if (!casereader_peek (input, 0, &c))
726     return;
727   output_split_file_values (ds, &c);
728   case_destroy (&c);
729
730   input = casereader_create_filter_weight (input, dict, NULL, NULL);
731   input = casereader_create_counter (input, &case_no, 0);
732
733   /* Make sure we haven't got rubbish left over from a
734      previous split. */
735   fctr = factors;
736   while (fctr)
737     {
738       struct factor *next = fctr->next;
739
740       hsh_clear (fctr->fstats);
741
742       fctr->fs = 0;
743
744       fctr = next;
745     }
746
747   for ( v = 0 ; v < n_dependent_vars ; ++v )
748     metrics_precalc (&totals[v]);
749
750   for (; casereader_read (input, &c); case_destroy (&c))
751     {
752       int case_missing = 0;
753       const double weight = dict_get_case_weight (dict, &c, NULL);
754
755       if ( cmd->miss == XMN_LISTWISE )
756         {
757           for ( v = 0 ; v < n_dependent_vars ; ++v )
758             {
759               const struct variable *var = dependent_vars[v];
760               union value *val = value_dup (
761                                                   case_data (&c, var),
762                                                   var_get_width (var)
763                                                   );
764
765               if ( var_is_value_missing (var, val, exclude_values))
766                 case_missing = 1;
767
768               free (val);
769             }
770         }
771
772       for ( v = 0 ; v < n_dependent_vars ; ++v )
773         {
774           const struct variable *var = dependent_vars[v];
775           union value *val = value_dup (
776                                         case_data (&c, var),
777                                         var_get_width (var)
778                                         );
779
780           if ( var_is_value_missing (var, val, exclude_values)
781                || 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   ok = casereader_destroy (input);
795
796   for ( v = 0 ; v < n_dependent_vars ; ++v)
797     {
798       fctr = factors;
799       while ( fctr )
800         {
801           struct hsh_iterator hi;
802           struct factor_statistics *fs;
803
804           for ( fs = hsh_first (fctr->fstats, &hi);
805                 fs != 0 ;
806                 fs = hsh_next (fctr->fstats, &hi))
807             {
808
809               fs->m[v].ptile_hash = list_to_ptile_hash (&percentile_list);
810               fs->m[v].ptile_alg = percentile_algorithm;
811               metrics_postcalc (&fs->m[v]);
812             }
813
814           fctr = fctr->next;
815         }
816
817       totals[v].ptile_hash = list_to_ptile_hash (&percentile_list);
818       totals[v].ptile_alg = percentile_algorithm;
819       metrics_postcalc (&totals[v]);
820     }
821
822
823   /* Make sure that the combination of factors are complete */
824
825   fctr = factors;
826   while ( fctr )
827     {
828       struct hsh_iterator hi;
829       struct hsh_iterator hi0;
830       struct hsh_iterator hi1;
831       struct factor_statistics *fs;
832
833       struct hsh_table *idh0=0;
834       struct hsh_table *idh1=0;
835       union value *val0;
836       union value *val1;
837
838       idh0 = hsh_create (4, (hsh_compare_func *) compare_values,
839                          (hsh_hash_func *) hash_value,
840                         0,0);
841
842       idh1 = hsh_create (4, (hsh_compare_func *) compare_values,
843                          (hsh_hash_func *) hash_value,
844                         0,0);
845
846
847       for ( fs = hsh_first (fctr->fstats, &hi);
848             fs != 0 ;
849             fs = hsh_next (fctr->fstats, &hi))
850         {
851           hsh_insert (idh0, (void *) &fs->id[0]);
852           hsh_insert (idh1, (void *) &fs->id[1]);
853         }
854
855       /* Ensure that the factors combination is complete */
856       for ( val0 = hsh_first (idh0, &hi0);
857             val0 != 0 ;
858             val0 = hsh_next (idh0, &hi0))
859         {
860           for ( val1 = hsh_first (idh1, &hi1);
861                 val1 != 0 ;
862                 val1 = hsh_next (idh1, &hi1))
863             {
864               struct factor_statistics **ffs;
865               union value key[2];
866               key[0] = *val0;
867               key[1] = *val1;
868
869               ffs = (struct factor_statistics **)
870                 hsh_probe (fctr->fstats, (void *) &key );
871
872               if ( !*ffs ) {
873                 size_t i;
874                  (*ffs) = create_factor_statistics (n_dependent_vars,
875                                                    &key[0], &key[1]);
876                 for ( i = 0 ; i < n_dependent_vars ; ++i )
877                   metrics_precalc ( & (*ffs)->m[i]);
878               }
879             }
880         }
881
882       hsh_destroy (idh0);
883       hsh_destroy (idh1);
884
885       fctr->fs = (struct factor_statistics **) hsh_sort_copy (fctr->fstats);
886
887       fctr = fctr->next;
888     }
889
890   if (ok)
891     output_examine ();
892
893
894   if ( totals )
895     {
896       size_t i;
897       for ( i = 0 ; i < n_dependent_vars ; ++i )
898         {
899           metrics_destroy (&totals[i]);
900         }
901     }
902 }
903
904
905 static void
906 show_summary (const 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 (const 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 (const 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 /* Fill in the descriptives data */
1515 void
1516 populate_descriptives (struct tab_table *tbl, int col, int row,
1517                       const struct metrics *m)
1518 {
1519   const double t = gsl_cdf_tdist_Qinv ((1 - cmd.n_cinterval[0] / 100.0)/2.0,
1520                                       m->n -1);
1521
1522   tab_text (tbl, col,
1523             row,
1524             TAB_LEFT | TAT_TITLE,
1525             _ ("Mean"));
1526
1527   tab_float (tbl, col + 2,
1528              row,
1529              TAB_CENTER,
1530              m->mean,
1531              8,2);
1532
1533   tab_float (tbl, col + 3,
1534              row,
1535              TAB_CENTER,
1536              m->se_mean,
1537              8,3);
1538
1539
1540   tab_text (tbl, col,
1541             row + 1,
1542             TAB_LEFT | TAT_TITLE | TAT_PRINTF,
1543             _ ("%g%% Confidence Interval for Mean"), cmd.n_cinterval[0]);
1544
1545
1546   tab_text (tbl, col + 1,
1547             row  + 1,
1548             TAB_LEFT | TAT_TITLE,
1549             _ ("Lower Bound"));
1550
1551   tab_float (tbl, col + 2,
1552              row + 1,
1553              TAB_CENTER,
1554              m->mean - t * m->se_mean,
1555              8,3);
1556
1557   tab_text (tbl, col + 1,
1558             row + 2,
1559             TAB_LEFT | TAT_TITLE,
1560             _ ("Upper Bound"));
1561
1562
1563   tab_float (tbl, col + 2,
1564              row + 2,
1565              TAB_CENTER,
1566              m->mean + t * m->se_mean,
1567              8,3);
1568
1569   tab_text (tbl, col,
1570             row + 3,
1571             TAB_LEFT | TAT_TITLE | TAT_PRINTF,
1572             _ ("5%% Trimmed Mean"));
1573
1574   tab_float (tbl, col + 2,
1575              row + 3,
1576              TAB_CENTER,
1577              m->trimmed_mean,
1578              8,2);
1579
1580   tab_text (tbl, col,
1581             row + 4,
1582             TAB_LEFT | TAT_TITLE,
1583             _ ("Median"));
1584
1585   {
1586     struct percentile *p;
1587     double d = 50;
1588
1589     p = hsh_find (m->ptile_hash, &d);
1590
1591     assert (p);
1592
1593
1594     tab_float (tbl, col + 2,
1595                row + 4,
1596                TAB_CENTER,
1597                p->v,
1598                8, 2);
1599   }
1600
1601
1602   tab_text (tbl, col,
1603             row + 5,
1604             TAB_LEFT | TAT_TITLE,
1605             _ ("Variance"));
1606
1607   tab_float (tbl, col + 2,
1608              row + 5,
1609              TAB_CENTER,
1610              m->var,
1611              8,3);
1612
1613
1614   tab_text (tbl, col,
1615             row + 6,
1616             TAB_LEFT | TAT_TITLE,
1617             _ ("Std. Deviation"));
1618
1619
1620   tab_float (tbl, col + 2,
1621              row + 6,
1622              TAB_CENTER,
1623              m->stddev,
1624              8,3);
1625
1626
1627   tab_text (tbl, col,
1628             row + 7,
1629             TAB_LEFT | TAT_TITLE,
1630             _ ("Minimum"));
1631
1632   tab_float (tbl, col + 2,
1633              row + 7,
1634              TAB_CENTER,
1635              m->min,
1636              8,3);
1637
1638   tab_text (tbl, col,
1639             row + 8,
1640             TAB_LEFT | TAT_TITLE,
1641             _ ("Maximum"));
1642
1643   tab_float (tbl, col + 2,
1644              row + 8,
1645              TAB_CENTER,
1646              m->max,
1647              8,3);
1648
1649
1650   tab_text (tbl, col,
1651             row + 9,
1652             TAB_LEFT | TAT_TITLE,
1653             _ ("Range"));
1654
1655
1656   tab_float (tbl, col + 2,
1657              row + 9,
1658              TAB_CENTER,
1659              m->max - m->min,
1660              8,3);
1661
1662   tab_text (tbl, col,
1663             row + 10,
1664             TAB_LEFT | TAT_TITLE,
1665             _ ("Interquartile Range"));
1666
1667   {
1668     struct percentile *p1;
1669     struct percentile *p2;
1670
1671     double d = 75;
1672     p1 = hsh_find (m->ptile_hash, &d);
1673
1674     d = 25;
1675     p2 = hsh_find (m->ptile_hash, &d);
1676
1677     assert (p1);
1678     assert (p2);
1679
1680     tab_float (tbl, col + 2,
1681                row + 10,
1682                TAB_CENTER,
1683                p1->v - p2->v,
1684                8, 2);
1685   }
1686
1687
1688
1689   tab_text (tbl, col,
1690             row + 11,
1691             TAB_LEFT | TAT_TITLE,
1692             _ ("Skewness"));
1693
1694
1695   tab_float (tbl, col + 2,
1696              row + 11,
1697              TAB_CENTER,
1698              m->skewness,
1699              8,3);
1700
1701   /* stderr of skewness */
1702   tab_float (tbl, col + 3,
1703              row + 11,
1704              TAB_CENTER,
1705              calc_seskew (m->n),
1706              8,3);
1707
1708
1709   tab_text (tbl, col,
1710             row + 12,
1711             TAB_LEFT | TAT_TITLE,
1712             _ ("Kurtosis"));
1713
1714
1715   tab_float (tbl, col + 2,
1716              row + 12,
1717              TAB_CENTER,
1718              m->kurtosis,
1719              8,3);
1720
1721   /* stderr of kurtosis */
1722   tab_float (tbl, col + 3,
1723              row + 12,
1724              TAB_CENTER,
1725              calc_sekurt (m->n),
1726              8,3);
1727
1728
1729 }
1730
1731
1732
1733 void
1734 box_plot_variables (const struct factor *fctr,
1735                    const struct variable **vars, int n_vars,
1736                    const struct variable *id)
1737 {
1738
1739   int i;
1740   struct factor_statistics **fs ;
1741
1742   if ( ! fctr )
1743     {
1744       box_plot_group (fctr, vars, n_vars, id);
1745       return;
1746     }
1747
1748   for ( fs = fctr->fs ; *fs ; ++fs )
1749     {
1750       double y_min = DBL_MAX;
1751       double y_max = -DBL_MAX;
1752       struct chart *ch = chart_create ();
1753       const char *s = factor_to_string (fctr, *fs, 0 );
1754
1755       chart_write_title (ch, s);
1756
1757       for ( i = 0 ; i < n_vars ; ++i )
1758         {
1759           y_max = MAX (y_max, (*fs)->m[i].max);
1760           y_min = MIN (y_min, (*fs)->m[i].min);
1761         }
1762
1763       boxplot_draw_yscale (ch, y_max, y_min);
1764
1765       for ( i = 0 ; i < n_vars ; ++i )
1766         {
1767
1768           const double box_width = (ch->data_right - ch->data_left)
1769             / (n_vars * 2.0 ) ;
1770
1771           const double box_centre = ( i * 2 + 1) * box_width
1772             + ch->data_left;
1773
1774           boxplot_draw_boxplot (ch,
1775                                box_centre, box_width,
1776                                & (*fs)->m[i],
1777                                var_to_string (vars[i]));
1778
1779
1780         }
1781
1782       chart_submit (ch);
1783
1784     }
1785 }
1786
1787
1788
1789 /* Do a box plot, grouping all factors into one plot ;
1790    each dependent variable has its own plot.
1791 */
1792 void
1793 box_plot_group (const struct factor *fctr,
1794                const struct variable **vars,
1795                int n_vars,
1796                const struct variable *id UNUSED)
1797 {
1798
1799   int i;
1800
1801   for ( i = 0 ; i < n_vars ; ++i )
1802     {
1803       struct factor_statistics **fs ;
1804       struct chart *ch;
1805
1806       ch = chart_create ();
1807
1808       boxplot_draw_yscale (ch, totals[i].max, totals[i].min);
1809
1810       if ( fctr )
1811         {
1812           int n_factors = 0;
1813           int f=0;
1814           for ( fs = fctr->fs ; *fs ; ++fs )
1815             ++n_factors;
1816
1817           chart_write_title (ch, _ ("Boxplot of %s vs. %s"),
1818                             var_to_string (vars[i]), var_to_string (fctr->indep_var[0]) );
1819
1820           for ( fs = fctr->fs ; *fs ; ++fs )
1821             {
1822
1823               const char *s = factor_to_string_concise (fctr, *fs);
1824
1825               const double box_width = (ch->data_right - ch->data_left)
1826                 / (n_factors * 2.0 ) ;
1827
1828               const double box_centre = ( f++ * 2 + 1) * box_width
1829                 + ch->data_left;
1830
1831               boxplot_draw_boxplot (ch,
1832                                    box_centre, box_width,
1833                                    & (*fs)->m[i],
1834                                    s);
1835             }
1836         }
1837       else if ( ch )
1838         {
1839           const double box_width = (ch->data_right - ch->data_left) / 3.0;
1840           const double box_centre = (ch->data_right + ch->data_left) / 2.0;
1841
1842           chart_write_title (ch, _ ("Boxplot"));
1843
1844           boxplot_draw_boxplot (ch,
1845                                box_centre,    box_width,
1846                                &totals[i],
1847                                var_to_string (vars[i]) );
1848
1849         }
1850
1851       chart_submit (ch);
1852     }
1853 }
1854
1855
1856 /* Plot the normal and detrended normal plots for m
1857    Label the plots with factorname */
1858 void
1859 np_plot (const struct metrics *m, const char *factorname)
1860 {
1861   int i;
1862   double yfirst=0, ylast=0;
1863
1864   /* Normal Plot */
1865   struct chart *np_chart;
1866
1867   /* Detrended Normal Plot */
1868   struct chart *dnp_chart;
1869
1870   /* The slope and intercept of the ideal normal probability line */
1871   const double slope = 1.0 / m->stddev;
1872   const double intercept = - m->mean / m->stddev;
1873
1874   /* Cowardly refuse to plot an empty data set */
1875   if ( m->n_data == 0 )
1876     return ;
1877
1878   np_chart = chart_create ();
1879   dnp_chart = chart_create ();
1880
1881   if ( !np_chart || ! dnp_chart )
1882     return ;
1883
1884   chart_write_title (np_chart, _ ("Normal Q-Q Plot of %s"), factorname);
1885   chart_write_xlabel (np_chart, _ ("Observed Value"));
1886   chart_write_ylabel (np_chart, _ ("Expected Normal"));
1887
1888
1889   chart_write_title (dnp_chart, _ ("Detrended Normal Q-Q Plot of %s"),
1890                     factorname);
1891   chart_write_xlabel (dnp_chart, _ ("Observed Value"));
1892   chart_write_ylabel (dnp_chart, _ ("Dev from Normal"));
1893
1894   yfirst = gsl_cdf_ugaussian_Pinv (m->wvp[0]->rank / ( m->n + 1));
1895   ylast =  gsl_cdf_ugaussian_Pinv (m->wvp[m->n_data-1]->rank / ( m->n + 1));
1896
1897
1898   {
1899     /* Need to make sure that both the scatter plot and the ideal fit into the
1900        plot */
1901     double x_lower = MIN (m->min, (yfirst - intercept) / slope) ;
1902     double x_upper = MAX (m->max, (ylast  - intercept) / slope) ;
1903     double slack = (x_upper - x_lower)  * 0.05 ;
1904
1905     chart_write_xscale (np_chart, x_lower - slack, x_upper + slack, 5);
1906
1907     chart_write_xscale (dnp_chart, m->min, m->max, 5);
1908
1909   }
1910
1911   chart_write_yscale (np_chart, yfirst, ylast, 5);
1912
1913   {
1914     /* We have to cache the detrended data, beacause we need to
1915        find its limits before we can plot it */
1916     double *d_data = xnmalloc (m->n_data, sizeof *d_data);
1917     double d_max = -DBL_MAX;
1918     double d_min = DBL_MAX;
1919     for ( i = 0 ; i < m->n_data; ++i )
1920       {
1921         const double ns = gsl_cdf_ugaussian_Pinv (m->wvp[i]->rank / ( m->n + 1));
1922
1923         chart_datum (np_chart, 0, m->wvp[i]->v.f, ns);
1924
1925         d_data[i] = (m->wvp[i]->v.f - m->mean) / m->stddev  - ns;
1926
1927         if ( d_data[i] < d_min ) d_min = d_data[i];
1928         if ( d_data[i] > d_max ) d_max = d_data[i];
1929       }
1930     chart_write_yscale (dnp_chart, d_min, d_max, 5);
1931
1932     for ( i = 0 ; i < m->n_data; ++i )
1933       chart_datum (dnp_chart, 0, m->wvp[i]->v.f, d_data[i]);
1934
1935     free (d_data);
1936   }
1937
1938   chart_line (np_chart, slope, intercept, yfirst, ylast , CHART_DIM_Y);
1939   chart_line (dnp_chart, 0, 0, m->min, m->max , CHART_DIM_X);
1940
1941   chart_submit (np_chart);
1942   chart_submit (dnp_chart);
1943 }
1944
1945
1946
1947
1948 /* Show the percentiles */
1949 void
1950 show_percentiles (const struct variable **dependent_var,
1951                  int n_dep_var,
1952                  struct factor *fctr)
1953 {
1954   struct tab_table *tbl;
1955   int i;
1956
1957   int n_cols, n_rows;
1958   int n_factors;
1959
1960   struct hsh_table *ptiles ;
1961
1962   int n_heading_columns;
1963   const int n_heading_rows = 2;
1964   const int n_stat_rows = 2;
1965
1966   int n_ptiles ;
1967
1968   if ( fctr )
1969     {
1970       struct factor_statistics **fs = fctr->fs ;
1971       n_heading_columns = 3;
1972       n_factors = hsh_count (fctr->fstats);
1973
1974       ptiles = (*fs)->m[0].ptile_hash;
1975
1976       if ( fctr->indep_var[1] )
1977         n_heading_columns = 4;
1978     }
1979   else
1980     {
1981       n_factors = 1;
1982       n_heading_columns = 2;
1983
1984       ptiles = totals[0].ptile_hash;
1985     }
1986
1987   n_ptiles = hsh_count (ptiles);
1988
1989   n_rows = n_heading_rows + n_dep_var * n_stat_rows * n_factors;
1990
1991   n_cols = n_heading_columns + n_ptiles ;
1992
1993   tbl = tab_create (n_cols, n_rows, 0);
1994
1995   tab_headers (tbl, n_heading_columns + 1, 0, n_heading_rows, 0);
1996
1997   tab_dim (tbl, tab_natural_dimensions);
1998
1999   /* Outline the box and have no internal lines*/
2000   tab_box (tbl,
2001            TAL_2, TAL_2,
2002            -1, -1,
2003            0, 0,
2004            n_cols - 1, n_rows - 1);
2005
2006   tab_hline (tbl, TAL_2, 0, n_cols - 1, n_heading_rows );
2007
2008   tab_vline (tbl, TAL_2, n_heading_columns, 0, n_rows - 1);
2009
2010
2011   tab_title (tbl, _ ("Percentiles"));
2012
2013
2014   tab_hline (tbl, TAL_1, n_heading_columns, n_cols - 1, 1 );
2015
2016
2017   tab_box (tbl,
2018            -1, -1,
2019            -1, TAL_1,
2020            0, n_heading_rows,
2021            n_heading_columns - 1, n_rows - 1);
2022
2023
2024   tab_box (tbl,
2025            -1, -1,
2026            -1, TAL_1,
2027            n_heading_columns, n_heading_rows - 1,
2028            n_cols - 1, n_rows - 1);
2029
2030   tab_joint_text (tbl, n_heading_columns + 1, 0,
2031                  n_cols - 1 , 0,
2032                  TAB_CENTER | TAT_TITLE ,
2033                  _ ("Percentiles"));
2034
2035
2036   {
2037     /* Put in the percentile break points as headings */
2038
2039     struct percentile **p = (struct percentile **) hsh_sort (ptiles);
2040
2041     i = 0;
2042     while ( (*p)  )
2043       {
2044         tab_float (tbl, n_heading_columns + i++ , 1,
2045                   TAB_CENTER,
2046                   (*p)->p, 8, 0);
2047
2048         p++;
2049       }
2050
2051   }
2052
2053   for ( i = 0 ; i < n_dep_var ; ++i )
2054     {
2055       const int n_stat_rows = 2;
2056       const int row = n_heading_rows + i * n_stat_rows * n_factors ;
2057
2058       if ( i > 0 )
2059         tab_hline (tbl, TAL_1, 0, n_cols - 1, row );
2060
2061       tab_text (tbl, 0,
2062                 i * n_stat_rows * n_factors  + n_heading_rows,
2063                 TAB_LEFT | TAT_TITLE,
2064                 var_to_string (dependent_var[i])
2065                 );
2066
2067       if ( fctr  )
2068         {
2069           const union value *prev  = NULL ;
2070           struct factor_statistics **fs = fctr->fs;
2071           int count = 0;
2072
2073           tab_text (tbl, 1, n_heading_rows - 1,
2074                     TAB_CENTER | TAT_TITLE,
2075                     var_to_string (fctr->indep_var[0]));
2076
2077
2078           if ( fctr->indep_var[1])
2079             tab_text (tbl, 2, n_heading_rows - 1, TAB_CENTER | TAT_TITLE,
2080                       var_to_string (fctr->indep_var[1]));
2081
2082           while ( *fs )
2083             {
2084               const int row = n_heading_rows + n_stat_rows  *
2085                  ( ( i  * n_factors  ) +  count );
2086
2087
2088               if ( !prev || 0 != compare_values (prev, (*fs)->id[0],
2089                                         var_get_width (fctr->indep_var[0])))
2090                 {
2091
2092                   if ( count > 0 )
2093                     tab_hline (tbl, TAL_1, 1, n_cols - 1, row);
2094
2095                   tab_text (tbl,
2096                             1, row,
2097                             TAB_LEFT | TAT_TITLE,
2098                             var_get_value_name (fctr->indep_var[0],
2099                                                 (*fs)->id[0])
2100                             );
2101
2102
2103                 }
2104
2105               prev = (*fs)->id[0];
2106
2107               if (fctr->indep_var[1] && count > 0 )
2108                 tab_hline (tbl, TAL_1, 2, n_cols - 1, row);
2109
2110               if ( fctr->indep_var[1])
2111                 tab_text (tbl, 2, row,
2112                           TAB_LEFT | TAT_TITLE,
2113                           var_get_value_name (fctr->indep_var[1], (*fs)->id[1])
2114                           );
2115
2116
2117               populate_percentiles (tbl, n_heading_columns - 1,
2118                                    row, & (*fs)->m[i]);
2119
2120
2121               count++ ;
2122               fs++;
2123             }
2124
2125
2126         }
2127       else
2128         {
2129           populate_percentiles (tbl, n_heading_columns - 1,
2130                                i * n_stat_rows * n_factors  + n_heading_rows,
2131                                &totals[i]);
2132         }
2133
2134
2135     }
2136
2137
2138   tab_submit (tbl);
2139
2140
2141 }
2142
2143
2144
2145
2146 void
2147 populate_percentiles (struct tab_table *tbl, int col, int row,
2148                      const struct metrics *m)
2149 {
2150   int i;
2151
2152   struct percentile **p = (struct percentile **) hsh_sort (m->ptile_hash);
2153
2154   tab_text (tbl,
2155             col, row + 1,
2156             TAB_LEFT | TAT_TITLE,
2157             _ ("Tukey\'s Hinges")
2158             );
2159
2160   tab_text (tbl,
2161             col, row,
2162             TAB_LEFT | TAT_TITLE,
2163             ptile_alg_desc[m->ptile_alg]
2164             );
2165
2166
2167   i = 0;
2168   while ( (*p)  )
2169     {
2170       tab_float (tbl, col + i + 1 , row,
2171                 TAB_CENTER,
2172                  (*p)->v, 8, 2);
2173       if ( (*p)->p == 25 )
2174         tab_float (tbl, col + i + 1 , row + 1,
2175                   TAB_CENTER,
2176                   m->hinge[0], 8, 2);
2177
2178       if ( (*p)->p == 50 )
2179         tab_float (tbl, col + i + 1 , row + 1,
2180                   TAB_CENTER,
2181                   m->hinge[1], 8, 2);
2182
2183       if ( (*p)->p == 75 )
2184         tab_float (tbl, col + i + 1 , row + 1,
2185                   TAB_CENTER,
2186                   m->hinge[2], 8, 2);
2187
2188
2189       i++;
2190
2191       p++;
2192     }
2193
2194 }
2195
2196
2197
2198 const char *
2199 factor_to_string (const struct factor *fctr,
2200                   const struct factor_statistics *fs,
2201                   const struct variable *var)
2202 {
2203
2204   static char buf1[100];
2205   char buf2[100];
2206
2207   strcpy (buf1,"");
2208
2209   if (var)
2210     sprintf (buf1, "%s (",var_to_string (var) );
2211
2212
2213   snprintf (buf2, 100, "%s = %s",
2214            var_to_string (fctr->indep_var[0]),
2215            var_get_value_name (fctr->indep_var[0], fs->id[0]));
2216
2217   strcat (buf1, buf2);
2218
2219   if ( fctr->indep_var[1] )
2220     {
2221       sprintf (buf2, "; %s = %s)",
2222               var_to_string (fctr->indep_var[1]),
2223               var_get_value_name (fctr->indep_var[1], fs->id[1]));
2224       strcat (buf1, buf2);
2225     }
2226   else
2227     {
2228       if ( var )
2229         strcat (buf1, ")");
2230     }
2231
2232   return buf1;
2233 }
2234
2235
2236
2237 const char *
2238 factor_to_string_concise (const struct factor *fctr,
2239                          struct factor_statistics *fs)
2240
2241 {
2242
2243   static char buf[100];
2244
2245   char buf2[100];
2246
2247   snprintf (buf, 100, "%s",
2248             var_get_value_name (fctr->indep_var[0], fs->id[0]));
2249
2250   if ( fctr->indep_var[1] )
2251     {
2252       sprintf (buf2, ",%s)", var_get_value_name (fctr->indep_var[1],
2253                                                  fs->id[1]) );
2254       strcat (buf, buf2);
2255     }
2256
2257
2258   return buf;
2259 }