2-d subtotals work
[pspp] / src / language / stats / ctables.c
index af53a6b6c53643a9d577a0b06a01d43e5db06880..c982f19cf63ad431faaf532c0637133daf43b574 100644 (file)
@@ -1925,7 +1925,8 @@ ctables_summary_add (union ctables_summary *s,
     case CTSF_LAYERPCT_SUM:
     case CTSF_LAYERROWPCT_SUM:
     case CTSF_LAYERCOLPCT_SUM:
-      moments1_add (s->moments, value->f, weight);
+      if (!var_is_value_missing (var, value))
+        moments1_add (s->moments, value->f, weight);
       break;
 
     case CTSF_MEDIAN:
@@ -2446,6 +2447,34 @@ recurse_totals (struct ctables_table *t, const struct ccase *c,
     }
 }
 
+static void
+recurse_subtotals (struct ctables_table *t, const struct ccase *c,
+                   size_t ix[PIVOT_N_AXES],
+                   const struct ctables_category *cats[PIVOT_N_AXES][10],
+                   double weight,
+                   enum pivot_axis_type start_axis, size_t start_nest)
+{
+  for (enum pivot_axis_type a = start_axis; a < PIVOT_N_AXES; a++)
+    {
+      const struct ctables_nest *nest = &t->stacks[a].nests[ix[a]];
+      for (size_t i = start_nest; i < nest->n; i++)
+        {
+          if (i == nest->scale_idx)
+            continue;
+
+          const struct ctables_category *save = cats[a][i];
+          if (save->subtotal)
+            {
+              cats[a][i] = save->subtotal;
+              ctables_cell_add__ (t, c, ix, cats, weight);
+              recurse_subtotals (t, c, ix, cats, weight, a, i + 1);
+              cats[a][i] = save;
+            }
+        }
+      start_nest = 0;
+    }
+}
+
 static void
 ctables_cell_insert (struct ctables_table *t,
                      const struct ccase *c,
@@ -2483,24 +2512,7 @@ ctables_cell_insert (struct ctables_table *t,
   ctables_cell_add__ (t, c, ix, cats, weight);
 
   recurse_totals (t, c, ix, cats, weight, 0, 0);
-
-  for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
-    {
-      const struct ctables_nest *nest = &t->stacks[a].nests[ix[a]];
-      for (size_t i = 0; i < nest->n; i++)
-        {
-          if (i == nest->scale_idx)
-            continue;
-
-          const struct ctables_category *save = cats[a][i];
-          if (save->subtotal)
-            {
-              cats[a][i] = save->subtotal;
-              ctables_cell_add__ (t, c, ix, cats, weight);
-              cats[a][i] = save;
-            }
-        }
-    }
+  recurse_subtotals (t, c, ix, cats, weight, 0, 0);
 }
 
 struct merge_item
@@ -2566,12 +2578,16 @@ ctables_table_output (struct ctables *ct, struct ctables_table *t)
     pivot_table_set_caption (
       pt, pivot_value_new_user_text (t->corner, SIZE_MAX));
 
-  bool summary_dimension = t->summary_axis != t->slabels_axis;
+  bool summary_dimension = (t->summary_axis != t->slabels_axis
+                            || (!t->slabels_visible
+                                && t->summary_specs.n > 1));
   if (summary_dimension)
     {
       struct pivot_dimension *d = pivot_dimension_create (
-        pt, t->slabels_axis, N_("Summaries"));
+        pt, t->slabels_axis, N_("Statistics"));
       const struct ctables_summary_spec_set *specs = &t->summary_specs;
+      if (!t->slabels_visible)
+        d->hide_all_labels = true;
       for (size_t i = 0; i < specs->n; i++)
         pivot_category_create_leaf (
           d->root, pivot_value_new_text (specs->specs[i].label));
@@ -2678,13 +2694,11 @@ ctables_table_output (struct ctables *ct, struct ctables_table *t)
           if (new_subtable)
             {
               n_levels = 0;
-              printf ("%s levels:", pivot_axis_type_to_string (a));
               for (size_t k = 0; k < nest->n; k++)
                 {
                   enum ctables_vlabel vlabel = ct->vlabels[var_get_dict_index (nest->vars[k])];
                   if (vlabel != CTVL_NONE)
                     {
-                      printf (" var(%s)", var_get_name (nest->vars[k]));
                       levels[n_levels++] = (struct ctables_level) {
                         .type = CTL_VAR,
                         .var_idx = k,
@@ -2694,7 +2708,6 @@ ctables_table_output (struct ctables *ct, struct ctables_table *t)
                   if (nest->scale_idx != k
                       && (k != nest->n - 1 || t->label_axis[a] == a))
                     {
-                      printf (" category(%s)", var_get_name (nest->vars[k]));
                       levels[n_levels++] = (struct ctables_level) {
                         .type = CTL_CATEGORY,
                         .var_idx = k,
@@ -2702,15 +2715,13 @@ ctables_table_output (struct ctables *ct, struct ctables_table *t)
                     }
                 }
 
-              if (a == t->slabels_axis && a == t->summary_axis)
+              if (!summary_dimension && a == t->slabels_axis)
                 {
-                  printf (" summary");
                   levels[n_levels++] = (struct ctables_level) {
                     .type = CTL_SUMMARY,
                     .var_idx = SIZE_MAX,
                   };
                 }
-              printf ("\n");
             }
 
           size_t n_common = 0;
@@ -2722,17 +2733,16 @@ ctables_table_output (struct ctables *ct, struct ctables_table *t)
                   if (level->type == CTL_CATEGORY)
                     {
                       size_t var_idx = level->var_idx;
-                      if (prev->axes[a].cvs[var_idx].category
-                          != cell->axes[a].cvs[var_idx].category)
-                        {
-                          break;
-                        }
-                      else if (!value_equal (&prev->axes[a].cvs[var_idx].value,
-                                           &cell->axes[a].cvs[var_idx].value,
-                                             var_get_type (nest->vars[var_idx])))
-                        {
-                          break;
-                        }
+                      const struct ctables_category *c = cell->axes[a].cvs[var_idx].category;
+                      if (prev->axes[a].cvs[var_idx].category != c)
+                        break;
+                      else if (c->type != CCT_SUBTOTAL
+                               && c->type != CCT_HSUBTOTAL
+                               && c->type != CCT_TOTAL
+                               && !value_equal (&prev->axes[a].cvs[var_idx].value,
+                                                &cell->axes[a].cvs[var_idx].value,
+                                                var_get_type (nest->vars[var_idx])))
+                        break;
                     }
                 }
             }