Fixed some bugs related to empty parentheses
[pspp] / src / language / stats / examine.c
index 489de0180645127c6c6f9bcaf8f5548ffeb91bc2..46863cad9724f3b7899ab637ec8f3100a06df548 100644 (file)
@@ -1,6 +1,6 @@
 /*
   PSPP - a program for statistical analysis.
-  Copyright (C) 2012 Free Software Foundation, Inc.
+  Copyright (C) 2012, 2013  Free Software Foundation, Inc.
   
   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -40,6 +40,7 @@
 #include "math/interaction.h"
 #include "math/box-whisker.h"
 #include "math/categoricals.h"
+#include "math/chart-geometry.h"
 #include "math/histogram.h"
 #include "math/moments.h"
 #include "math/np.h"
@@ -51,6 +52,7 @@
 
 #include "output/charts/boxplot.h"
 #include "output/charts/np-plot.h"
+#include "output/charts/spreadlevel-plot.h"
 #include "output/charts/plot-hist.h"
 
 #include "language/command.h"
 #define _(msgid) gettext (msgid)
 #define N_(msgid) msgid
 
+static void 
+append_value_name (const struct variable *var, const union value *val, struct string *str)
+{
+  var_append_value_name (var, val, str);
+  if ( var_is_value_missing (var, val, MV_ANY))
+    ds_put_cstr (str, _(" (missing)"));
+}
+
 enum bp_mode
   {
     BP_GROUPS,
@@ -94,7 +104,8 @@ struct examine
   size_t n_iacts;
   struct interaction **iacts;
 
-  enum mv_class exclude;
+  enum mv_class dep_excl;
+  enum mv_class fctr_excl;
 
   const struct dictionary *dict;
 
@@ -109,19 +120,19 @@ struct examine
 
   bool missing_pw;
 
-  /* Test options require that casenumbers are known */
-  bool casenumbers;
-
   /* The case index of the ID value (or -1) if not applicable */
   size_t id_idx;
+  int id_width;
 
   enum pc_alg pc_alg;
   double *ptiles;
   size_t n_percentiles;
   
   bool npplot;
-  bool histogram;
+  bool histogramplot;
   bool boxplot;
+  bool spreadlevelplot;
+  int sl_power;
 
   enum bp_mode boxplot_mode;
 
@@ -137,7 +148,7 @@ struct extremity
 
   /* Either the casenumber or the value of the variable specified
      by the /ID subcommand which corresponds to this extremity */
-  double identity;
+  union value identity;
 };
 
 struct exploratory_stats
@@ -293,13 +304,19 @@ show_boxplot_grouped (const struct examine *cmd, int iact_idx)
           ds_init_empty (&label);
           for (ivar_idx = 0; ivar_idx < iact->n_vars; ++ivar_idx)
             {
+              struct string l;
               const struct variable *ivar = iact->vars[ivar_idx];
               const union value *val = case_data (c, ivar);
-              
-              ds_put_cstr (&label, var_to_string (ivar));
-              ds_put_cstr (&label, " = ");
-              var_append_value_name (ivar, val, &label);
-              ds_put_cstr (&label, "; ");
+              ds_init_empty (&l);
+
+              append_value_name (ivar, val, &l);
+              ds_ltrim (&l, ss_cstr (" "));
+
+              ds_put_substring (&label, l.ss);
+              if (ivar_idx < iact->n_vars - 1)
+                ds_put_cstr (&label, "; ");
+
+              ds_destroy (&l);
             }
 
           boxplot_add_box (boxplot, es[v].box_whisker, ds_cstr (&label));
@@ -326,7 +343,7 @@ show_boxplot_variabled (const struct examine *cmd, int iact_idx)
       double y_max = -DBL_MAX;
 
       const struct ccase *c =
-            categoricals_get_case_by_category_real (cmd->cats,  iact_idx, grp);
+       categoricals_get_case_by_category_real (cmd->cats,  iact_idx, grp);
 
       struct string title;
       ds_init_empty (&title);
@@ -357,7 +374,7 @@ show_boxplot_variabled (const struct examine *cmd, int iact_idx)
               
               ds_put_cstr (&label, var_to_string (ivar));
               ds_put_cstr (&label, " = ");
-              var_append_value_name (ivar, val, &label);
+              append_value_name (ivar, val, &label);
               ds_put_cstr (&label, "; ");
             }
 
@@ -424,7 +441,7 @@ show_npplot (const struct examine *cmd, int iact_idx)
                   
                   ds_put_cstr (&label, var_to_string (ivar));
                   ds_put_cstr (&label, " = ");
-                  var_append_value_name (ivar, val, &label);
+                  append_value_name (ivar, val, &label);
                   ds_put_cstr (&label, "; ");
                   
                 }
@@ -456,6 +473,58 @@ show_npplot (const struct examine *cmd, int iact_idx)
     }
 }
 
+static void
+show_spreadlevel (const struct examine *cmd, int iact_idx)
+{
+  const struct interaction *iact = cmd->iacts[iact_idx];
+  const size_t n_cats =  categoricals_n_count (cmd->cats, iact_idx);
+
+  int v;
+
+  /* Spreadlevel when there are no levels is not useful */
+  if (iact->n_vars == 0)
+    return;
+
+  for (v = 0; v < cmd->n_dep_vars; ++v)
+    {
+      int grp;
+      struct chart_item *sl;
+
+      struct string label;
+      ds_init_cstr (&label, 
+                   var_to_string (cmd->dep_vars[v]));
+
+      if (iact->n_vars > 0)
+       {
+         ds_put_cstr (&label, " (");
+         interaction_to_string (iact, &label);
+         ds_put_cstr (&label, ")");
+       }
+      
+      sl = spreadlevel_plot_create (ds_cstr (&label), cmd->sl_power);
+
+      for (grp = 0; grp < n_cats; ++grp)
+        {
+          const struct exploratory_stats *es =
+            categoricals_get_user_data_by_category_real (cmd->cats, iact_idx, grp);
+
+         double median = percentile_calculate (es[v].quartiles[1], cmd->pc_alg);
+
+         double iqr = percentile_calculate (es[v].quartiles[2], cmd->pc_alg) -
+           percentile_calculate (es[v].quartiles[0], cmd->pc_alg);
+
+         spreadlevel_plot_add (sl, iqr, median);
+       }
+
+      if (sl == NULL)
+       msg (MW, _("Not creating spreadlevel chart for %s"), ds_cstr (&label));
+      else 
+       chart_item_submit (sl);
+
+      ds_destroy (&label);
+    }
+}
+
 
 static void
 show_histogram (const struct examine *cmd, int iact_idx)
@@ -480,6 +549,10 @@ show_histogram (const struct examine *cmd, int iact_idx)
             categoricals_get_user_data_by_category_real (cmd->cats, iact_idx, grp);
 
           struct string label;
+
+         if (es[v].histogram == NULL)
+           continue;
+
           ds_init_cstr (&label, 
                         var_to_string (cmd->dep_vars[v]));
 
@@ -493,7 +566,7 @@ show_histogram (const struct examine *cmd, int iact_idx)
                   
                   ds_put_cstr (&label, var_to_string (ivar));
                   ds_put_cstr (&label, " = ");
-                  var_append_value_name (ivar, val, &label);
+                  append_value_name (ivar, val, &label);
                   ds_put_cstr (&label, "; ");
                   
                 }
@@ -532,6 +605,7 @@ percentiles_report (const struct examine *cmd, int iact_idx)
   const int nc = heading_columns + cmd->n_percentiles;
 
   t = tab_create (nc, nr);
+
   tab_title (t, _("Percentiles"));
 
   tab_headers (t, heading_columns, 0, heading_rows, 0);
@@ -576,119 +650,119 @@ percentiles_report (const struct examine *cmd, int iact_idx)
 
   if (n_cats > 0)
     {
-    tab_vline (t, TAL_1, heading_columns - 1, heading_rows, nr - 1);
+      tab_vline (t, TAL_1, heading_columns - 1, heading_rows, nr - 1);
 
-  for (v = 0; v < cmd->n_dep_vars; ++v)
-    {
-      const union value **prev_vals = previous_value_alloc (iact);
+      for (v = 0; v < cmd->n_dep_vars; ++v)
+       {
+         const union value **prev_vals = previous_value_alloc (iact);
 
-      int ivar_idx;
-      if ( v > 0 )
-        tab_hline (t, TAL_1, 0, nc - 1, heading_rows + v * rows_per_var);
+         int ivar_idx;
+         if ( v > 0 )
+           tab_hline (t, TAL_1, 0, nc - 1, heading_rows + v * rows_per_var);
         
-      tab_text (t,
-                0, heading_rows + v * rows_per_var,
-                TAT_TITLE | TAB_LEFT,
-                var_to_string (cmd->dep_vars[v])
-                );
-
-      for (i = 0; i < n_cats; ++i)
-        {
-          const struct ccase *c =
-            categoricals_get_case_by_category_real (cmd->cats,
-                                                    iact_idx, i);
+         tab_text (t,
+                   0, heading_rows + v * rows_per_var,
+                   TAT_TITLE | TAB_LEFT,
+                   var_to_string (cmd->dep_vars[v])
+                   );
 
-          const struct exploratory_stats *ess =
-            categoricals_get_user_data_by_category_real (cmd->cats, iact_idx, i);
+         for (i = 0; i < n_cats; ++i)
+           {
+             const struct ccase *c =
+               categoricals_get_case_by_category_real (cmd->cats,
+                                                       iact_idx, i);
 
-          const struct exploratory_stats *es = ess + v;
+             const struct exploratory_stats *ess =
+               categoricals_get_user_data_by_category_real (cmd->cats, iact_idx, i);
 
-          int diff_idx = previous_value_record (iact, c, prev_vals);
+             const struct exploratory_stats *es = ess + v;
 
-          double hinges[3];
-          int p;
+             int diff_idx = previous_value_record (iact, c, prev_vals);
 
-          for (ivar_idx = 0; ivar_idx < iact->n_vars; ++ivar_idx)
-            {
-              const struct variable *ivar = iact->vars[ivar_idx];
-              const union value *val = case_data (c, ivar);
+             double hinges[3];
+             int p;
 
-              if (( diff_idx != -1 && diff_idx <= ivar_idx)
-                  || i == 0)
-                {              
-                  struct string str;
-                  ds_init_empty (&str);
-                  var_append_value_name (ivar, val, &str);
+             for (ivar_idx = 0; ivar_idx < iact->n_vars; ++ivar_idx)
+               {
+                 const struct variable *ivar = iact->vars[ivar_idx];
+                 const union value *val = case_data (c, ivar);
+
+                 if (( diff_idx != -1 && diff_idx <= ivar_idx)
+                     || i == 0)
+                   {              
+                     struct string str;
+                     ds_init_empty (&str);
+                     append_value_name (ivar, val, &str);
               
-                  tab_text (t,
-                            1 + ivar_idx,
-                            heading_rows + v * rows_per_var + i * rows_per_cat,
-                            TAT_TITLE | TAB_LEFT,
-                            ds_cstr (&str)
-                            );
+                     tab_text (t,
+                               1 + ivar_idx,
+                               heading_rows + v * rows_per_var + i * rows_per_cat,
+                               TAT_TITLE | TAB_LEFT,
+                               ds_cstr (&str)
+                               );
                   
-                  ds_destroy (&str);
-                }
-            }
+                     ds_destroy (&str);
+                   }
+               }
 
-          if ( diff_idx != -1 && diff_idx < iact->n_vars)
-            {
-              tab_hline (t, TAL_1, 1 + diff_idx, nc - 1,
-                         heading_rows + v * rows_per_var + i * rows_per_cat
-                         );
-            }
+             if ( diff_idx != -1 && diff_idx < iact->n_vars)
+               {
+                 tab_hline (t, TAL_1, 1 + diff_idx, nc - 1,
+                            heading_rows + v * rows_per_var + i * rows_per_cat
+                            );
+               }
 
-          tab_text (t, heading_columns - 1, 
-                    heading_rows + v * rows_per_var + i * rows_per_cat,
-                    TAT_TITLE | TAB_LEFT,
-                   gettext (ptile_alg_desc [cmd->pc_alg]));
+             tab_text (t, heading_columns - 1, 
+                       heading_rows + v * rows_per_var + i * rows_per_cat,
+                       TAT_TITLE | TAB_LEFT,
+                       gettext (ptile_alg_desc [cmd->pc_alg]));
 
-          tukey_hinges_calculate (es->hinges, hinges);
+             tukey_hinges_calculate (es->hinges, hinges);
 
-          for (p = 0; p < cmd->n_percentiles; ++p)
-            {
-              tab_double (t, heading_columns + p, 
-                          heading_rows + v * rows_per_var + i * rows_per_cat,
-                          0,
-                          percentile_calculate (es->percentiles[p], cmd->pc_alg),
-                          0);
+             for (p = 0; p < cmd->n_percentiles; ++p)
+               {
+                 tab_double (t, heading_columns + p, 
+                             heading_rows + v * rows_per_var + i * rows_per_cat,
+                             0,
+                             percentile_calculate (es->percentiles[p], cmd->pc_alg),
+                             NULL, RC_OTHER);
               
-              if (cmd->ptiles[p] == 25.0)
-                {
-                  tab_double (t, heading_columns + p, 
-                              heading_rows + v * rows_per_var + i * rows_per_cat + 1,
-                              0,
-                              hinges[0],
-                              0);
-                }
-              else if (cmd->ptiles[p] == 50.0)
-                {
-                  tab_double (t, heading_columns + p, 
-                              heading_rows + v * rows_per_var + i * rows_per_cat + 1,
-                              0,
-                              hinges[1],
-                              0);
-                }
-              else if (cmd->ptiles[p] == 75.0)
-                {
-                  tab_double (t, heading_columns + p, 
-                              heading_rows + v * rows_per_var + i * rows_per_cat + 1,
-                              0,
-                              hinges[2],
-                              0);
-                }
-            }
+                 if (cmd->ptiles[p] == 25.0)
+                   {
+                     tab_double (t, heading_columns + p, 
+                                 heading_rows + v * rows_per_var + i * rows_per_cat + 1,
+                                 0,
+                                 hinges[0],
+                                 NULL, RC_OTHER);
+                   }
+                 else if (cmd->ptiles[p] == 50.0)
+                   {
+                     tab_double (t, heading_columns + p, 
+                                 heading_rows + v * rows_per_var + i * rows_per_cat + 1,
+                                 0,
+                                 hinges[1],
+                                 NULL, RC_OTHER);
+                   }
+                 else if (cmd->ptiles[p] == 75.0)
+                   {
+                     tab_double (t, heading_columns + p, 
+                                 heading_rows + v * rows_per_var + i * rows_per_cat + 1,
+                                 0,
+                                 hinges[2],
+                                 NULL, RC_OTHER);
+                   }
+               }
 
 
-          tab_text (t, heading_columns - 1, 
-                    heading_rows + v * rows_per_var + i * rows_per_cat + 1,
-                    TAT_TITLE | TAB_LEFT,
-                    _("Tukey's Hinges"));
+             tab_text (t, heading_columns - 1, 
+                       heading_rows + v * rows_per_var + i * rows_per_cat + 1,
+                       TAT_TITLE | TAB_LEFT,
+                       _("Tukey's Hinges"));
           
-        }
+           }
 
-      free (prev_vals);
-    }
+         free (prev_vals);
+       }
     }
   tab_submit (t);
 }
@@ -711,6 +785,7 @@ descriptives_report (const struct examine *cmd, int iact_idx)
   const int nc = 2 + heading_columns;
 
   t = tab_create (nc, nr);
+
   tab_title (t, _("Descriptives"));
 
   tab_headers (t, heading_columns, 0, heading_rows, 0);
@@ -786,7 +861,7 @@ descriptives_report (const struct examine *cmd, int iact_idx)
                 {              
                   struct string str;
                   ds_init_empty (&str);
-                  var_append_value_name (ivar, val, &str);
+                  append_value_name (ivar, val, &str);
               
                   tab_text (t,
                             1 + ivar_idx,
@@ -816,12 +891,12 @@ descriptives_report (const struct examine *cmd, int iact_idx)
           tab_double (t,
                       1 + iact->n_vars + 2,
                       heading_rows + v * rows_per_var + i * rows_per_cat,
-                      0, m1, 0);
+                      0, m1, NULL, RC_OTHER);
 
           tab_double (t,
                       1 + iact->n_vars + 3,
                       heading_rows + v * rows_per_var + i * rows_per_cat,
-                      0, calc_semean (m2, m0), 0);
+                      0, calc_semean (m2, m0), NULL, RC_OTHER);
 
           tab_text_format (t,
                            1 + iact->n_vars,
@@ -841,7 +916,7 @@ descriptives_report (const struct examine *cmd, int iact_idx)
           tab_double (t,
                       1 + iact->n_vars + 2,
                       heading_rows + v * rows_per_var + i * rows_per_cat + 1,
-                      0, m1 - tval * calc_semean (m2, m0), 0);
+                      0, m1 - tval * calc_semean (m2, m0), NULL, RC_OTHER);
 
 
           tab_text (t,
@@ -854,7 +929,7 @@ descriptives_report (const struct examine *cmd, int iact_idx)
           tab_double (t,
                       1 + iact->n_vars + 2,
                       heading_rows + v * rows_per_var + i * rows_per_cat + 2,
-                      0, m1 + tval * calc_semean (m2, m0), 0);
+                      0, m1 + tval * calc_semean (m2, m0), NULL, RC_OTHER);
 
 
           tab_text (t,
@@ -869,7 +944,7 @@ descriptives_report (const struct examine *cmd, int iact_idx)
                       heading_rows + v * rows_per_var + i * rows_per_cat + 3,
                       0,
                       trimmed_mean_calculate (es->trimmed_mean),
-                      0);
+                      NULL, RC_OTHER);
 
           tab_text (t,
                     1 + iact->n_vars,
@@ -883,7 +958,7 @@ descriptives_report (const struct examine *cmd, int iact_idx)
                       heading_rows + v * rows_per_var + i * rows_per_cat + 4,
                       0,
                       percentile_calculate (es->quartiles[1], cmd->pc_alg),
-                      0);
+                      NULL, RC_OTHER);
 
 
           tab_text (t,
@@ -896,7 +971,7 @@ descriptives_report (const struct examine *cmd, int iact_idx)
           tab_double (t,
                       1 + iact->n_vars + 2,
                       heading_rows + v * rows_per_var + i * rows_per_cat + 5,
-                      0, m2, 0);
+                      0, m2, NULL, RC_OTHER);
 
           tab_text (t,
                     1 + iact->n_vars,
@@ -908,7 +983,7 @@ descriptives_report (const struct examine *cmd, int iact_idx)
           tab_double (t,
                       1 + iact->n_vars + 2,
                       heading_rows + v * rows_per_var + i * rows_per_cat + 6,
-                      0, sqrt (m2), 0);
+                      0, sqrt (m2), NULL, RC_OTHER);
 
           tab_text (t,
                     1 + iact->n_vars,
@@ -922,7 +997,7 @@ descriptives_report (const struct examine *cmd, int iact_idx)
                       heading_rows + v * rows_per_var + i * rows_per_cat + 7,
                       0, 
                       es->minima[0].val,
-                      0);
+                      NULL, RC_OTHER);
 
           tab_text (t,
                     1 + iact->n_vars,
@@ -936,7 +1011,7 @@ descriptives_report (const struct examine *cmd, int iact_idx)
                       heading_rows + v * rows_per_var + i * rows_per_cat + 8,
                       0, 
                       es->maxima[0].val,
-                      0);
+                      NULL, RC_OTHER);
 
           tab_text (t,
                     1 + iact->n_vars,
@@ -950,7 +1025,7 @@ descriptives_report (const struct examine *cmd, int iact_idx)
                       heading_rows + v * rows_per_var + i * rows_per_cat + 9,
                       0, 
                       es->maxima[0].val - es->minima[0].val,
-                      0);
+                      NULL, RC_OTHER);
 
           tab_text (t,
                     1 + iact->n_vars,
@@ -966,7 +1041,7 @@ descriptives_report (const struct examine *cmd, int iact_idx)
                       0,
                       percentile_calculate (es->quartiles[2], cmd->pc_alg) - 
                       percentile_calculate (es->quartiles[0], cmd->pc_alg),
-                      0);
+                      NULL, RC_OTHER);
 
 
 
@@ -981,12 +1056,12 @@ descriptives_report (const struct examine *cmd, int iact_idx)
           tab_double (t,
                       1 + iact->n_vars + 2,
                       heading_rows + v * rows_per_var + i * rows_per_cat + 11,
-                      0, m3, 0);
+                      0, m3, NULL, RC_OTHER);
 
           tab_double (t,
                       1 + iact->n_vars + 3,
                       heading_rows + v * rows_per_var + i * rows_per_cat + 11,
-                      0, calc_seskew (m0), 0);
+                      0, calc_seskew (m0), NULL, RC_OTHER);
 
           tab_text (t,
                     1 + iact->n_vars,
@@ -998,12 +1073,12 @@ descriptives_report (const struct examine *cmd, int iact_idx)
           tab_double (t,
                       1 + iact->n_vars + 2,
                       heading_rows + v * rows_per_var + i * rows_per_cat + 12,
-                      0, m4, 0);
+                      0, m4, NULL, RC_OTHER);
 
           tab_double (t,
                       1 + iact->n_vars + 3,
                       heading_rows + v * rows_per_var + i * rows_per_cat + 12,
-                      0, calc_sekurt (m0), 0);
+                      0, calc_sekurt (m0), NULL, RC_OTHER);
         }
 
       free (prev_val);
@@ -1030,6 +1105,7 @@ extremes_report (const struct examine *cmd, int iact_idx)
   const int nc = 2 + heading_columns;
 
   t = tab_create (nc, nr);
+
   tab_title (t, _("Extreme Values"));
 
   tab_headers (t, heading_columns, 0, heading_rows, 0);
@@ -1102,7 +1178,7 @@ extremes_report (const struct examine *cmd, int iact_idx)
                 {              
                   struct string str;
                   ds_init_empty (&str);
-                  var_append_value_name (ivar, val, &str);
+                  append_value_name (ivar, val, &str);
               
                   tab_text (t,
                             1 + ivar_idx,
@@ -1146,47 +1222,63 @@ extremes_report (const struct examine *cmd, int iact_idx)
                           heading_rows + v * rows_per_var + i * rows_per_cat + e,
                           TAB_RIGHT,
                           e + 1,
-                          &F_8_0);
+                          NULL, RC_INTEGER);
 
               /* The casenumber */
-              tab_double (t,
+              if (cmd->id_var)
+                tab_value (t,
+                           heading_columns,
+                           heading_rows + v * rows_per_var + i * rows_per_cat + e,
+                           TAB_RIGHT,
+                           &es->maxima[e].identity,
+                           cmd->id_var,
+                           NULL);
+              else 
+                tab_double (t,
                           heading_columns,
-                          heading_rows + v * rows_per_var + i * rows_per_cat + e,
-                          0,
-                          es->maxima[e].identity,
-                          &F_8_0);
-
+                            heading_rows + v * rows_per_var + i * rows_per_cat + e,
+                            TAB_RIGHT,
+                            es->maxima[e].identity.f,
+                            NULL, RC_INTEGER);
 
               tab_double (t,
-                          heading_columns + 1,
-                          heading_rows + v * rows_per_var + i * rows_per_cat + e,
-                          0,
-                          es->maxima[e].val,
-                          0);
-
-
+                         heading_columns + 1,
+                         heading_rows + v * rows_per_var + i * rows_per_cat + e,
+                         0,
+                         es->maxima[e].val,
+                         var_get_print_format (cmd->dep_vars[v]), RC_OTHER);
+                         
 
               tab_double (t,
                           heading_columns - 1,
                           heading_rows + v * rows_per_var + i * rows_per_cat + cmd->disp_extremes + e,
                           TAB_RIGHT,
                           e + 1,
-                          &F_8_0);
+                          NULL, RC_INTEGER);
 
               /* The casenumber */
-              tab_double (t,
-                          heading_columns,
-                          heading_rows + v * rows_per_var + i * rows_per_cat + cmd->disp_extremes + e,
-                          0,
-                          es->minima[e].identity,
-                          &F_8_0);
+              if (cmd->id_var)
+                tab_value (t,
+                           heading_columns,
+                           heading_rows + v * rows_per_var + i * rows_per_cat + cmd->disp_extremes + e,
+                           TAB_RIGHT,
+                           &es->minima[e].identity,
+                           cmd->id_var,
+                           NULL);
+              else
+                tab_double (t,
+                            heading_columns,
+                            heading_rows + v * rows_per_var + i * rows_per_cat + cmd->disp_extremes + e,
+                            TAB_RIGHT,
+                            es->minima[e].identity.f,
+                            NULL, RC_INTEGER);
 
               tab_double (t,
                           heading_columns + 1,
                           heading_rows + v * rows_per_var + i * rows_per_cat + cmd->disp_extremes + e,
                           0,
                           es->minima[e].val,
-                          0);
+                          var_get_print_format (cmd->dep_vars[v]), RC_OTHER);
             }
         }
       free (prev_val);
@@ -1213,6 +1305,7 @@ summary_report (const struct examine *cmd, int iact_idx)
   const int nc = 6 + heading_columns;
 
   t = tab_create (nc, nr);
+  tab_set_format (t, RC_WEIGHT, wfmt);
   tab_title (t, _("Case Processing Summary"));
 
   tab_headers (t, heading_columns, 0, heading_rows, 0);
@@ -1263,114 +1356,114 @@ summary_report (const struct examine *cmd, int iact_idx)
     }
 
   if (n_cats > 0)
-  for (v = 0; v < cmd->n_dep_vars; ++v)
-    {
-      int ivar_idx;
-      const union value **prev_values = previous_value_alloc (iact);
-
-      if ( v > 0 )
-        tab_hline (t, TAL_1, 0, nc - 1, heading_rows + v * n_cats);
-
-      tab_text (t,
-                0, heading_rows + n_cats * v,
-                TAT_TITLE,
-                var_to_string (cmd->dep_vars[v])
-                );
-
-
-      for (i = 0; i < n_cats; ++i)
-        {
-          double total;
-          const struct exploratory_stats *es;
-
-          const struct ccase *c =
-            categoricals_get_case_by_category_real (cmd->cats,
-                                                    iact_idx, i);
-          if (c)
-            {
-              int diff_idx = previous_value_record (iact, c, prev_values);
-
-              if ( diff_idx != -1 && diff_idx < iact->n_vars - 1)
-                tab_hline (t, TAL_1, 1 + diff_idx, nc - 1,
-                           heading_rows + n_cats * v + i );
-
-              for (ivar_idx = 0; ivar_idx < iact->n_vars; ++ivar_idx)
-                {
-                  const struct variable *ivar = iact->vars[ivar_idx];
-                  const union value *val = case_data (c, ivar);
-
-                  if (( diff_idx != -1 && diff_idx <= ivar_idx)
-                      || i == 0)
-                    {              
-                      struct string str;
-                      ds_init_empty (&str);
-                      var_append_value_name (ivar, val, &str);
+    for (v = 0; v < cmd->n_dep_vars; ++v)
+      {
+       int ivar_idx;
+       const union value **prev_values = previous_value_alloc (iact);
+
+       if ( v > 0 )
+         tab_hline (t, TAL_1, 0, nc - 1, heading_rows + v * n_cats);
+
+       tab_text (t,
+                 0, heading_rows + n_cats * v,
+                 TAT_TITLE,
+                 var_to_string (cmd->dep_vars[v])
+                 );
+
+
+       for (i = 0; i < n_cats; ++i)
+         {
+           double total;
+           const struct exploratory_stats *es;
+
+           const struct ccase *c =
+             categoricals_get_case_by_category_real (cmd->cats,
+                                                     iact_idx, i);
+           if (c)
+             {
+               int diff_idx = previous_value_record (iact, c, prev_values);
+
+               if ( diff_idx != -1 && diff_idx < iact->n_vars - 1)
+                 tab_hline (t, TAL_1, 1 + diff_idx, nc - 1,
+                            heading_rows + n_cats * v + i );
+
+               for (ivar_idx = 0; ivar_idx < iact->n_vars; ++ivar_idx)
+                 {
+                   const struct variable *ivar = iact->vars[ivar_idx];
+                   const union value *val = case_data (c, ivar);
+
+                   if (( diff_idx != -1 && diff_idx <= ivar_idx)
+                       || i == 0)
+                     {              
+                       struct string str;
+                       ds_init_empty (&str);
+                       append_value_name (ivar, val, &str);
               
-                      tab_text (t,
-                                1 + ivar_idx, heading_rows + n_cats * v + i,
-                                TAT_TITLE | TAB_LEFT,
-                                ds_cstr (&str)
-                                );
+                       tab_text (t,
+                                 1 + ivar_idx, heading_rows + n_cats * v + i,
+                                 TAT_TITLE | TAB_LEFT,
+                                 ds_cstr (&str)
+                                 );
                   
-                      ds_destroy (&str);
-                    }
-                }
-            }
+                       ds_destroy (&str);
+                     }
+                 }
+             }
 
 
-          es = categoricals_get_user_data_by_category_real (cmd->cats, iact_idx, i);
+           es = categoricals_get_user_data_by_category_real (cmd->cats, iact_idx, i);
   
           
-          total = es[v].missing + es[v].non_missing;
-          tab_double (t, 
-                      heading_columns + 0,
-                      heading_rows + n_cats * v + i,
-                      0,
-                      es[v].non_missing,
-                      wfmt);
-
-
-          tab_text_format (t, 
-                           heading_columns + 1,
-                           heading_rows + n_cats * v + i,
-                           0,
-                           "%g%%",
-                           100.0 * es[v].non_missing / total
-                           );
-
-
-          tab_double (t, 
-                      heading_columns + 2,
-                      heading_rows + n_cats * v + i,
-                      0,
-                      es[v].missing,
-                      wfmt);
-
-          tab_text_format (t, 
-                           heading_columns + 3,
-                           heading_rows + n_cats * v + i,
-                           0,
-                           "%g%%",
-                           100.0 * es[v].missing / total
-                           );
-          tab_double (t, 
-                      heading_columns + 4,
-                      heading_rows + n_cats * v + i,
-                      0,
-                      total,
-                      wfmt);
-
-          /* This can only be 100% can't it? */
-          tab_text_format (t, 
-                           heading_columns + 5,
-                           heading_rows + n_cats * v + i,
-                           0,
-                           "%g%%",
-                           100.0 * (es[v].missing + es[v].non_missing)/ total
-                           );
-        }
-      free (prev_values);
-    }
+           total = es[v].missing + es[v].non_missing;
+           tab_double (t, 
+                       heading_columns + 0,
+                       heading_rows + n_cats * v + i,
+                       0,
+                       es[v].non_missing,
+                       NULL, RC_WEIGHT);
+
+
+           tab_text_format (t, 
+                            heading_columns + 1,
+                            heading_rows + n_cats * v + i,
+                            0,
+                            "%g%%",
+                            100.0 * es[v].non_missing / total
+                            );
+
+
+           tab_double (t, 
+                       heading_columns + 2,
+                       heading_rows + n_cats * v + i,
+                       0,
+                       es[v].missing,
+                       NULL, RC_WEIGHT);
+
+           tab_text_format (t, 
+                            heading_columns + 3,
+                            heading_rows + n_cats * v + i,
+                            0,
+                            "%g%%",
+                            100.0 * es[v].missing / total
+                            );
+           tab_double (t, 
+                       heading_columns + 4,
+                       heading_rows + n_cats * v + i,
+                       0,
+                       total,
+                       NULL, RC_WEIGHT);
+
+           /* This can only be 100% can't it? */
+           tab_text_format (t, 
+                            heading_columns + 5,
+                            heading_rows + n_cats * v + i,
+                            0,
+                            "%g%%",
+                            100.0 * (es[v].missing + es[v].non_missing)/ total
+                            );
+         }
+       free (prev_values);
+      }
 
   tab_hline (t, TAL_1, heading_columns, nc - 1, 1);
   tab_hline (t, TAL_1, heading_columns, nc - 1, 2);
@@ -1378,25 +1471,6 @@ summary_report (const struct examine *cmd, int iact_idx)
   tab_submit (t);
 }
 
-
-/* Match a variable.
-   If the match succeeds, the variable will be placed in VAR.
-   Returns true if successful */
-static bool
-lex_match_variable (struct lexer *lexer, 
-                    const struct dictionary *dict, const struct variable **var)
-{
-  if (lex_token (lexer) !=  T_ID)
-
-    return false;
-
-  *var = parse_variable_const  (lexer, dict);
-
-  if ( *var == NULL)
-    return false;
-  return true;
-}
-
 /* Attempt to parse an interaction from LEXER */
 static struct interaction *
 parse_interaction (struct lexer *lexer, struct examine *ex)
@@ -1457,19 +1531,20 @@ update_n (const void *aux1, void *aux2 UNUSED, void *user_data,
   int v;
   const struct examine *examine = aux1;
   struct exploratory_stats *es = user_data;
-
+  
   for (v = 0; v < examine->n_dep_vars; v++)
     {
+      struct ccase *outcase ;
       const struct variable *var = examine->dep_vars[v];
       const double x = case_data (c, var)->f;
       
-      if (var_is_value_missing (var, case_data (c, var), examine->exclude))
+      if (var_is_value_missing (var, case_data (c, var), examine->dep_excl))
         {
           es[v].missing += weight;
           continue;
         }
 
-      struct ccase *outcase = case_create (examine->ex_proto);
+      outcase = case_create (examine->ex_proto);
 
       if (x > es[v].maximum)
         es[v].maximum = x;
@@ -1481,10 +1556,11 @@ update_n (const void *aux1, void *aux2 UNUSED, void *user_data,
 
       moments_pass_one (es[v].mom, x, weight);
 
-      /* Save the value and the casenumber to the writer */
+      /* Save the value and the ID to the writer */
+      assert (examine->id_idx != -1);
       case_data_rw_idx (outcase, EX_VAL)->f = x;
-      if ( examine->id_idx != -1)
-        case_data_rw_idx (outcase, EX_ID)->f = case_data_idx (c, examine->id_idx)->f;
+      value_copy (case_data_rw_idx (outcase, EX_ID),
+                  case_data_idx (c, examine->id_idx), examine->id_width);
 
       case_data_rw_idx (outcase, EX_WT)->f = weight;
       
@@ -1508,29 +1584,39 @@ calculate_n (const void *aux1, void *aux2 UNUSED, void *user_data)
     {
       int i;
       casenumber imin = 0;
-      double imax = es[v].cc;
+      casenumber imax;
       struct casereader *reader;
       struct ccase *c;
-      casenumber total_cases;
 
-      if (examine->histogram)
+      if (examine->histogramplot)
         {
+          /* Sturges Rule */
+          double bin_width = fabs (es[v].minimum - es[v].maximum)
+            / (1 + log2 (es[v].cc))
+            ;
+
           es[v].histogram =
-            histogram_create (10, es[v].minimum, es[v].maximum);
+            histogram_create (bin_width, es[v].minimum, es[v].maximum);
         }
 
       es[v].sorted_reader = casewriter_make_reader (es[v].sorted_writer);
-      total_cases = casereader_count_cases (es[v].sorted_reader);
       es[v].sorted_writer = NULL;
 
+      imax = casereader_get_case_cnt (es[v].sorted_reader);
+
       es[v].maxima = pool_calloc (examine->pool, examine->calc_extremes, sizeof (*es[v].maxima));
       es[v].minima = pool_calloc (examine->pool, examine->calc_extremes, sizeof (*es[v].minima));
+      for (i = 0; i < examine->calc_extremes; ++i)
+        {
+          value_init_pool (examine->pool, &es[v].maxima[i].identity, examine->id_width) ;
+          value_init_pool (examine->pool, &es[v].minima[i].identity, examine->id_width) ;
+        }
       
       for (reader = casereader_clone (es[v].sorted_reader);
            (c = casereader_read (reader)) != NULL; case_unref (c))
         {
           const double val = case_data_idx (c, EX_VAL)->f;
-          const double wt = case_data_idx (c, EX_WT)->f;   /* FIXME: What about fractional weights ??? */
+          const double wt = case_data_idx (c, EX_WT)->f;
 
           moments_pass_two (es[v].mom, val, wt);
 
@@ -1544,17 +1630,17 @@ calculate_n (const void *aux1, void *aux2 UNUSED, void *user_data)
                 {
                   struct extremity *min = &es[v].minima[x];
                   min->val = val;
-                  min->identity = case_data_idx (c, EX_ID)->f;
+                  value_copy (&min->identity, case_data_idx (c, EX_ID), examine->id_width);
                 }
-              imin += wt;
+              imin ++;
             }
 
-          imax -= wt;
+          imax --;
           if (imax < examine->calc_extremes)
             {
               int x;
 
-              for (x = imax; x < imax + wt; ++x)
+              for (x = imax; x < imax + 1; ++x)
                 {
                   struct extremity *max;
 
@@ -1563,7 +1649,7 @@ calculate_n (const void *aux1, void *aux2 UNUSED, void *user_data)
 
                   max = &es[v].maxima[x];
                   max->val = val;
-                  max->identity = case_data_idx (c, EX_ID)->f;
+                  value_copy (&max->identity, case_data_idx (c, EX_ID), examine->id_width);
                 }
             }
         }
@@ -1572,41 +1658,41 @@ calculate_n (const void *aux1, void *aux2 UNUSED, void *user_data)
       if (examine->calc_extremes > 0)
         {
           assert (es[v].minima[0].val == es[v].minimum);
-          assert (es[v].maxima[0].val == es[v].maximum);
+         assert (es[v].maxima[0].val == es[v].maximum);
         }
 
       {
-      const int n_os = 5 + examine->n_percentiles;
-      struct order_stats **os ;
-      es[v].percentiles = pool_calloc (examine->pool, examine->n_percentiles, sizeof (*es[v].percentiles));
+       const int n_os = 5 + examine->n_percentiles;
+       struct order_stats **os ;
+       es[v].percentiles = pool_calloc (examine->pool, examine->n_percentiles, sizeof (*es[v].percentiles));
 
-      es[v].trimmed_mean = trimmed_mean_create (es[v].cc, 0.05);
+       es[v].trimmed_mean = trimmed_mean_create (es[v].cc, 0.05);
 
-      os = xcalloc (n_os, sizeof *os);
-      os[0] = &es[v].trimmed_mean->parent;
+       os = xcalloc (n_os, sizeof *os);
+       os[0] = &es[v].trimmed_mean->parent;
 
-      es[v].quartiles[0] = percentile_create (0.25, es[v].cc);
-      es[v].quartiles[1] = percentile_create (0.5,  es[v].cc);
-      es[v].quartiles[2] = percentile_create (0.75, es[v].cc);
+       es[v].quartiles[0] = percentile_create (0.25, es[v].cc);
+       es[v].quartiles[1] = percentile_create (0.5,  es[v].cc);
+       es[v].quartiles[2] = percentile_create (0.75, es[v].cc);
 
-      os[1] = &es[v].quartiles[0]->parent;
-      os[2] = &es[v].quartiles[1]->parent;
-      os[3] = &es[v].quartiles[2]->parent;
+       os[1] = &es[v].quartiles[0]->parent;
+       os[2] = &es[v].quartiles[1]->parent;
+       os[3] = &es[v].quartiles[2]->parent;
 
-      es[v].hinges = tukey_hinges_create (es[v].cc, es[v].cmin);
-      os[4] = &es[v].hinges->parent;
+       es[v].hinges = tukey_hinges_create (es[v].cc, es[v].cmin);
+       os[4] = &es[v].hinges->parent;
 
-      for (i = 0; i < examine->n_percentiles; ++i)
-        {
-          es[v].percentiles[i] = percentile_create (examine->ptiles[i] / 100.00, es[v].cc);
-          os[5 + i] = &es[v].percentiles[i]->parent;
-        }
+       for (i = 0; i < examine->n_percentiles; ++i)
+         {
+           es[v].percentiles[i] = percentile_create (examine->ptiles[i] / 100.00, es[v].cc);
+           os[5 + i] = &es[v].percentiles[i]->parent;
+         }
 
-      order_stats_accumulate_idx (os, n_os,
-                                  casereader_clone (es[v].sorted_reader),
-                                  EX_WT, EX_VAL);
+       order_stats_accumulate_idx (os, n_os,
+                                   casereader_clone (es[v].sorted_reader),
+                                   EX_WT, EX_VAL);
 
-      free (os);
+       free (os);
       }
 
       if (examine->boxplot)
@@ -1614,12 +1700,12 @@ calculate_n (const void *aux1, void *aux2 UNUSED, void *user_data)
           struct order_stats *os;
 
           es[v].box_whisker = box_whisker_create (es[v].hinges, 
-                                                  EX_ID);
+                                                  EX_ID, examine->id_var);
 
           os = &es[v].box_whisker->parent;
          order_stats_accumulate_idx (&os, 1,
-                                  casereader_clone (es[v].sorted_reader),
-                                  EX_WT, EX_VAL);
+                                     casereader_clone (es[v].sorted_reader),
+                                     EX_WT, EX_VAL);
         }
 
       if (examine->npplot)
@@ -1634,8 +1720,8 @@ calculate_n (const void *aux1, void *aux2 UNUSED, void *user_data)
           os = &es[v].np->parent;
 
           order_stats_accumulate_idx (&os, 1,
-                                  casereader_clone (es[v].sorted_reader),
-                                  EX_WT, EX_VAL);
+                                     casereader_clone (es[v].sorted_reader),
+                                     EX_WT, EX_VAL);
         }
 
     }
@@ -1659,42 +1745,36 @@ cleanup_exploratory_stats (struct examine *cmd)
              const struct exploratory_stats *es =
                categoricals_get_user_data_by_category_real (cmd->cats, i, grp);
 
-             struct order_stats *os = es[v].hinges;
+             struct order_stats *os = &es[v].hinges->parent;
              struct statistic  *stat = &os->parent;
              stat->destroy (stat);
 
              for (q = 0; q < 3 ; q++)
                {
-                 os = es[v].quartiles[q];
+                 os = &es[v].quartiles[q]->parent;
                  stat = &os->parent;
                  stat->destroy (stat);
                }
 
              for (q = 0; q < cmd->n_percentiles ; q++)
                {
-                 os = es[v].percentiles[q];
+                 os = &es[v].percentiles[q]->parent;
                  stat = &os->parent;
                  stat->destroy (stat);
                }
 
-             os = es[v].trimmed_mean;
+             os = &es[v].trimmed_mean->parent;
              stat = &os->parent;
              stat->destroy (stat);
 
-             os = es[v].np;
-             if (os)
-               {
-                 stat = &os->parent;
-                 stat->destroy (stat);
-               }
-
-             os = es[v].histogram;
+             os = &es[v].np->parent;
              if (os)
                {
                  stat = &os->parent;
                  stat->destroy (stat);
                }
 
+             statistic_destroy (&es[v].histogram->parent);
              moments_destroy (es[v].mom);
 
              casereader_destroy (es[v].sorted_reader);
@@ -1714,40 +1794,33 @@ run_examine (struct examine *cmd, struct casereader *input)
   struct payload payload;
   payload.create = create_n;
   payload.update = update_n;
-  payload.destroy = calculate_n;
+  payload.calculate = calculate_n;
+  payload.destroy = NULL;
   
   cmd->wv = dict_get_weight (cmd->dict);
 
-  cmd->id_idx = -1;
   cmd->cats
     = categoricals_create (cmd->iacts, cmd->n_iacts,  
-                           cmd->wv, cmd->exclude);
+                           cmd->wv, cmd->dep_excl, cmd->fctr_excl);
 
   categoricals_set_payload (cmd->cats, &payload, cmd, NULL);
 
-  if (cmd->casenumbers)
+  if (cmd->id_var == NULL)
     {
       struct ccase *c = casereader_peek (input,  0);
 
-      if (cmd->id_var) 
-        cmd->id_idx = var_get_case_index (cmd->id_var);
-      else
-        {
-          cmd->id_idx = case_get_value_cnt (c);
-          input = casereader_create_arithmetic_sequence (input, 1.0, 1.0);
-        }
+      cmd->id_idx = case_get_value_cnt (c);
+      input = casereader_create_arithmetic_sequence (input, 1.0, 1.0);
 
       case_unref (c);
     }
 
-  /* FIXME: Filter out missing factor variables */
-
   /* Remove cases on a listwise basis if requested */
   if ( cmd->missing_pw == false)
     input = casereader_create_filter_missing (input,
                                               cmd->dep_vars,
                                               cmd->n_dep_vars,
-                                              cmd->exclude,
+                                              cmd->dep_excl,
                                               NULL,
                                               NULL);
 
@@ -1785,12 +1858,15 @@ run_examine (struct examine *cmd, struct casereader *input)
             }
         }
 
-      if (cmd->histogram)
+      if (cmd->histogramplot)
         show_histogram (cmd, i);
 
       if (cmd->npplot)
         show_npplot (cmd, i);
 
+      if (cmd->spreadlevelplot)
+        show_spreadlevel (cmd, i);
+
       if (cmd->descriptives)
         descriptives_report (cmd, i);
     }
@@ -1811,7 +1887,6 @@ cmd_examine (struct lexer *lexer, struct dataset *ds)
   struct examine examine;
   bool percentiles_seen = false;
 
-  examine.casenumbers = false;
   examine.missing_pw = false;
   examine.disp_extremes = 0;
   examine.calc_extremes = 0;
@@ -1820,13 +1895,12 @@ cmd_examine (struct lexer *lexer, struct dataset *ds)
   examine.pc_alg = PC_HAVERAGE;
   examine.ptiles = NULL;
   examine.n_percentiles = 0;
-  examine.id_var = 0;
+  examine.id_idx = -1;
+  examine.id_width = 0;
+  examine.id_var = NULL;
   examine.boxplot_mode = BP_GROUPS;
   
   examine.ex_proto = caseproto_create ();
-  examine.ex_proto = caseproto_add_width (examine.ex_proto, 0); /* value */
-  examine.ex_proto = caseproto_add_width (examine.ex_proto, 0); /* id */
-  examine.ex_proto = caseproto_add_width (examine.ex_proto, 0); /* weight */
 
   examine.pool = pool_create ();
 
@@ -1839,10 +1913,13 @@ cmd_examine (struct lexer *lexer, struct dataset *ds)
   examine.iacts = iacts_mem = pool_zalloc (examine.pool, sizeof (struct interaction *));
   examine.iacts[0] = interaction_create (NULL);
 
-  examine.exclude = MV_ANY;
-  examine.histogram = false;
+  examine.dep_excl = MV_ANY;
+  examine.fctr_excl = MV_ANY;
+  examine.histogramplot = false;
   examine.npplot = false;
   examine.boxplot = false;
+  examine.spreadlevelplot = false;
+  examine.sl_power = 0;
   
   examine.dict = dataset_dict (ds);
 
@@ -2021,11 +2098,19 @@ cmd_examine (struct lexer *lexer, struct dataset *ds)
                 }
               else if (lex_match_id (lexer, "EXCLUDE"))
                 {
-                  examine.exclude = MV_ANY;
+                  examine.dep_excl = MV_ANY;
                 }
               else if (lex_match_id (lexer, "INCLUDE"))
                 {
-                  examine.exclude = MV_SYSTEM;
+                  examine.dep_excl = MV_SYSTEM;
+                }
+              else if (lex_match_id (lexer, "REPORT"))
+                {
+                  examine.fctr_excl = MV_NEVER;
+                }
+              else if (lex_match_id (lexer, "NOREPORT"))
+                {
+                  examine.fctr_excl = MV_ANY;
                 }
               else
                 {
@@ -2068,17 +2153,30 @@ cmd_examine (struct lexer *lexer, struct dataset *ds)
                 }
               else if (lex_match_id (lexer, "HISTOGRAM"))
                 {
-                  examine.histogram = true;
+                  examine.histogramplot = true;
+                }
+              else if (lex_match_id (lexer, "SPREADLEVEL"))
+                {
+                 examine.spreadlevelplot = true;
+                 examine.sl_power = 0;
+                 if (lex_match (lexer, T_LPAREN) && lex_force_int (lexer))
+                   {
+                      examine.sl_power = lex_integer (lexer);
+
+                      lex_get (lexer);
+                      if (! lex_force_match (lexer, T_RPAREN))
+                        goto error;
+                   }
                 }
               else if (lex_match_id (lexer, "NONE"))
                 {
-                  examine.histogram = false;
+                  examine.histogramplot = false;
                   examine.npplot = false;
                   examine.boxplot = false;
                 }
               else if (lex_match (lexer, T_ALL))
                 {
-                  examine.histogram = true;
+                  examine.histogramplot = true;
                   examine.npplot = true;
                   examine.boxplot = true;
                 }
@@ -2111,6 +2209,7 @@ cmd_examine (struct lexer *lexer, struct dataset *ds)
         }
     }
 
+
   if ( totals_seen && nototals_seen)
     {
       msg (SE, _("%s and %s are mutually exclusive"),"TOTAL","NOTOTAL");
@@ -2127,21 +2226,26 @@ cmd_examine (struct lexer *lexer, struct dataset *ds)
     {
       examine.n_iacts--;
       examine.iacts = &iacts_mem[1];
+      interaction_destroy (iacts_mem[0]);
     }
 
 
-  if (examine.disp_extremes > 0)
+  if ( examine.id_var )
     {
-      examine.calc_extremes = examine.disp_extremes;
-      examine.casenumbers = true;
+      examine.id_idx = var_get_case_index (examine.id_var);
+      examine.id_width = var_get_width (examine.id_var);
     }
 
-  if (examine.boxplot)
+  examine.ex_proto = caseproto_add_width (examine.ex_proto, 0); /* value */
+  examine.ex_proto = caseproto_add_width (examine.ex_proto, examine.id_width);   /* id */
+  examine.ex_proto = caseproto_add_width (examine.ex_proto, 0); /* weight */
+
+
+  if (examine.disp_extremes > 0)
     {
-      examine.casenumbers = true;
+      examine.calc_extremes = examine.disp_extremes;
     }
 
-
   if (examine.descriptives && examine.calc_extremes == 0)
     {
       /* Descriptives always displays the max and min */
@@ -2180,7 +2284,6 @@ cmd_examine (struct lexer *lexer, struct dataset *ds)
 
   for (i = 0; i < examine.n_iacts; ++i)
     interaction_destroy (examine.iacts[i]);
-
   free (examine.ptiles);
   free (examine.dep_vars);
   pool_destroy (examine.pool);
@@ -2189,6 +2292,7 @@ cmd_examine (struct lexer *lexer, struct dataset *ds)
 
  error:
   caseproto_unref (examine.ex_proto);
+  examine.iacts = iacts_mem;
   for (i = 0; i < examine.n_iacts; ++i)
     interaction_destroy (examine.iacts[i]);
   free (examine.dep_vars);