From daf83021bebf527fa36e5f7a4accd71e09315e26 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Sat, 1 Jan 2022 10:09:12 -0800 Subject: [PATCH] work --- src/language/stats/ctables.c | 173 +++++++++++++++++++++++------------ 1 file changed, 116 insertions(+), 57 deletions(-) diff --git a/src/language/stats/ctables.c b/src/language/stats/ctables.c index 30ce9db8ab..8cf79c0123 100644 --- a/src/language/stats/ctables.c +++ b/src/language/stats/ctables.c @@ -1672,7 +1672,7 @@ ctables_summary_add (union ctables_summary *s, } -static double +static double UNUSED ctables_summary_value (union ctables_summary *s, const struct ctables_summary_spec *ss) { @@ -1814,7 +1814,6 @@ struct ctables_freqtab const struct ctables_summary_spec *summaries; size_t n_summaries; const struct variable *summary_var; - struct ctables_freq **sorted; }; static struct ctables_freq * @@ -1837,17 +1836,28 @@ ctables_freq_add (struct ctables_freqtab *ft, struct ctables_freq *f, var, value, weight); } +struct ctables_axis_render + { + size_t ofs; + struct variable **vars; + size_t n_vars; + + struct ctables_freq **freqs; + size_t n_freqs; + }; + static int -ctables_freq_compare_3way (const void *a_, const void *b_, const void *vars_) +ctables_freq_compare_3way (const void *a_, const void *b_, const void *ar_) { - const struct var_array *vars = vars_; + const struct ctables_axis_render *ar = ar_; struct ctables_freq *const *a = a_; struct ctables_freq *const *b = b_; - for (size_t i = 0; i < vars->n; i++) + for (size_t i = 0; i < ar->n_vars; i++) { - int cmp = value_compare_3way (&(*a)->values[i], &(*b)->values[i], - var_get_width (vars->vars[i])); + int cmp = value_compare_3way (&(*a)->values[i + ar->ofs], + &(*b)->values[i + ar->ofs], + var_get_width (ar->vars[i])); if (cmp) return cmp; } @@ -2011,70 +2021,119 @@ ctables_execute (struct dataset *ds, struct ctables *ct) struct ctables_table *t = &ct->tables[i]; struct pivot_table *pt = pivot_table_create (N_("Custom Tables")); - struct pivot_dimension *d = pivot_dimension_create ( - pt, PIVOT_AXIS_ROW, N_("Rows")); + pivot_table_set_look (pt, ct->look); + struct pivot_dimension *d[PIVOT_N_AXES]; + for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++) + { + static const char *names[] = { + [PIVOT_AXIS_ROW] = N_("Rows"), + [PIVOT_AXIS_COLUMN] = N_("Columns"), + [PIVOT_AXIS_LAYER] = N_("Layers"), + }; + d[a] = (t->axes[a] || a == t->slabels_position + ? pivot_dimension_create (pt, a, names[a]) + : NULL); + } for (size_t j = 0; j < t->n_fts; j++) { struct ctables_freqtab *ft = t->fts[j]; - ft->sorted = xnmalloc (ft->data.count, sizeof *ft->sorted); - - struct ctables_freq *f; - size_t n = 0; - HMAP_FOR_EACH (f, struct ctables_freq, node, &ft->data) - ft->sorted[n++] = f; - assert (n == ft->data.count); - sort (ft->sorted, n, sizeof *ft->sorted, - ctables_freq_compare_3way, &ft->vars); - - struct pivot_category **groups = xnmalloc (ft->vars.n, - sizeof *groups); - for (size_t k = 0; k < n; k++) + + struct ctables_axis_render axis_renders[PIVOT_N_AXES]; + + for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++) { - struct ctables_freq *prev = k > 0 ? ft->sorted[k - 1] : NULL; - struct ctables_freq *f = ft->sorted[k]; - - size_t n_common = 0; - if (prev) - for (; n_common + 1 < ft->vars.n; n_common++) - if (!value_equal (&prev->values[n_common], - &f->values[n_common], - var_get_type (ft->vars.vars[n_common]))) + size_t ofs = 0; + struct variable **vars = NULL; + size_t n = 0; + for (size_t k = 0; k < ft->vars.n; k++) + if (ft->vars.axes[k] == a) + { + ofs = k; + vars = &ft->vars.vars[k]; + for (n = 1; k + n < ft->vars.n; n++) + if (ft->vars.axes[k + n] != a) + break; break; + } - for (size_t m = n_common; m < ft->vars.n; m++) - { - struct pivot_category *parent = m > 0 ? groups[m - 1] : d->root; - const struct variable *var = ft->vars.vars[m]; - enum ctables_vlabel vlabel = ct->vlabels[var_get_dict_index (var)]; + struct ctables_axis_render *ar = &axis_renders[a]; + *ar = (struct ctables_axis_render) { + .ofs = ofs, + .vars = vars, + .n_vars = n + }; + printf ("axis %s: %zu variables\n", pivot_axis_type_to_string (a), n); + if (!n) + continue; - if (vlabel != CTVL_NONE) - parent = pivot_category_create_group__ ( - parent, pivot_value_new_variable (ft->vars.vars[m])); + ar->freqs = xnmalloc (ft->data.count, sizeof *ar->freqs); - if (m + 1 < ft->vars.n) - parent = pivot_category_create_group__ ( - parent, - pivot_value_new_var_value (ft->vars.vars[m], &f->values[m])); - groups[m] = parent; + struct ctables_freq *f; + size_t n_freqs = 0; + HMAP_FOR_EACH (f, struct ctables_freq, node, &ft->data) + ar->freqs[n_freqs++] = f; + assert (n_freqs == ft->data.count); + ar->n_freqs = sort_unique (ar->freqs, n_freqs, sizeof *ar->freqs, + ctables_freq_compare_3way, ar); + } - if (m == ft->vars.n - 1) + for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++) + { + struct ctables_axis_render *ar = &axis_renders[a]; + if (!ar->n_vars && a != t->slabels_position) + continue; + + struct pivot_category **groups = xnmalloc (ar->n_vars, + sizeof *groups); + for (size_t k = 0; k < ar->n_freqs; k++) + { + struct ctables_freq *prev = k > 0 ? ar->freqs[k - 1] : NULL; + struct ctables_freq *f = ar->freqs[k]; + + size_t n_common = 0; + if (prev) + for (; n_common + 1 < ar->n_vars; n_common++) + if (!value_equal (&prev->values[ar->ofs + n_common], + &f->values[ar->ofs + n_common], + var_get_type (ar->vars[n_common]))) + break; + + for (size_t m = n_common; m < ar->n_vars; m++) { - struct pivot_category *c = pivot_category_create_group__ ( - parent, - pivot_value_new_var_value (ft->vars.vars[ft->vars.n - 1], - &f->values[ft->vars.n - 1])); - for (size_t p = 0; p < ft->n_summaries; p++) + struct pivot_category *parent = m > 0 ? groups[m - 1] : d[a]->root; + const struct variable *var = ar->vars[m]; + enum ctables_vlabel vlabel = ct->vlabels[var_get_dict_index (var)]; + + if (vlabel != CTVL_NONE) + parent = pivot_category_create_group__ ( + parent, pivot_value_new_variable (ar->vars[m])); + + if (m + 1 < ar->n_vars) + parent = pivot_category_create_group__ ( + parent, + pivot_value_new_var_value (ar->vars[m], &f->values[m])); + groups[m] = parent; + + if (m == ar->n_vars - 1) { - double value = ctables_summary_value ( - &f->summaries[p], &ft->summaries[p]); - int leaf = pivot_category_create_leaf ( - c, pivot_value_new_text (ft->summaries[p].label)); - pivot_table_put1 (pt, leaf, pivot_value_new_number (value)); + pivot_category_create_leaf ( + parent, + pivot_value_new_var_value (ar->vars[ar->n_vars - 1], + &f->values[ar->ofs + ar->n_vars - 1])); +#if 0 + for (size_t p = 0; p < ft->n_summaries; p++) + { + if (a == t->slabels_position) + pivot_category_create_leaf ( + c, pivot_value_new_text (ft->summaries[p].label)); + //pivot_table_put1 (pt, leaf, pivot_value_new_number (value)); + } +#endif } } } + free (groups); } - free (groups); } pivot_table_submit (pt); } @@ -2101,7 +2160,6 @@ ctables_execute (struct dataset *ds, struct ctables *ct) free (f); } hmap_destroy (&ft->data); - free (ft->sorted); var_array_uninit (&ft->vars); free (ft); } @@ -2127,6 +2185,7 @@ cmd_ctables (struct lexer *lexer, struct dataset *ds) .vlabels = vlabels, .hide_threshold = 5, }; + ct->look->omit_empty = false; if (!lex_force_match (lexer, T_SLASH)) goto error; -- 2.30.2