work on docs
authorBen Pfaff <blp@cs.stanford.edu>
Fri, 5 Aug 2022 23:20:04 +0000 (16:20 -0700)
committerBen Pfaff <blp@cs.stanford.edu>
Fri, 5 Aug 2022 23:20:04 +0000 (16:20 -0700)
doc/automake.mk
doc/pspp-figures/ctables22.sps [new file with mode: 0644]
doc/statistics.texi
doc/tutorial.stt
src/language/stats/ctables.c
src/language/stats/ctables.inc
tests/language/stats/ctables.at

index 4ecd6ff9c089cc5f2801f386ed429131ffb9e673..e99b82c6ee518e5b3aa4d645d164c84e775eac53 100644 (file)
@@ -138,6 +138,7 @@ FIGURE_SYNTAX = \
  doc/pspp-figures/ctables19.sps \
  doc/pspp-figures/ctables20.sps \
  doc/pspp-figures/ctables21.sps \
+ doc/pspp-figures/ctables22.sps \
  doc/pspp-figures/crosstabs.sps \
  doc/pspp-figures/descriptives.sps \
  doc/pspp-figures/flip.sps \
@@ -267,6 +268,13 @@ EXTRA_DIST += doc/tutorial.stt
 .spv.html:
        $(convert) -O format=html -O bare=true
 
+# Make sure that tutorial.stt outputs all layers, because a few of the
+# examples in the manual rely on that and it would be easy to replace
+# it with a style that didn't.
+ALL_LOCAL += tutorial-stt-must-print-all-layers
+tutorial-stt-must-print-all-layers:
+       $(AM_V_GEN)grep 'printAllLayers="true"' $(srcdir)/doc/tutorial.stt >/dev/null 2>&1 && touch $@
+
 # Convert a text file into a Texinfo file.
 .txt.texi:
        $(AM_V_GEN)$(SED) -e 's/@/@@/g' $< > $@
diff --git a/doc/pspp-figures/ctables22.sps b/doc/pspp-figures/ctables22.sps
new file mode 100644 (file)
index 0000000..396fbd3
--- /dev/null
@@ -0,0 +1,5 @@
+GET FILE='nhtsa.sav'.
+CTABLES
+    /VLABELS VARIABLES=ALL DISPLAY=NAME
+    /TABLE qn61 > qn57 BY qnd7a > qn86 + qn64b BY qns3a[TABLE.ID, LAYER.ID, SUBTABLE.ID]
+    /SLABELS POSITION=ROW.
index 497d3fa5a6351afb280222599ff4e5d85ca94993..60253236545786cc1cebba995a89c2bfee8ff691 100644 (file)
@@ -1196,46 +1196,47 @@ The following section lists the available summary functions.
 
 This section lists the summary functions that can be applied to cells
 in @code{CTABLES}.  Many of these functions have an @var{area} in
-their names.  The supported areas are:
-
-@itemize @bullet
-@item
-Areas that correspond to parts of @dfn{sections}, where stacked
-variables divide each section from another:
+their names, indicating that they summarize over multiple cells within
+an area of the output chosen by the user.  The following basic
+@var{area}s are supported, in decreasing order of size:
 
 @table @code
 @item TABLE
-An entire section.
+A @dfn{section}.  Stacked variables divide sections of the output from
+each other.  sections may span multiple layers.
 
 @item LAYER
-A layer within a section.
-
-@item LAYERROW
-A row in one layer within a section.
+A section within a single layer.
 
-@item LAYERCOL
-A column in one layer within a section.
+@item SUBTABLE
+A @dfn{subtable}, whose contents are the cells that pair an innermost
+row variable and an innermost column variable within a single layer.
 @end table
 
-@item
-Areas that correspond to parts of @dfn{subtables}, whose contents are
-the cells that pair an innermost row variable and an innermost column
-variable within a single layer.  A section can contain multiple
-subtables and a subtable is always within a single section:
+The following shows how the output for the table expression @code{qn61
+> qn57 BY qnd7a > qn86 + qn64b BY qns3a}@footnote{This is not
+necessarily a meaningful table, so for clarity variable labels are
+omitted.} is divided up into @code{TABLE}, @code{LAYER}, and
+@code{SUBTABLE} areas.  Each unique value for Table ID is one section,
+and similarly for Layer ID and Subtable ID.  Thus, this output has two
+@code{TABLE} areas (one for @code{qnd7a} and one for @code{qn64b}),
+four @code{LAYER} areas (for those two variables, per layer), and 12
+@code{SUBTABLE} areas.
+@psppoutput {ctables22}
 
-@table @code
-@item ROW
-A row within a subtable.
+@code{CTABLES} also supports the following @var{area}s that further
+divide a subtable or a layer within a section:
 
-@item COL
-A column within a subtable.
+@table @code
+@item LAYERROW
+@itemx LAYERCOL
+A row or column, respectively, in one layer of a section.
 
-@item SUBTABLE
-All the cells in a subtable.
+@item ROW
+@itemx ROW
+A row or column, respectively, in a subtable.
 @end table
 
-@end itemize
-
 The following summary functions may be applied to any variable
 regardless of whether it is categorical or scalar.  The default label
 for each function is listed in parentheses:
index 130ae9b23baa2b68217d59dc417a4f680d6107be..5c15a7130d717630b05547fefd95a2fac537519d 100644 (file)
@@ -49,5 +49,5 @@
         <horizontalCategoryBorderColumns borderStyleType="solid" color="#000000"/>
         <verticalCategoryBorderColumns borderStyleType="solid" color="#000000"/>
     </borderProperties>
-    <printingProperties printAllLayers="false" rescaleLongTableToFitPage="false" rescaleWideTableToFitPage="false" windowOrphanLines="0"/>
+    <printingProperties printAllLayers="true" rescaleLongTableToFitPage="false" rescaleWideTableToFitPage="false" windowOrphanLines="0"/>
 </tableProperties>
index 15c45b3042f29374bb9f745d7d089abdc97131a6..a573afaad1ba99075265128c73a58b47fae3c557 100644 (file)
@@ -109,7 +109,7 @@ struct ctables_domain
 
     const struct ctables_cell *example;
 
-    int sequence;
+    size_t sequence;
     double d_valid;             /* Dictionary weight. */
     double d_count;
     double d_total;
@@ -3311,6 +3311,25 @@ ctables_cell_compare_3way (const void *a_, const void *b_, const void *aux_)
   return 0;
 }
 
+static int
+ctables_cell_compare_leaf_3way (const void *a_, const void *b_,
+                                const void *aux UNUSED)
+{
+  struct ctables_cell *const *ap = a_;
+  struct ctables_cell *const *bp = b_;
+  const struct ctables_cell *a = *ap;
+  const struct ctables_cell *b = *bp;
+
+  for (enum pivot_axis_type axis = 0; axis < PIVOT_N_AXES; axis++)
+    {
+      int al = a->axes[axis].leaf;
+      int bl = b->axes[axis].leaf;
+      if (al != bl)
+        return al > bl ? 1 : -1;
+    }
+  return 0;
+}
+
 /* Algorithm:
 
    For each row:
@@ -4412,7 +4431,7 @@ ctables_table_output (struct ctables *ct, struct ctables_table *t)
               {
                 struct ctables_section *s = &t->sections[j];
                 sections[n_sections++] = s;
-                n_total_cells += s->cells.count;
+                n_total_cells += hmap_count (&s->cells);
 
                 size_t depth = s->nests[a]->n;
                 max_depth = MAX (depth, max_depth);
@@ -4436,6 +4455,24 @@ ctables_table_output (struct ctables *ct, struct ctables_table *t)
           struct ctables_cell_sort_aux aux = { .nest = nest, .a = a };
           sort (sorted, n_sorted, sizeof *sorted, ctables_cell_compare_3way, &aux);
 
+#if 0
+          if (a == PIVOT_AXIS_ROW)
+            {
+              size_t ids[N_CTDTS];
+              memset (ids, 0, sizeof ids);
+              for (size_t j = 0; j < n_sorted; j++)
+                {
+                  struct ctables_cell *cell = sorted[j];
+                  for (enum ctables_domain_type dt = 0; dt < N_CTDTS; dt++)
+                    {
+                      struct ctables_domain *domain = cell->domains[dt];
+                      if (!domain->sequence)
+                        domain->sequence = ++ids[dt];
+                    }
+                }
+            }
+#endif
+
 #if 0
           for (size_t j = 0; j < n_sorted; j++)
             {
@@ -4517,19 +4554,6 @@ ctables_table_output (struct ctables *ct, struct ctables_table *t)
               struct ctables_cell *cell = sorted[j];
               struct ctables_cell *prev = j > 0 ? sorted[j - 1] : NULL;
 
-              struct ctables_domain *domain = cell->domains[CTDT_SUBTABLE];
-              if (!domain->sequence)
-                {
-                  static int x;
-                  domain->sequence = ++x;
-                }
-              domain = cell->domains[CTDT_TABLE];
-              if (!domain->sequence)
-                {
-                  static int x;
-                  domain->sequence = ++x;
-                }
-
               size_t n_common = 0;
               if (j > 0)
                 {
@@ -4606,6 +4630,40 @@ ctables_table_output (struct ctables *ct, struct ctables_table *t)
         }
     }
 
+  {
+    size_t n_total_cells = 0;
+    for (size_t j = 0; j < t->n_sections; j++)
+      n_total_cells += hmap_count (&t->sections[j].cells);
+
+    struct ctables_cell **sorted = xnmalloc (n_total_cells, sizeof *sorted);
+    size_t n_sorted = 0;
+    for (size_t j = 0; j < t->n_sections; j++)
+      {
+        const struct ctables_section *s = &t->sections[j];
+        struct ctables_cell *cell;
+        HMAP_FOR_EACH (cell, struct ctables_cell, node, &s->cells)
+          if (!cell->hide)
+            sorted[n_sorted++] = cell;
+      }
+    assert (n_sorted <= n_total_cells);
+    sort (sorted, n_sorted, sizeof *sorted, ctables_cell_compare_leaf_3way,
+          NULL);
+    size_t ids[N_CTDTS];
+    memset (ids, 0, sizeof ids);
+    for (size_t j = 0; j < n_sorted; j++)
+      {
+        struct ctables_cell *cell = sorted[j];
+        for (enum ctables_domain_type dt = 0; dt < N_CTDTS; dt++)
+          {
+            struct ctables_domain *domain = cell->domains[dt];
+            if (!domain->sequence)
+              domain->sequence = ++ids[dt];
+          }
+      }
+
+    free (sorted);
+  }
+
   for (size_t i = 0; i < t->n_sections; i++)
     {
       struct ctables_section *s = &t->sections[i];
index 2cf5f9658a40dc462e80c3f32f95ecec3faa5526..e039cfd3ce67b73d19c763a152224e35f3d33ac0 100644 (file)
@@ -95,13 +95,13 @@ S(CTSF_ULAYERROWPCT_SUM, "ULAYERROWPCT.SUM", N_("Unweighted Layer Row Sum %"), C
 S(CTSF_ULAYERCOLPCT_SUM, "ULAYERCOLPCT.SUM", N_("Unweighted Layer Column Sum %"), CTF_PERCENT, CTFA_SCALE)
 
 /* Debugging and troubleshooting. */
-S(CTSF_ROW_ID, "ROW.ID", N_("Row ID"), CTF_GENERAL, CTFA_ALL)
-S(CTSF_COL_ID, "COL.ID", N_("Column ID"), CTF_GENERAL, CTFA_ALL)
-S(CTSF_TABLE_ID, "TABLE.ID", N_("Table ID"), CTF_GENERAL, CTFA_ALL)
-S(CTSF_SUBTABLE_ID, "SUBTABLE.ID", N_("Subtable ID"), CTF_GENERAL, CTFA_ALL)
-S(CTSF_LAYER_ID, "LAYER.ID", N_("Layer ID"), CTF_GENERAL, CTFA_ALL)
-S(CTSF_LAYERROW_ID, "LAYERROW.ID", N_("Layer Row ID"), CTF_GENERAL, CTFA_ALL)
-S(CTSF_LAYERCOL_ID, "LAYERCOL.ID", N_("Layer Column ID"), CTF_GENERAL, CTFA_ALL)
+S(CTSF_ROW_ID, "ROW.ID", N_("Row ID"), CTF_COUNT, CTFA_ALL)
+S(CTSF_COL_ID, "COL.ID", N_("Column ID"), CTF_COUNT, CTFA_ALL)
+S(CTSF_TABLE_ID, "TABLE.ID", N_("Table ID"), CTF_COUNT, CTFA_ALL)
+S(CTSF_SUBTABLE_ID, "SUBTABLE.ID", N_("Subtable ID"), CTF_COUNT, CTFA_ALL)
+S(CTSF_LAYER_ID, "LAYER.ID", N_("Layer ID"), CTF_COUNT, CTFA_ALL)
+S(CTSF_LAYERROW_ID, "LAYERROW.ID", N_("Layer Row ID"), CTF_COUNT, CTFA_ALL)
+S(CTSF_LAYERCOL_ID, "LAYERCOL.ID", N_("Layer Column ID"), CTF_COUNT, CTFA_ALL)
 
 #if 0         /* Multiple response sets not yet implemented. */
 S(CTSF_RESPONSES, "RESPONSES", N_("Responses"), CTF_COUNT, CTFA_MRSETS)
index e9ab6d2187b71615d3277e603be8b328bdc42e25..efb59ca23a6d6521a54afbc8246ae9aa61c882f0 100644 (file)
@@ -2535,6 +2535,174 @@ Generated HH:MM:SS on MM/DD/YY
 ])
 AT_CLEANUP
 
+AT_SETUP([CTABLES area definitions])
+AT_CHECK([ln $top_srcdir/examples/nhtsa.sav . || cp $top_srcdir/examples/nhtsa.sav .])
+AT_DATA([ctables.sps],
+[[GET 'nhtsa.sav'.
+CTABLES
+    /VLABELS VARIABLES=ALL DISPLAY=NAME
+    /TABLE qn61 > qn57 BY qnd7a > qn86 + qn64b BY qns3a[TABLE.ID, LAYER.ID, SUBTABLE.ID]
+    /SLABELS POSITION=ROW
+    /TABLE qn61 > qn57 BY qnd7a > qn86 + qn64b BY qns3a[ROW.ID, LAYERROW.ID]
+    /SLABELS POSITION=ROW
+    /TABLE qn61 > qn57 BY qnd7a > qn86 + qn64b BY qns3a[COL.ID, LAYERCOL.ID]
+    /SLABELS POSITION=ROW.
+]])
+AT_CHECK([pspp ctables.sps --table-look="$builddir"/all-layers.stt -O box=unicode -O width=80], [0], [dnl
+                    Custom Tables
+Male
+╭─────────────────────────────┬─────────────┬──────╮
+│                             │    QND7A    │ QN64B│
+│                             ├──────┬──────┼───┬──┤
+│                             │  Yes │  No  │   │  │
+│                             ├──────┼──────┤   │  │
+│                             │ QN86 │ QN86 │   │  │
+│                             ├───┬──┼───┬──┤   │  │
+│                             │Yes│No│Yes│No│Yes│No│
+├─────────────────────────────┼───┼──┼───┼──┼───┼──┤
+│QN61 Yes QN57 Yes Table ID   │  1│ 1│  1│ 1│  2│ 2│
+│                  Layer ID   │  1│ 1│  1│ 1│  2│ 2│
+│                  Subtable ID│  1│ 1│  2│ 2│  3│ 3│
+│             ╶───────────────┼───┼──┼───┼──┼───┼──┤
+│              No  Table ID   │  1│ 1│  1│ 1│  2│ 2│
+│                  Layer ID   │  1│ 1│  1│ 1│  2│ 2│
+│                  Subtable ID│  1│ 1│  2│ 2│  3│ 3│
+│    ╶────────────────────────┼───┼──┼───┼──┼───┼──┤
+│     No  QN57 Yes Table ID   │  1│ 1│  1│ 1│  2│ 2│
+│                  Layer ID   │  1│ 1│  1│ 1│  2│ 2│
+│                  Subtable ID│  4│ 4│  5│ 5│  6│ 6│
+│             ╶───────────────┼───┼──┼───┼──┼───┼──┤
+│              No  Table ID   │  1│ 1│  1│ 1│  2│ 2│
+│                  Layer ID   │  1│ 1│  1│ 1│  2│ 2│
+│                  Subtable ID│  4│ 4│  5│ 5│  6│ 6│
+╰─────────────────────────────┴───┴──┴───┴──┴───┴──╯
+
+                    Custom Tables
+Female
+╭─────────────────────────────┬─────────────┬──────╮
+│                             │    QND7A    │ QN64B│
+│                             ├──────┬──────┼───┬──┤
+│                             │  Yes │  No  │   │  │
+│                             ├──────┼──────┤   │  │
+│                             │ QN86 │ QN86 │   │  │
+│                             ├───┬──┼───┬──┤   │  │
+│                             │Yes│No│Yes│No│Yes│No│
+├─────────────────────────────┼───┼──┼───┼──┼───┼──┤
+│QN61 Yes QN57 Yes Table ID   │  1│ 1│  1│ 1│  2│ 2│
+│                  Layer ID   │  3│ 3│  3│ 3│  4│ 4│
+│                  Subtable ID│  7│ 7│  8│ 8│  9│ 9│
+│             ╶───────────────┼───┼──┼───┼──┼───┼──┤
+│              No  Table ID   │  1│ 1│  1│ 1│  2│ 2│
+│                  Layer ID   │  3│ 3│  3│ 3│  4│ 4│
+│                  Subtable ID│  7│ 7│  8│ 8│  9│ 9│
+│    ╶────────────────────────┼───┼──┼───┼──┼───┼──┤
+│     No  QN57 Yes Table ID   │  1│ 1│  1│ 1│  2│ 2│
+│                  Layer ID   │  3│ 3│  3│ 3│  4│ 4│
+│                  Subtable ID│ 10│10│ 11│11│ 12│12│
+│             ╶───────────────┼───┼──┼───┼──┼───┼──┤
+│              No  Table ID   │  1│ 1│  1│ 1│  2│ 2│
+│                  Layer ID   │  3│ 3│  3│ 3│  4│ 4│
+│                  Subtable ID│ 10│10│ 11│11│ 12│12│
+╰─────────────────────────────┴───┴──┴───┴──┴───┴──╯
+
+                    Custom Tables
+Male
+╭──────────────────────────────┬─────────────┬──────╮
+│                              │    QND7A    │ QN64B│
+│                              ├──────┬──────┼───┬──┤
+│                              │  Yes │  No  │   │  │
+│                              ├──────┼──────┤   │  │
+│                              │ QN86 │ QN86 │   │  │
+│                              ├───┬──┼───┬──┤   │  │
+│                              │Yes│No│Yes│No│Yes│No│
+├──────────────────────────────┼───┼──┼───┼──┼───┼──┤
+│QN61 Yes QN57 Yes Row ID      │  1│ 1│  2│ 2│  3│ 3│
+│                  Layer Row ID│  1│ 1│  1│ 1│  2│ 2│
+│             ╶────────────────┼───┼──┼───┼──┼───┼──┤
+│              No  Row ID      │  4│ 4│  5│ 5│  6│ 6│
+│                  Layer Row ID│  3│ 3│  3│ 3│  4│ 4│
+│    ╶─────────────────────────┼───┼──┼───┼──┼───┼──┤
+│     No  QN57 Yes Row ID      │  7│ 7│  8│ 8│  9│ 9│
+│                  Layer Row ID│  5│ 5│  5│ 5│  6│ 6│
+│             ╶────────────────┼───┼──┼───┼──┼───┼──┤
+│              No  Row ID      │ 10│10│ 11│11│ 12│12│
+│                  Layer Row ID│  7│ 7│  7│ 7│  8│ 8│
+╰──────────────────────────────┴───┴──┴───┴──┴───┴──╯
+
+                    Custom Tables
+Female
+╭──────────────────────────────┬─────────────┬──────╮
+│                              │    QND7A    │ QN64B│
+│                              ├──────┬──────┼───┬──┤
+│                              │  Yes │  No  │   │  │
+│                              ├──────┼──────┤   │  │
+│                              │ QN86 │ QN86 │   │  │
+│                              ├───┬──┼───┬──┤   │  │
+│                              │Yes│No│Yes│No│Yes│No│
+├──────────────────────────────┼───┼──┼───┼──┼───┼──┤
+│QN61 Yes QN57 Yes Row ID      │ 13│13│ 14│14│ 15│15│
+│                  Layer Row ID│  9│ 9│  9│ 9│ 10│10│
+│             ╶────────────────┼───┼──┼───┼──┼───┼──┤
+│              No  Row ID      │ 16│16│ 17│17│ 18│18│
+│                  Layer Row ID│ 11│11│ 11│11│ 12│12│
+│    ╶─────────────────────────┼───┼──┼───┼──┼───┼──┤
+│     No  QN57 Yes Row ID      │ 19│19│ 20│20│ 21│21│
+│                  Layer Row ID│ 13│13│ 13│13│ 14│14│
+│             ╶────────────────┼───┼──┼───┼──┼───┼──┤
+│              No  Row ID      │ 22│22│ 23│23│ 24│24│
+│                  Layer Row ID│ 15│15│ 15│15│ 16│16│
+╰──────────────────────────────┴───┴──┴───┴──┴───┴──╯
+
+                      Custom Tables
+Male
+╭─────────────────────────────────┬─────────────┬──────╮
+│                                 │    QND7A    │ QN64B│
+│                                 ├──────┬──────┼───┬──┤
+│                                 │  Yes │  No  │   │  │
+│                                 ├──────┼──────┤   │  │
+│                                 │ QN86 │ QN86 │   │  │
+│                                 ├───┬──┼───┬──┤   │  │
+│                                 │Yes│No│Yes│No│Yes│No│
+├─────────────────────────────────┼───┼──┼───┼──┼───┼──┤
+│QN61 Yes QN57 Yes Column ID      │  1│ 2│  3│ 4│  5│ 6│
+│                  Layer Column ID│  1│ 2│  3│ 4│  5│ 6│
+│             ╶───────────────────┼───┼──┼───┼──┼───┼──┤
+│              No  Column ID      │  1│ 2│  3│ 4│  5│ 6│
+│                  Layer Column ID│  1│ 2│  3│ 4│  5│ 6│
+│    ╶────────────────────────────┼───┼──┼───┼──┼───┼──┤
+│     No  QN57 Yes Column ID      │  7│ 8│  9│10│ 11│12│
+│                  Layer Column ID│  1│ 2│  3│ 4│  5│ 6│
+│             ╶───────────────────┼───┼──┼───┼──┼───┼──┤
+│              No  Column ID      │  7│ 8│  9│10│ 11│12│
+│                  Layer Column ID│  1│ 2│  3│ 4│  5│ 6│
+╰─────────────────────────────────┴───┴──┴───┴──┴───┴──╯
+
+                      Custom Tables
+Female
+╭─────────────────────────────────┬─────────────┬──────╮
+│                                 │    QND7A    │ QN64B│
+│                                 ├──────┬──────┼───┬──┤
+│                                 │  Yes │  No  │   │  │
+│                                 ├──────┼──────┤   │  │
+│                                 │ QN86 │ QN86 │   │  │
+│                                 ├───┬──┼───┬──┤   │  │
+│                                 │Yes│No│Yes│No│Yes│No│
+├─────────────────────────────────┼───┼──┼───┼──┼───┼──┤
+│QN61 Yes QN57 Yes Column ID      │ 13│14│ 15│16│ 17│18│
+│                  Layer Column ID│  7│ 8│  9│10│ 11│12│
+│             ╶───────────────────┼───┼──┼───┼──┼───┼──┤
+│              No  Column ID      │ 13│14│ 15│16│ 17│18│
+│                  Layer Column ID│  7│ 8│  9│10│ 11│12│
+│    ╶────────────────────────────┼───┼──┼───┼──┼───┼──┤
+│     No  QN57 Yes Column ID      │ 19│20│ 21│22│ 23│24│
+│                  Layer Column ID│  7│ 8│  9│10│ 11│12│
+│             ╶───────────────────┼───┼──┼───┼──┼───┼──┤
+│              No  Column ID      │ 19│20│ 21│22│ 23│24│
+│                  Layer Column ID│  7│ 8│  9│10│ 11│12│
+╰─────────────────────────────────┴───┴──┴───┴──┴───┴──╯
+])
+AT_CLEANUP
+
 AT_SETUP([CTABLES summary functions])
 AT_CHECK([ln $top_srcdir/examples/nhtsa.sav . || cp $top_srcdir/examples/nhtsa.sav .])
 AT_DATA([ctables.sps],
@@ -2545,3 +2713,4 @@ CTABLES
 ]])
 AT_CHECK([pspp ctables.sps --table-look="$builddir"/all-layers.stt -O box=unicode -O width=120], [0], [])
 AT_CLEANUP
+