Added npplot and detrended np plots
[pspp] / src / examine.q
1 /* PSPP - EXAMINE data for normality . -*-c-*-
2
3 Copyright (C) 2004 Free Software Foundation, Inc.
4 Author: John Darrington 2004
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., 59 Temple Place - Suite 330, Boston, MA
19 02111-1307, USA. */
20
21 #include <config.h>
22 #include <gsl/gsl_cdf.h>
23 #include "error.h"
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <math.h>
27 #include "alloc.h"
28 #include "str.h"
29 #include "case.h"
30 #include "command.h"
31 #include "lexer.h"
32 #include "error.h"
33 #include "magic.h"
34 #include "misc.h"
35 #include "tab.h"
36 #include "som.h"
37 #include "value-labels.h"
38 #include "var.h"
39 #include "vfm.h"
40 #include "hash.h"
41 #include "casefile.h"
42 #include "factor_stats.h"
43 #include "chart.h"
44
45 /* (specification)
46    "EXAMINE" (xmn_):
47    *variables=custom;
48    +total=custom;
49    +nototal=custom;
50    +missing=miss:pairwise/!listwise,
51    rep:report/!noreport,
52    incl:include/!exclude;
53    +compare=cmp:variables/!groups;
54    +plot[plt_]=stemleaf,boxplot,npplot,:spreadlevel(*d:n),histogram,all,none;
55    +cinterval=double;
56    +statistics[st_]=descriptives,:extreme(*d:n),all,none.
57 */
58
59 /* (declarations) */
60
61 /* (functions) */
62
63
64
65 static struct cmd_examine cmd;
66
67 static struct variable **dependent_vars;
68
69 static int n_dependent_vars;
70
71 static struct hsh_table *hash_table_factors=0;
72
73
74
75
76 struct factor 
77 {
78   /* The independent variable for this factor */
79   struct variable *indep_var;
80
81   /* The  factor statistics for each value of the independent variable */
82   struct hsh_table *hash_table_val;
83
84   /* The subfactor (if any) */
85   struct factor *subfactor;
86
87 };
88
89
90
91
92 /* Parse the clause specifying the factors */
93 static int examine_parse_independent_vars(struct cmd_examine *cmd, 
94                                           struct hsh_table *hash_factors );
95
96
97
98
99 /* Functions to support hashes of factors */
100 int compare_factors(const struct factor *f1, const struct factor *f2, 
101                     void *aux);
102
103 unsigned hash_factor(const struct factor *f, void *aux);
104
105 void free_factor(struct factor *f, void *aux UNUSED);
106
107
108 /* Output functions */
109 static void show_summary(struct variable **dependent_var, int n_dep_var, 
110                          struct factor *f);
111
112 static void show_descriptives(struct variable **dependent_var, 
113                               int n_dep_var, 
114                               struct factor *factor);
115
116
117 static void show_extremes(struct variable **dependent_var, 
118                           int n_dep_var, 
119                           struct factor *factor,
120                           int n_extremities);
121
122
123 void np_plot(const struct metrics *m, const char *varname);
124
125
126
127 /* Per Split function */
128 static void run_examine(const struct casefile *cf, void *cmd_);
129
130 static void output_examine(void);
131
132
133 static struct factor_statistics *totals = 0;
134
135
136
137 int
138 cmd_examine(void)
139 {
140
141   if ( !parse_examine(&cmd) )
142     return CMD_FAILURE;
143   
144   if ( cmd.st_n == SYSMIS ) 
145     cmd.st_n = 5;
146
147   if ( ! cmd.sbc_cinterval) 
148     cmd.n_cinterval[0] = 95.0;
149
150
151   totals = xmalloc ( sizeof (struct factor_statistics *) );
152
153   totals->stats = xmalloc(sizeof ( struct metrics ) * n_dependent_vars);
154
155   multipass_procedure_with_splits (run_examine, &cmd);
156
157
158   hsh_destroy(hash_table_factors);
159
160   free(totals->stats);
161   free(totals);
162
163   return CMD_SUCCESS;
164 };
165
166
167 /* Show all the appropriate tables */
168 static void
169 output_examine(void)
170 {
171
172   /* Show totals if appropriate */
173   if ( ! cmd.sbc_nototal || 
174        ! hash_table_factors || 0 == hsh_count (hash_table_factors))
175     {
176       show_summary(dependent_vars, n_dependent_vars,0);
177
178       if ( cmd.sbc_statistics ) 
179         {
180           if ( cmd.a_statistics[XMN_ST_DESCRIPTIVES]) 
181             show_descriptives(dependent_vars, n_dependent_vars, 0);
182           
183           if ( cmd.a_statistics[XMN_ST_EXTREME]) 
184             show_extremes(dependent_vars, n_dependent_vars, 0, cmd.st_n);
185         }
186
187       if ( cmd.sbc_plot) 
188         {
189           if ( cmd.a_plot[XMN_PLT_NPPLOT] ) 
190             {
191               int v;
192
193               for ( v = 0 ; v < n_dependent_vars; ++v ) 
194                 {
195                   np_plot(&totals->stats[v], var_to_string(dependent_vars[v]));
196                 }
197
198             }
199         }
200
201     }
202
203
204   /* Show grouped statistics  if appropriate */
205   if ( hash_table_factors && 0 != hsh_count (hash_table_factors))
206     {
207       struct hsh_iterator hi;
208       struct factor *f;
209
210       for(f = hsh_first(hash_table_factors,&hi);
211           f != 0;
212           f = hsh_next(hash_table_factors,&hi)) 
213         {
214           show_summary(dependent_vars, n_dependent_vars,f);
215
216           if ( cmd.sbc_statistics )
217             {
218               if ( cmd.a_statistics[XMN_ST_DESCRIPTIVES])
219                 show_descriptives(dependent_vars, n_dependent_vars, f);
220               
221               if ( cmd.a_statistics[XMN_ST_EXTREME])
222                 show_extremes(dependent_vars, n_dependent_vars, f, cmd.st_n);
223             }
224
225
226           if ( cmd.sbc_plot) 
227             {
228               if ( cmd.a_plot[XMN_PLT_NPPLOT] ) 
229                 {
230                   struct hsh_iterator h2;
231                   struct factor_statistics *foo ;
232                   for (foo = hsh_first(f->hash_table_val,&h2);
233                        foo != 0 ; 
234                        foo  = hsh_next(f->hash_table_val,&h2))
235                     {
236                       int v;
237                       for ( v = 0 ; v < n_dependent_vars; ++ v)
238                         {
239                           char buf[100];
240                           sprintf(buf, "%s (%s = %s)",
241                                   var_to_string(dependent_vars[v]),
242                                   var_to_string(f->indep_var),
243                                   value_to_string(foo->id,f->indep_var));
244                           np_plot(&foo->stats[v], buf);
245                         }
246                     }
247                 }
248             }
249         }
250     }
251
252 }
253
254
255
256 /* TOTAL and NOTOTAL are simple, mutually exclusive flags */
257 static int
258 xmn_custom_total(struct cmd_examine *p)
259 {
260   if ( p->sbc_nototal ) 
261     {
262       msg (SE, _("%s and %s are mutually exclusive"),"TOTAL","NOTOTAL");
263       return 0;
264     }
265
266   return 1;
267 }
268
269 static int
270 xmn_custom_nototal(struct cmd_examine *p)
271 {
272   if ( p->sbc_total ) 
273     {
274       msg (SE, _("%s and %s are mutually exclusive"),"TOTAL","NOTOTAL");
275       return 0;
276     }
277
278   return 1;
279 }
280
281
282 /* Compare two factors */
283 int 
284 compare_factors (const struct factor *f1, 
285                  const struct factor *f2, 
286                  void *aux)
287 {
288   int indep_var_cmp = strcmp(f1->indep_var->name, f2->indep_var->name);
289
290   if ( 0 != indep_var_cmp ) 
291     return indep_var_cmp;
292
293   /* If the names are identical, and there are no subfactors then
294      the factors are identical */
295   if ( ! f1->subfactor &&  ! f2->subfactor ) 
296     return 0;
297     
298   /* ... otherwise we must compare the subfactors */
299
300   return compare_factors(f1->subfactor, f2->subfactor, aux);
301
302 }
303
304 /* Create a hash of a factor */
305 unsigned 
306 hash_factor( const struct factor *f, void *aux)
307 {
308   unsigned h;
309   h = hsh_hash_string(f->indep_var->name);
310   
311   if ( f->subfactor ) 
312     h += hash_factor(f->subfactor, aux);
313
314   return h;
315 }
316
317
318 /* Free up a factor */
319 void
320 free_factor(struct factor *f, void *aux)
321 {
322   hsh_destroy(f->hash_table_val);
323
324   if ( f->subfactor ) 
325     free_factor(f->subfactor, aux);
326
327   free(f);
328 }
329
330
331 /* Parser for the variables sub command */
332 static int
333 xmn_custom_variables(struct cmd_examine *cmd )
334 {
335
336   lex_match('=');
337
338   if ((token != T_ID || dict_lookup_var (default_dict, tokid) == NULL)
339       && token != T_ALL)
340     return 2;
341   
342   if (!parse_variables (default_dict, &dependent_vars, &n_dependent_vars,
343                         PV_NO_DUPLICATE | PV_NUMERIC | PV_NO_SCRATCH) )
344     {
345       free (dependent_vars);
346       return 0;
347     }
348
349   assert(n_dependent_vars);
350
351   if ( lex_match(T_BY))
352     {
353       hash_table_factors = hsh_create(4, 
354                                       (hsh_compare_func *) compare_factors, 
355                                       (hsh_hash_func *) hash_factor, 
356                                       (hsh_free_func *) free_factor, 0);
357
358       return examine_parse_independent_vars(cmd, hash_table_factors);
359     }
360
361   
362   
363   return 1;
364 }
365
366
367 /* Parse the clause specifying the factors */
368 static int
369 examine_parse_independent_vars(struct cmd_examine *cmd, 
370                                struct hsh_table *hash_table_factors )
371 {
372   struct factor *f = 0;
373
374   if ((token != T_ID || dict_lookup_var (default_dict, tokid) == NULL)
375       && token != T_ALL)
376     return 2;
377
378   if ( !f ) 
379     {
380       f = xmalloc(sizeof(struct factor));
381       f->indep_var = 0;
382       f->hash_table_val = 0;
383       f->subfactor = 0;
384     }
385   
386   f->indep_var = parse_variable();
387   
388   if ( ! f->hash_table_val ) 
389     f->hash_table_val = hsh_create(4,(hsh_compare_func *) compare_indep_values,
390                                    (hsh_hash_func *) hash_indep_value,
391                                    (hsh_free_func *) free_factor_stats,
392                                    (void *) f->indep_var->width);
393
394   if ( token == T_BY ) 
395     {
396       lex_match(T_BY);
397
398       if ((token != T_ID || dict_lookup_var (default_dict, tokid) == NULL)
399           && token != T_ALL)
400         return 2;
401
402       f->subfactor = xmalloc(sizeof(struct factor));
403
404       f->subfactor->indep_var = parse_variable();
405       
406       f->subfactor->subfactor = 0;
407
408       f->subfactor->hash_table_val = 
409         hsh_create(4,
410                    (hsh_compare_func *) compare_indep_values,
411                    (hsh_hash_func *) hash_indep_value,
412                    (hsh_free_func *) free_factor_stats,
413                    (void *) f->subfactor->indep_var->width);
414     }
415
416   hsh_insert(hash_table_factors, f);
417   
418   lex_match(',');
419
420   if ( token == '.' || token == '/' ) 
421     return 1;
422
423   return examine_parse_independent_vars(cmd, hash_table_factors);
424 }
425
426
427 void populate_descriptives(struct tab_table *t, int col, int row, 
428                            const struct metrics *fs);
429
430
431 void populate_extremities(struct tab_table *t, int col, int row, int n);
432
433
434 /* Show the descriptives table */
435 void
436 show_descriptives(struct variable **dependent_var, 
437                   int n_dep_var, 
438                   struct factor *factor)
439 {
440   int i;
441   int heading_columns ;
442   int n_cols;
443   const int n_stat_rows = 13;
444
445   const int heading_rows = 1;
446   int n_rows = heading_rows ;
447
448   struct tab_table *t;
449
450
451   if ( !factor ) 
452     {
453       heading_columns = 1;
454       n_rows += n_dep_var * n_stat_rows;
455     }
456   else
457     {
458       assert(factor->indep_var);
459       if ( factor->subfactor == 0 ) 
460         {
461           heading_columns = 2;
462           n_rows += n_dep_var * hsh_count(factor->hash_table_val) * n_stat_rows;
463         }
464       else
465         {
466           heading_columns = 3;
467           n_rows += n_dep_var * hsh_count(factor->hash_table_val) * 
468             hsh_count(factor->subfactor->hash_table_val) * n_stat_rows ;
469         }
470     }
471
472   n_cols = heading_columns + 4;
473
474   t = tab_create (n_cols, n_rows, 0);
475
476   tab_headers (t, heading_columns + 1, 0, heading_rows, 0);
477
478   tab_dim (t, tab_natural_dimensions);
479
480   /* Outline the box and have no internal lines*/
481   tab_box (t, 
482            TAL_2, TAL_2,
483            -1, -1,
484            0, 0,
485            n_cols - 1, n_rows - 1);
486
487   tab_hline (t, TAL_2, 0, n_cols - 1, heading_rows );
488
489   tab_vline (t, TAL_1, heading_columns, 0, n_rows - 1);
490   tab_vline (t, TAL_2, n_cols - 2, 0, n_rows - 1);
491   tab_vline (t, TAL_1, n_cols - 1, 0, n_rows - 1);
492
493   tab_text (t, n_cols - 2, 0, TAB_CENTER | TAT_TITLE, _("Statistic"));
494   tab_text (t, n_cols - 1, 0, TAB_CENTER | TAT_TITLE, _("Std. Error"));
495
496
497   for ( i = 0 ; i < n_dep_var ; ++i ) 
498     {
499       int row;
500       int n_subfactors = 1;
501       int n_factors = 1;
502         
503       if ( factor ) 
504         {
505           n_factors = hsh_count(factor->hash_table_val);
506           if (  factor->subfactor ) 
507             n_subfactors = hsh_count(factor->subfactor->hash_table_val);
508         }
509
510
511       row = heading_rows + i * n_stat_rows * n_factors * n_subfactors; 
512
513       if ( i > 0 )
514         tab_hline(t, TAL_1, 0, n_cols - 1, row );
515
516       if ( factor  )
517         {
518           struct hsh_iterator hi;
519           const struct factor_statistics *fs;
520           int count = 0;
521
522           tab_text (t, 1, heading_rows - 1, TAB_CENTER | TAT_TITLE, 
523                     var_to_string(factor->indep_var));
524
525
526
527           for (fs  = hsh_first(factor->hash_table_val, &hi);
528                fs != 0;
529                fs  = hsh_next(factor->hash_table_val,  &hi))
530             {
531               tab_text (t, 1, 
532                         row  + count * n_subfactors * n_stat_rows,
533                         TAB_RIGHT | TAT_TITLE, 
534                         value_to_string(fs->id, factor->indep_var)
535                         );
536
537               if ( count > 0 ) 
538                 tab_hline (t, TAL_1, 1, n_cols - 1,  
539                            row  + count * n_subfactors * n_stat_rows);
540
541               if ( factor->subfactor ) 
542                 {
543                   int count2=0;
544                   struct hsh_iterator h2;
545                   const struct factor_statistics *sub_fs;
546               
547                   tab_text (t, 2, heading_rows - 1, TAB_CENTER | TAT_TITLE, 
548                             var_to_string(factor->subfactor->indep_var));
549
550                   for ( sub_fs = hsh_first(factor->subfactor->hash_table_val, 
551                                            &h2);
552                         sub_fs != 0;
553                         sub_fs = hsh_next(factor->subfactor->hash_table_val, 
554                                           &h2))
555                     {
556                         
557                       tab_text(t, 2, 
558                                row
559                                + count * n_subfactors * n_stat_rows 
560                                + count2 * n_stat_rows,
561                                TAB_RIGHT | TAT_TITLE ,
562                                value_to_string(sub_fs->id, factor->subfactor->indep_var)
563                                );
564
565                       if ( count2 > 0 ) 
566                         tab_hline (t, TAL_1, 2, n_cols - 1,  
567                                    row
568                                    + count * n_subfactors * n_stat_rows 
569                                    + count2 * n_stat_rows);
570                                
571                       populate_descriptives(t, heading_columns,
572                                             row
573                                             + count * n_subfactors 
574                                             * n_stat_rows 
575                                             + count2 * n_stat_rows,
576                                             &sub_fs->stats[i]);
577                                             
578                         
579                       count2++;
580                     }
581                 }
582               else
583                 {
584                   
585                   populate_descriptives(t, heading_columns, 
586                                         row  
587                                         + count * n_subfactors * n_stat_rows, 
588                                         &fs->stats[i]);
589                 }
590
591               count ++;
592             }
593         }
594       else
595         {
596           populate_descriptives(t, heading_columns, 
597                                 row, &totals->stats[i]);
598         }
599
600       tab_text (t, 
601                 0, row,
602                 TAB_LEFT | TAT_TITLE, 
603                 var_to_string(dependent_var[i])
604                 );
605
606     }
607
608   tab_title (t, 0, _("Descriptives"));
609
610   tab_submit(t);
611
612 }
613
614
615
616 /* Fill in the descriptives data */
617 void
618 populate_descriptives(struct tab_table *tbl, int col, int row, 
619                       const struct metrics *m)
620 {
621
622   const double t = gsl_cdf_tdist_Qinv(1 - cmd.n_cinterval[0]/100.0/2.0, \
623                                        m->n -1);
624
625
626   tab_text (tbl, col, 
627             row,
628             TAB_LEFT | TAT_TITLE,
629             _("Mean"));
630
631   tab_float (tbl, col + 2,
632              row,
633              TAB_CENTER,
634              m->mean,
635              8,2);
636   
637   tab_float (tbl, col + 3,
638              row,
639              TAB_CENTER,
640              m->stderr,
641              8,3);
642   
643
644   tab_text (tbl, col, 
645             row + 1,
646             TAB_LEFT | TAT_TITLE | TAT_PRINTF,
647             _("%g%% Confidence Interval for Mean"), cmd.n_cinterval[0]);
648
649
650   tab_text (tbl, col + 1, 
651             row  + 1,
652             TAB_LEFT | TAT_TITLE,
653             _("Lower Bound"));
654
655   tab_float (tbl, col + 2,
656              row + 1,
657              TAB_CENTER,
658              m->mean - t * m->stderr, 
659              8,3);
660
661   tab_text (tbl, col + 1,  
662             row + 2,
663             TAB_LEFT | TAT_TITLE,
664             _("Upper Bound"));
665
666
667   tab_float (tbl, col + 2,
668              row + 2,
669              TAB_CENTER,
670              m->mean + t * m->stderr, 
671              8,3);
672
673   tab_text (tbl, col, 
674             row + 3,
675             TAB_LEFT | TAT_TITLE,
676             _("5% Trimmed Mean"));
677
678   tab_float (tbl, col + 2, 
679             row + 3,
680              TAB_CENTER,
681              m->trimmed_mean,
682              8,2);
683
684   tab_text (tbl, col, 
685             row + 4,
686             TAB_LEFT | TAT_TITLE,
687             _("Median"));
688
689   tab_text (tbl, col, 
690             row + 5,
691             TAB_LEFT | TAT_TITLE,
692             _("Variance"));
693
694   tab_float (tbl, col + 2,
695              row + 5,
696              TAB_CENTER,
697              m->var,
698              8,3);
699
700
701   tab_text (tbl, col, 
702             row + 6,
703             TAB_LEFT | TAT_TITLE,
704             _("Std. Deviation"));
705
706
707   tab_float (tbl, col + 2,
708              row + 6,
709              TAB_CENTER,
710              m->stddev,
711              8,3);
712
713   
714   tab_text (tbl, col, 
715             row + 7,
716             TAB_LEFT | TAT_TITLE,
717             _("Minimum"));
718
719   tab_float (tbl, col + 2,
720              row + 7,
721              TAB_CENTER,
722              m->min,
723              8,3);
724
725   tab_text (tbl, col, 
726             row + 8,
727             TAB_LEFT | TAT_TITLE,
728             _("Maximum"));
729
730   tab_float (tbl, col + 2,
731              row + 8,
732              TAB_CENTER,
733              m->max,
734              8,3);
735
736
737   tab_text (tbl, col, 
738             row + 9,
739             TAB_LEFT | TAT_TITLE,
740             _("Range"));
741
742
743   tab_float (tbl, col + 2,
744              row + 9,
745              TAB_CENTER,
746              m->max - m->min,
747              8,3);
748
749   tab_text (tbl, col, 
750             row + 10,
751             TAB_LEFT | TAT_TITLE,
752             _("Interquartile Range"));
753
754   tab_text (tbl, col, 
755             row + 11,
756             TAB_LEFT | TAT_TITLE,
757             _("Skewness"));
758
759   tab_text (tbl, col, 
760             row + 12,
761             TAB_LEFT | TAT_TITLE,
762             _("Kurtosis"));
763 }
764
765
766 void
767 show_summary(struct variable **dependent_var, 
768              int n_dep_var, 
769              struct factor *factor)
770 {
771   static const char *subtitle[]=
772     {
773       N_("Valid"),
774       N_("Missing"),
775       N_("Total")
776     };
777
778   int i;
779   int heading_columns ;
780   int n_cols;
781   const int heading_rows = 3;
782   struct tab_table *tbl;
783
784   int n_rows = heading_rows;
785
786   if ( !factor ) 
787     {
788       heading_columns = 1;
789       n_rows += n_dep_var;
790     }
791   else
792     {
793       assert(factor->indep_var);
794       if ( factor->subfactor == 0 ) 
795         {
796           heading_columns = 2;
797           n_rows += n_dep_var * hsh_count(factor->hash_table_val);
798         }
799       else
800         {
801           heading_columns = 3;
802           n_rows += n_dep_var * hsh_count(factor->hash_table_val) * 
803             hsh_count(factor->subfactor->hash_table_val) ;
804         }
805     }
806
807
808   n_cols = heading_columns + 6;
809
810   tbl = tab_create (n_cols,n_rows,0);
811   tab_headers (tbl, heading_columns, 0, heading_rows, 0);
812
813   tab_dim (tbl, tab_natural_dimensions);
814   
815   /* Outline the box and have vertical internal lines*/
816   tab_box (tbl, 
817            TAL_2, TAL_2,
818            -1, TAL_1,
819            0, 0,
820            n_cols - 1, n_rows - 1);
821
822   tab_hline (tbl, TAL_2, 0, n_cols - 1, heading_rows );
823   tab_hline (tbl, TAL_1, heading_columns, n_cols - 1, 1 );
824   tab_hline (tbl, TAL_1, 0, n_cols - 1, heading_rows -1 );
825
826   tab_vline (tbl, TAL_2, heading_columns, 0, n_rows - 1);
827
828
829   tab_title (tbl, 0, _("Case Processing Summary"));
830   
831
832   tab_joint_text(tbl, heading_columns, 0, 
833                  n_cols -1, 0,
834                  TAB_CENTER | TAT_TITLE,
835                  _("Cases"));
836
837   /* Remove lines ... */
838   tab_box (tbl, 
839            -1, -1,
840            TAL_0, TAL_0,
841            heading_columns, 0,
842            n_cols - 1, 0);
843
844   if ( factor ) 
845     {
846       tab_text (tbl, 1, heading_rows - 1, TAB_CENTER | TAT_TITLE, 
847                 var_to_string(factor->indep_var));
848
849       if ( factor->subfactor ) 
850         tab_text (tbl, 2, heading_rows - 1, TAB_CENTER | TAT_TITLE, 
851                   var_to_string(factor->subfactor->indep_var));
852     }
853
854   for ( i = 0 ; i < 3 ; ++i ) 
855     {
856       tab_text (tbl, heading_columns + i*2 , 2, TAB_CENTER | TAT_TITLE, _("N"));
857       tab_text (tbl, heading_columns + i*2 + 1, 2, TAB_CENTER | TAT_TITLE, 
858                 _("Percent"));
859
860       tab_joint_text(tbl, heading_columns + i*2 , 1,
861                      heading_columns + i*2 + 1, 1,
862                      TAB_CENTER | TAT_TITLE,
863                      subtitle[i]);
864
865       tab_box (tbl, -1, -1,
866                TAL_0, TAL_0,
867                heading_columns + i*2, 1,
868                heading_columns + i*2 + 1, 1);
869
870     }
871
872
873   for ( i = 0 ; i < n_dep_var ; ++i ) 
874     {
875       int n_subfactors = 1;
876       int n_factors = 1;
877         
878       if ( factor ) 
879         {
880           n_factors = hsh_count(factor->hash_table_val);
881           if (  factor->subfactor ) 
882             n_subfactors = hsh_count(factor->subfactor->hash_table_val);
883         }
884
885       tab_text (tbl, 
886                 0, i * n_factors * n_subfactors + heading_rows,
887                 TAB_LEFT | TAT_TITLE, 
888                 var_to_string(dependent_var[i])
889                 );
890
891       if ( factor  )
892         {
893           struct hsh_iterator hi;
894           const struct factor_statistics *fs;
895           int count = 0;
896
897           for (fs  = hsh_first(factor->hash_table_val, &hi);
898                fs != 0;
899                fs  = hsh_next(factor->hash_table_val,  &hi))
900             {
901               tab_text (tbl, 1, 
902                         i * n_factors * n_subfactors + heading_rows
903                         + count * n_subfactors,
904                         TAB_RIGHT | TAT_TITLE, 
905                         value_to_string(fs->id, factor->indep_var)
906                         );
907
908               if ( factor->subfactor ) 
909                 {
910                   int count2=0;
911                   struct hsh_iterator h2;
912                   const struct factor_statistics *sub_fs;
913                 
914                   for ( sub_fs = hsh_first(factor->subfactor->hash_table_val, 
915                                            &h2);
916                         sub_fs != 0;
917                         sub_fs = hsh_next(factor->subfactor->hash_table_val, 
918                                           &h2))
919                     {
920                         
921                       tab_text(tbl, 2, 
922                                i * n_factors * n_subfactors + heading_rows
923                                + count * n_subfactors + count2,
924                                TAB_RIGHT | TAT_TITLE ,
925                                value_to_string(sub_fs->id, factor->subfactor->indep_var)
926                                );
927                         
928                       count2++;
929                     }
930                 }
931               count ++;
932             }
933         }
934     }
935
936
937   tab_submit (tbl);
938   
939 }
940
941 static int bad_weight_warn = 1;
942
943
944 static void 
945 run_examine(const struct casefile *cf, void *cmd_)
946 {
947   struct hsh_iterator hi;
948   struct factor *fctr;
949
950   struct casereader *r;
951   struct ccase c;
952   int v;
953
954   const struct cmd_examine *cmd = (struct cmd_examine *) cmd_;
955
956   /* Make sure we haven't got rubbish left over from a 
957      previous split */
958   if ( hash_table_factors ) 
959     {
960       for ( fctr = hsh_first(hash_table_factors, &hi);
961             fctr != 0;
962             fctr = hsh_next (hash_table_factors, &hi) )
963         {
964           hsh_clear(fctr->hash_table_val);
965
966           while ( (fctr = fctr->subfactor) )
967             hsh_clear(fctr->hash_table_val);
968         }
969     }
970
971   for ( v = 0 ; v < n_dependent_vars ; ++v ) 
972     metrics_precalc(&totals->stats[v]);
973
974   for(r = casefile_get_reader (cf);
975       casereader_read (r, &c) ;
976       case_destroy (&c) ) 
977     {
978       const double weight = 
979         dict_get_case_weight(default_dict, &c, &bad_weight_warn);
980
981       for ( v = 0 ; v < n_dependent_vars ; ++v ) 
982         {
983           const struct variable *var = dependent_vars[v];
984           const union value *val = case_data (&c, var->fv);
985
986           metrics_calc(&totals->stats[v], val, weight);
987         }
988
989       if ( hash_table_factors ) 
990         {
991           for ( fctr = hsh_first(hash_table_factors, &hi);
992                 fctr != 0;
993                 fctr = hsh_next (hash_table_factors, &hi) )
994             {
995               const union value *indep_val = 
996                 case_data(&c, fctr->indep_var->fv);
997
998               struct factor_statistics **foo = ( struct factor_statistics ** ) 
999                 hsh_probe(fctr->hash_table_val, (void *) &indep_val);
1000
1001               if ( !*foo ) 
1002                 {
1003                   *foo = xmalloc ( sizeof ( struct factor_statistics));
1004                   (*foo)->id = indep_val;
1005                   (*foo)->stats = xmalloc ( sizeof ( struct metrics ) 
1006                                             * n_dependent_vars);
1007
1008                   for ( v =  0 ; v  < n_dependent_vars ; ++v ) 
1009                     metrics_precalc( &(*foo)->stats[v] );
1010
1011                   hsh_insert(fctr->hash_table_val, (void *) *foo);
1012                 }
1013
1014               for ( v =  0 ; v  < n_dependent_vars ; ++v ) 
1015                 {
1016                   const struct variable *var = dependent_vars[v];
1017                   const union value *val = case_data (&c, var->fv);
1018
1019                   metrics_calc( &(*foo)->stats[v], val, weight );
1020                 }
1021
1022               if ( fctr->subfactor  ) 
1023                 {
1024                   struct factor *sfctr  = fctr->subfactor;
1025
1026                   const union value *ii_val = 
1027                     case_data (&c, sfctr->indep_var->fv);
1028
1029                   struct factor_statistics **bar = 
1030                     (struct factor_statistics **)
1031                     hsh_probe(sfctr->hash_table_val, (void *) &ii_val);
1032
1033                   if ( !*bar ) 
1034                     {
1035                       *bar = xmalloc ( sizeof ( struct factor_statistics));
1036                       (*bar)->id = ii_val;
1037                       (*bar)->stats = xmalloc ( sizeof ( struct metrics ) 
1038                                                 * n_dependent_vars);
1039                   
1040                       for ( v =  0 ; v  < n_dependent_vars ; ++v ) 
1041                         metrics_precalc( &(*bar)->stats[v] );
1042
1043                       hsh_insert(sfctr->hash_table_val, 
1044                                  (void *) *bar);
1045                     }
1046
1047                   for ( v =  0 ; v  < n_dependent_vars ; ++v ) 
1048                     {
1049                       const struct variable *var = dependent_vars[v];
1050                       const union value *val = case_data (&c, var->fv);
1051
1052                       metrics_calc( &(*bar)->stats[v], val, weight );
1053                     }
1054                 }
1055             }
1056         }
1057
1058     }
1059
1060   for ( v = 0 ; v < n_dependent_vars ; ++v)
1061     {
1062       if ( hash_table_factors ) 
1063         {
1064         for ( fctr = hsh_first(hash_table_factors, &hi);
1065               fctr != 0;
1066               fctr = hsh_next (hash_table_factors, &hi) )
1067           {
1068             struct hsh_iterator h2;
1069             struct factor_statistics *fs;
1070
1071             for ( fs = hsh_first(fctr->hash_table_val,&h2);
1072                   fs != 0;
1073                   fs = hsh_next(fctr->hash_table_val,&h2))
1074               {
1075                 metrics_postcalc( &fs->stats[v] );
1076               }
1077
1078             if ( fctr->subfactor) 
1079               {
1080                 struct hsh_iterator hsf;
1081                 struct factor_statistics *fss;
1082
1083                 for ( fss = hsh_first(fctr->subfactor->hash_table_val,&hsf);
1084                       fss != 0;
1085                       fss = hsh_next(fctr->subfactor->hash_table_val,&hsf))
1086                   {
1087                     metrics_postcalc( &fss->stats[v] );
1088                   }
1089               }
1090           }
1091         }
1092
1093       metrics_postcalc(&totals->stats[v]);
1094     }
1095
1096   output_examine();
1097
1098 }
1099
1100
1101 static void 
1102 show_extremes(struct variable **dependent_var, 
1103               int n_dep_var, 
1104               struct factor *factor,
1105               int n_extremities)
1106 {
1107   int i;
1108   int heading_columns ;
1109   int n_cols;
1110   const int heading_rows = 1;
1111   struct tab_table *t;
1112
1113   int n_rows = heading_rows;
1114
1115   if ( !factor ) 
1116     {
1117       heading_columns = 1 + 1;
1118       n_rows += n_dep_var * 2 * n_extremities;
1119     }
1120   else
1121     {
1122       assert(factor->indep_var);
1123       if ( factor->subfactor == 0 ) 
1124         {
1125           heading_columns = 2 + 1;
1126           n_rows += n_dep_var * 2 * n_extremities 
1127             * hsh_count(factor->hash_table_val);
1128         }
1129       else
1130         {
1131           heading_columns = 3 + 1;
1132           n_rows += n_dep_var * 2 * n_extremities 
1133             * hsh_count(factor->hash_table_val)
1134             * hsh_count(factor->subfactor->hash_table_val) ;
1135         }
1136     }
1137
1138
1139   n_cols = heading_columns + 3;
1140
1141   t = tab_create (n_cols,n_rows,0);
1142   tab_headers (t, heading_columns, 0, heading_rows, 0);
1143
1144   tab_dim (t, tab_natural_dimensions);
1145   
1146   /* Outline the box and have vertical internal lines*/
1147   tab_box (t, 
1148            TAL_2, TAL_2,
1149            -1, TAL_1,
1150            0, 0,
1151            n_cols - 1, n_rows - 1);
1152
1153
1154
1155   tab_hline (t, TAL_2, 0, n_cols - 1, heading_rows );
1156
1157   tab_title (t, 0, _("Extreme Values"));
1158
1159
1160
1161
1162   /* Remove lines ... */
1163   tab_box (t, 
1164            -1, -1,
1165            TAL_0, TAL_0,
1166            heading_columns, 0,
1167            n_cols - 1, 0);
1168
1169   if ( factor ) 
1170     {
1171       tab_text (t, 1, heading_rows - 1, TAB_CENTER | TAT_TITLE, 
1172                 var_to_string(factor->indep_var));
1173
1174       if ( factor->subfactor ) 
1175         tab_text (t, 2, heading_rows - 1, TAB_CENTER | TAT_TITLE, 
1176                   var_to_string(factor->subfactor->indep_var));
1177     }
1178
1179   tab_text (t, n_cols - 1, 0, TAB_CENTER | TAT_TITLE, _("Value"));
1180   tab_text (t, n_cols - 2, 0, TAB_CENTER | TAT_TITLE, _("Case Number"));
1181
1182
1183   for ( i = 0 ; i < n_dep_var ; ++i ) 
1184     {
1185       int n_subfactors = 1;
1186       int n_factors = 1;
1187         
1188       if ( factor ) 
1189         {
1190           n_factors = hsh_count(factor->hash_table_val);
1191           if (  factor->subfactor ) 
1192             n_subfactors = hsh_count(factor->subfactor->hash_table_val);
1193         }
1194
1195       tab_text (t, 
1196                 0, i * 2 * n_extremities * n_factors * 
1197                 n_subfactors + heading_rows,
1198                 TAB_LEFT | TAT_TITLE, 
1199                 var_to_string(dependent_var[i])
1200                 );
1201
1202
1203       if ( i > 0 ) 
1204         tab_hline (t, 
1205                    TAL_1, 0, n_cols - 1,  
1206                    heading_rows + 2 * n_extremities * 
1207                    (i * n_factors * n_subfactors )
1208                    );
1209
1210       if ( factor  )
1211         {
1212           struct hsh_iterator hi;
1213           const struct factor_statistics *fs;
1214           int count = 0;
1215
1216           for ( fs  = hsh_first(factor->hash_table_val, &hi);
1217                 fs != 0;
1218                 fs  = hsh_next(factor->hash_table_val,  &hi))
1219             {
1220               tab_text (t, 1, heading_rows + 2 * n_extremities * 
1221                         (i * n_factors * n_subfactors 
1222                          + count * n_subfactors),
1223                         TAB_RIGHT | TAT_TITLE, 
1224                         value_to_string(fs->id, factor->indep_var)
1225                         );
1226
1227               if ( count > 0 ) 
1228                 tab_hline (t, TAL_1, 1, n_cols - 1,  
1229                            heading_rows + 2 * n_extremities *
1230                            (i * n_factors * n_subfactors 
1231                             + count * n_subfactors));
1232
1233
1234               if ( factor->subfactor ) 
1235                 {
1236                   struct hsh_iterator h2;
1237                   const struct factor_statistics *sub_fs;
1238                   int count2=0;
1239
1240                   for ( sub_fs = hsh_first(factor->subfactor->hash_table_val, 
1241                                            &h2);
1242                         sub_fs != 0;
1243                         sub_fs = hsh_next(factor->subfactor->hash_table_val, 
1244                                           &h2))
1245                     {
1246                         
1247                       tab_text(t, 2, heading_rows + 2 * n_extremities *
1248                                (i * n_factors * n_subfactors 
1249                                 + count * n_subfactors + count2 ),
1250                                TAB_RIGHT | TAT_TITLE ,
1251                                value_to_string(sub_fs->id, 
1252                                                factor->subfactor->indep_var)
1253                                );
1254
1255
1256                       if ( count2 > 0 ) 
1257                         tab_hline (t, TAL_1, 2, n_cols - 1,  
1258                                    heading_rows + 2 * n_extremities *
1259                                    (i * n_factors * n_subfactors 
1260                                     + count * n_subfactors + count2 ));
1261
1262                       populate_extremities(t,3, 
1263                                            heading_rows + 2 * n_extremities *
1264                                            (i * n_factors * n_subfactors 
1265                                             + count * n_subfactors + count2),
1266                                            n_extremities );
1267                                            
1268                       count2++;
1269                     }
1270                 }
1271               else
1272                 {
1273                   populate_extremities(t,2, 
1274                                        heading_rows + 2 * n_extremities *
1275                                        (i * n_factors * n_subfactors 
1276                                         + count * n_subfactors),
1277                                        n_extremities);
1278                 }
1279
1280               count ++;
1281             }
1282         }
1283       else
1284         {
1285           populate_extremities(t, 1, 
1286                                heading_rows + 2 * n_extremities *
1287                                (i * n_factors * n_subfactors ),
1288                                n_extremities);
1289
1290         }
1291     }
1292
1293   tab_submit (t);
1294 }
1295
1296
1297
1298 /* Fill in the extremities table */
1299 void 
1300 populate_extremities(struct tab_table *t, int col, int row, int n)
1301 {
1302   int i;
1303
1304   tab_text(t, col, row,
1305            TAB_RIGHT | TAT_TITLE ,
1306            _("Highest")
1307            );
1308
1309   tab_text(t, col, row + n ,
1310            TAB_RIGHT | TAT_TITLE ,
1311            _("Lowest")
1312            );
1313
1314   for (i = 0; i < n ; ++i ) 
1315     {
1316       tab_float(t, col + 1, row + i,
1317                 TAB_RIGHT,
1318                 i + 1, 8, 0);
1319
1320       tab_float(t, col + 1, row + i + n,
1321                 TAB_RIGHT,
1322                 i + 1, 8, 0);
1323     }
1324 }
1325
1326
1327
1328 /* Plot the normal and detrended normal plots for m
1329    Label the plots with factorname */
1330 void
1331 np_plot(const struct metrics *m, const char *factorname)
1332 {
1333   int i;
1334   double yfirst=0, ylast=0;
1335
1336   /* Normal Plot */
1337   struct chart np_chart;
1338
1339   /* Detrended Normal Plot */
1340   struct chart dnp_chart;
1341
1342   const struct weighted_value *wv = m->wv;
1343   const int n_data = hsh_count(m->ordered_data) ; 
1344
1345   /* The slope and intercept of the ideal normal probability line */
1346   const double slope = 1.0 / m->stddev;
1347   const double intercept = - m->mean / m->stddev;
1348
1349   chart_initialise(&np_chart);
1350   chart_write_title(&np_chart, _("Normal Q-Q Plot of %s"), factorname);
1351   chart_write_xlabel(&np_chart, _("Observed Value"));
1352   chart_write_ylabel(&np_chart, _("Expected Normal"));
1353
1354   chart_initialise(&dnp_chart);
1355   chart_write_title(&dnp_chart, _("Detrended Normal Q-Q Plot of %s"), 
1356                     factorname);
1357   chart_write_xlabel(&dnp_chart, _("Observed Value"));
1358   chart_write_ylabel(&dnp_chart, _("Dev from Normal"));
1359
1360   yfirst = gsl_cdf_ugaussian_Pinv (wv[0].rank / ( m->n + 1));
1361   ylast =  gsl_cdf_ugaussian_Pinv (wv[n_data-1].rank / ( m->n + 1));
1362
1363   {
1364     /* Need to make sure that both the scatter plot and the ideal fit into the
1365        plot */
1366     double x_lower = min(m->min, (yfirst - intercept) / slope) ;
1367     double x_upper = max(m->max, (ylast  - intercept) / slope) ;
1368     double slack = (x_upper - x_lower)  * 0.05 ;
1369
1370     chart_write_xscale(&np_chart, x_lower  - slack, x_upper + slack,
1371                        chart_rounded_tick((m->max - m->min) / 5.0));
1372
1373
1374     chart_write_xscale(&dnp_chart, m->min, m->max,
1375                        chart_rounded_tick((m->max - m->min) / 5.0));
1376
1377   }
1378
1379   chart_write_yscale(&np_chart, yfirst, ylast, 
1380                      chart_rounded_tick((ylast - yfirst)/5.0) );
1381
1382   {
1383   /* We have to cache the detrended data, beacause we need to 
1384      find its limits before we can plot it */
1385   double *d_data;
1386   d_data = xmalloc (n_data * sizeof(double));
1387   double d_max = -DBL_MAX;
1388   double d_min = DBL_MAX;
1389   for ( i = 0 ; i < n_data; ++i ) 
1390     {
1391       const double ns = gsl_cdf_ugaussian_Pinv (wv[i].rank / ( m->n + 1));
1392
1393       chart_datum(&np_chart, 0, wv[i].v.f, ns);
1394
1395       d_data[i] = (wv[i].v.f - m->mean) / m->stddev  - ns;
1396    
1397       if ( d_data[i] < d_min ) d_min = d_data[i];
1398       if ( d_data[i] > d_max ) d_max = d_data[i];
1399     }
1400
1401   chart_write_yscale(&dnp_chart, d_min, d_max, 
1402                      chart_rounded_tick((d_max - d_min) / 5.0));
1403
1404   for ( i = 0 ; i < n_data; ++i ) 
1405       chart_datum(&dnp_chart, 0, wv[i].v.f, d_data[i]);
1406
1407   free(d_data);
1408   }
1409
1410   chart_line(&np_chart, slope, intercept, yfirst, ylast , CHART_DIM_Y);
1411   chart_line(&dnp_chart, 0, 0, m->min, m->max , CHART_DIM_X);
1412
1413   chart_finalise(&np_chart);
1414   chart_finalise(&dnp_chart);
1415
1416 }