EXAMINE: Fix memory leak in box-whisker plots.
[pspp] / src / language / stats / examine.c
index ea1b5dba19d3ba23fe83674605f41bca9dee621f..dc0d6c5beecfe4a160105e3fbbf2729631c5c7bd 100644 (file)
@@ -1,6 +1,6 @@
 /*
   PSPP - a program for statistical analysis.
-  Copyright (C) 2012, 2013  Free Software Foundation, Inc.
+  Copyright (C) 2012, 2013, 2016  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
@@ -298,7 +298,7 @@ show_boxplot_grouped (const struct examine *cmd, int iact_idx)
           const struct ccase *c =
             categoricals_get_case_by_category_real (cmd->cats,  iact_idx, grp);
 
-          const struct exploratory_stats *es =
+          struct exploratory_stats *es =
             categoricals_get_user_data_by_category_real (cmd->cats, iact_idx, grp);
 
           ds_init_empty (&label);
@@ -320,6 +320,7 @@ show_boxplot_grouped (const struct examine *cmd, int iact_idx)
             }
 
           boxplot_add_box (boxplot, es[v].box_whisker, ds_cstr (&label));
+          es[v].box_whisker = NULL;
 
           ds_destroy (&label);
         }
@@ -390,11 +391,12 @@ show_boxplot_variabled (const struct examine *cmd, int iact_idx)
 
       for (v = 0; v < cmd->n_dep_vars; ++v)
         {
-          const struct exploratory_stats *es =
+          struct exploratory_stats *es =
             categoricals_get_user_data_by_category_real (cmd->cats, iact_idx, grp);
 
           boxplot_add_box (boxplot, es[v].box_whisker, 
                            var_to_string (cmd->dep_vars[v]));
+          es[v].box_whisker = NULL;
         }
 
       boxplot_submit (boxplot);
@@ -605,6 +607,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);
@@ -724,7 +727,7 @@ percentiles_report (const struct examine *cmd, int iact_idx)
                              heading_rows + v * rows_per_var + i * rows_per_cat,
                              0,
                              percentile_calculate (es->percentiles[p], cmd->pc_alg),
-                             0);
+                             NULL, RC_OTHER);
               
                  if (cmd->ptiles[p] == 25.0)
                    {
@@ -732,7 +735,7 @@ percentiles_report (const struct examine *cmd, int iact_idx)
                                  heading_rows + v * rows_per_var + i * rows_per_cat + 1,
                                  0,
                                  hinges[0],
-                                 0);
+                                 NULL, RC_OTHER);
                    }
                  else if (cmd->ptiles[p] == 50.0)
                    {
@@ -740,7 +743,7 @@ percentiles_report (const struct examine *cmd, int iact_idx)
                                  heading_rows + v * rows_per_var + i * rows_per_cat + 1,
                                  0,
                                  hinges[1],
-                                 0);
+                                 NULL, RC_OTHER);
                    }
                  else if (cmd->ptiles[p] == 75.0)
                    {
@@ -748,7 +751,7 @@ percentiles_report (const struct examine *cmd, int iact_idx)
                                  heading_rows + v * rows_per_var + i * rows_per_cat + 1,
                                  0,
                                  hinges[2],
-                                 0);
+                                 NULL, RC_OTHER);
                    }
                }
 
@@ -784,6 +787,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);
@@ -889,12 +893,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,
@@ -914,7 +918,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,
@@ -927,7 +931,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,
@@ -942,7 +946,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,
@@ -956,7 +960,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,
@@ -969,7 +973,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,
@@ -981,7 +985,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,
@@ -995,7 +999,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,
@@ -1009,7 +1013,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,
@@ -1023,7 +1027,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,
@@ -1039,7 +1043,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);
 
 
 
@@ -1054,12 +1058,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,
@@ -1071,12 +1075,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);
@@ -1103,6 +1107,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);
@@ -1219,7 +1224,7 @@ 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 */
               if (cmd->id_var)
@@ -1236,14 +1241,14 @@ extremes_report (const struct examine *cmd, int iact_idx)
                             heading_rows + v * rows_per_var + i * rows_per_cat + e,
                             TAB_RIGHT,
                             es->maxima[e].identity.f,
-                            &F_8_0);
+                            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,
-                         var_get_print_format (cmd->dep_vars[v]));
+                         var_get_print_format (cmd->dep_vars[v]), RC_OTHER);
                          
 
               tab_double (t,
@@ -1251,7 +1256,7 @@ extremes_report (const struct examine *cmd, int iact_idx)
                           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 */
               if (cmd->id_var)
@@ -1268,14 +1273,14 @@ extremes_report (const struct examine *cmd, int iact_idx)
                             heading_rows + v * rows_per_var + i * rows_per_cat + cmd->disp_extremes + e,
                             TAB_RIGHT,
                             es->minima[e].identity.f,
-                            &F_8_0);
+                            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,
-                          var_get_print_format (cmd->dep_vars[v]));
+                          var_get_print_format (cmd->dep_vars[v]), RC_OTHER);
             }
         }
       free (prev_val);
@@ -1302,6 +1307,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);
@@ -1416,7 +1422,7 @@ summary_report (const struct examine *cmd, int iact_idx)
                        heading_rows + n_cats * v + i,
                        0,
                        es[v].non_missing,
-                       wfmt);
+                       NULL, RC_WEIGHT);
 
 
            tab_text_format (t, 
@@ -1433,7 +1439,7 @@ summary_report (const struct examine *cmd, int iact_idx)
                        heading_rows + n_cats * v + i,
                        0,
                        es[v].missing,
-                       wfmt);
+                       NULL, RC_WEIGHT);
 
            tab_text_format (t, 
                             heading_columns + 3,
@@ -1447,7 +1453,7 @@ summary_report (const struct examine *cmd, int iact_idx)
                        heading_rows + n_cats * v + i,
                        0,
                        total,
-                       wfmt);
+                       NULL, RC_WEIGHT);
 
            /* This can only be 100% can't it? */
            tab_text_format (t, 
@@ -1528,6 +1534,25 @@ update_n (const void *aux1, void *aux2 UNUSED, void *user_data,
   const struct examine *examine = aux1;
   struct exploratory_stats *es = user_data;
   
+  bool this_case_is_missing = false;
+  /* LISTWISE missing must be dealt with here */
+  if (!examine->missing_pw)
+    {
+      for (v = 0; v < examine->n_dep_vars; v++)
+       {
+         const struct variable *var = examine->dep_vars[v];
+
+         if (var_is_value_missing (var, case_data (c, var), examine->dep_excl))
+           {
+             es[v].missing += weight;
+             this_case_is_missing = true;
+           }
+       }
+    }
+
+  if (this_case_is_missing)
+    return;
+
   for (v = 0; v < examine->n_dep_vars; v++)
     {
       struct ccase *outcase ;
@@ -1584,7 +1609,7 @@ calculate_n (const void *aux1, void *aux2 UNUSED, void *user_data)
       struct casereader *reader;
       struct ccase *c;
 
-      if (examine->histogramplot)
+      if (examine->histogramplot && es[v].non_missing > 0)
         {
           /* Sturges Rule */
           double bin_width = fabs (es[v].minimum - es[v].maximum)
@@ -1651,7 +1676,7 @@ calculate_n (const void *aux1, void *aux2 UNUSED, void *user_data)
         }
       casereader_destroy (reader);
 
-      if (examine->calc_extremes > 0)
+      if (examine->calc_extremes > 0 && es[v].non_missing > 0)
         {
           assert (es[v].minima[0].val == es[v].minimum);
          assert (es[v].maxima[0].val == es[v].maximum);
@@ -1773,6 +1798,12 @@ cleanup_exploratory_stats (struct examine *cmd)
              statistic_destroy (&es[v].histogram->parent);
              moments_destroy (es[v].mom);
 
+              if (es[v].box_whisker)
+                {
+                  stat = &es[v].box_whisker->parent.parent;
+                  stat->destroy (stat);
+                }
+
              casereader_destroy (es[v].sorted_reader);
            }
        }
@@ -1811,15 +1842,6 @@ run_examine (struct examine *cmd, struct casereader *input)
       case_unref (c);
     }
 
-  /* 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->dep_excl,
-                                              NULL,
-                                              NULL);
-
   for (reader = input;
        (c = casereader_read (reader)) != NULL; case_unref (c))
     {
@@ -1832,6 +1854,10 @@ run_examine (struct examine *cmd, struct casereader *input)
     {
       summary_report (cmd, i);
 
+      const size_t n_cats =  categoricals_n_count (cmd->cats, i);
+      if (n_cats == 0)
+       continue;
+
       if (cmd->disp_extremes > 0)
         extremes_report (cmd, i);
 
@@ -2155,7 +2181,7 @@ cmd_examine (struct lexer *lexer, struct dataset *ds)
                 {
                  examine.spreadlevelplot = true;
                  examine.sl_power = 0;
-                 if (lex_match (lexer, T_LPAREN))
+                 if (lex_match (lexer, T_LPAREN) && lex_force_int (lexer))
                    {
                       examine.sl_power = lex_integer (lexer);
 
@@ -2278,6 +2304,8 @@ cmd_examine (struct lexer *lexer, struct dataset *ds)
 
   caseproto_unref (examine.ex_proto);
 
+  for (i = 0; i < examine.n_iacts; ++i)
+    interaction_destroy (examine.iacts[i]);
   free (examine.ptiles);
   free (examine.dep_vars);
   pool_destroy (examine.pool);