X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Flanguage%2Fstats%2Fctables.c;h=4f23b3607d46aab491e832c407bc1a00ad8a40cd;hb=75943041c08afda14867f3b6d14a416170825418;hp=bef413a879d65d19aba3e3e546ae19ad42f00299;hpb=29d19f18fb7945787910160eb17ced6856448623;p=pspp diff --git a/src/language/stats/ctables.c b/src/language/stats/ctables.c index bef413a879..4f23b3607d 100644 --- a/src/language/stats/ctables.c +++ b/src/language/stats/ctables.c @@ -224,9 +224,12 @@ enum ctables_label_position struct var_array { - const struct ctables_axis *summary; struct variable **vars; size_t n; + + struct ctables_summary_spec *summaries; + size_t n_summaries; + struct variable *summary_var; }; struct var_array2 @@ -239,6 +242,7 @@ struct ctables_table { struct ctables_axis *axes[PIVOT_N_AXES]; struct var_array2 vaas[PIVOT_N_AXES]; + enum pivot_axis_type summary_axis; struct hmap ft; enum pivot_axis_type slabels_position; @@ -616,6 +620,21 @@ ctables_summary_default_format (enum ctables_summary_function function, } } +static char * +ctables_summary_default_label (enum ctables_summary_function function, + double percentile) +{ + static const char *default_labels[] = { +#define S(ENUM, NAME, LABEL, FORMAT, AVAILABILITY) [ENUM] = LABEL, + SUMMARIES +#undef S + }; + + return (function == CTSF_PTILE + ? xasprintf (_("Percentile %.2f"), percentile) + : xstrdup (gettext (default_labels[function]))); +} + static const char * ctables_summary_function_name (enum ctables_summary_function function) { @@ -792,17 +811,8 @@ ctables_axis_parse_postfix (struct ctables_axis_parse_ctx *ctx) label = ss_xstrdup (lex_tokss (ctx->lexer)); lex_get (ctx->lexer); } - else if (function == CTSF_PTILE) - label = xasprintf (_("Percentile %.2f"), percentile); else - { - static const char *default_labels[] = { -#define S(ENUM, NAME, LABEL, FORMAT, AVAILABILITY) [ENUM] = LABEL, - SUMMARIES -#undef S - }; - label = xstrdup (gettext (default_labels[function])); - } + label = ctables_summary_default_label (function, percentile); /* Parse format. */ struct fmt_spec format; @@ -1299,11 +1309,19 @@ nest_fts (struct var_array2 va0, struct var_array2 va1) vars[n++] = b->vars[k]; assert (n == allocate); - assert (!(a->summary && b->summary)); + const struct var_array *summary_src; + if (!a->summary_var) + summary_src = b; + else if (!b->summary_var) + summary_src = a; + else + NOT_REACHED (); vaa.vas[vaa.n++] = (struct var_array) { - .summary = a->summary ? a->summary : b->summary, .vars = vars, - .n = n + .n = n, + .summaries = summary_src->summaries, + .n_summaries = summary_src->n_summaries, + .summary_var = summary_src->summary_var, }; } var_array2_uninit (&va0); @@ -1346,7 +1364,12 @@ enumerate_fts (enum pivot_axis_type axis_type, const struct ctables_axis *a) *axes = axis_type; *va = (struct var_array) { .vars = vars, .n = 1 }; } - va->summary = a->scale || a->n_summaries ? a : NULL; + if (a->n_summaries || a->scale) + { + va->summaries = a->summaries; + va->n_summaries = a->n_summaries; + va->summary_var = a->var.var; + } return (struct var_array2) { .vas = va, .n = 1 }; case CTAO_STACK: @@ -1798,6 +1821,7 @@ struct ctables_freq { size_t vaa_idx; union value *values; + int leaf; } axes[PIVOT_N_AXES]; @@ -1951,6 +1975,28 @@ ctables_execute (struct dataset *ds, struct ctables *ct) *va = (struct var_array) { .n = 0 }; t->vaas[a] = (struct var_array2) { .vas = va, .n = 1 }; } + + for (size_t i = 0; i < t->vaas[t->summary_axis].n; i++) + { + struct var_array *va = &t->vaas[t->summary_axis].vas[i]; + if (!va->n_summaries) + { + va->summaries = xmalloc (sizeof *va->summaries); + va->n_summaries = 1; + + enum ctables_summary_function function + = va->summary_var ? CTSF_MEAN : CTSF_COUNT; + struct ctables_var var = { .is_mrset = false, .var = va->summary_var }; + + *va->summaries = (struct ctables_summary_spec) { + .function = function, + .format = ctables_summary_default_format (function, &var), + .label = ctables_summary_default_label (function, 0), + }; + if (!va->summary_var) + va->summary_var = va->vars[0]; + } + } } struct casereader *input = casereader_create_filter_weight (proc_open (ds), @@ -1989,12 +2035,14 @@ ctables_execute (struct dataset *ds, struct ctables *ct) [PIVOT_AXIS_COLUMN] = N_("Columns"), [PIVOT_AXIS_LAYER] = N_("Layers"), }; - d[a] = (t->axes[a] + d[a] = (t->axes[a] || a == t->summary_axis ? pivot_dimension_create (pt, a, names[a]) : NULL); if (!d[a]) continue; + assert (t->axes[a]); + struct ctables_freq **sorted = xnmalloc (t->ft.count, sizeof *sorted); struct ctables_freq *f; @@ -2004,7 +2052,7 @@ ctables_execute (struct dataset *ds, struct ctables *ct) assert (n == t->ft.count); struct ctables_freq_sort_aux aux = { .t = t, .a = a }; - n = sort_unique (sorted, n, sizeof *sorted, ctables_freq_compare_3way, &aux); + sort (sorted, n, sizeof *sorted, ctables_freq_compare_3way, &aux); size_t max_depth = 0; for (size_t j = 0; j < t->vaas[a].n; j++) @@ -2013,6 +2061,7 @@ ctables_execute (struct dataset *ds, struct ctables *ct) struct pivot_category **groups = xnmalloc (max_depth, sizeof *groups); struct pivot_category *top = NULL; + int prev_leaf = 0; for (size_t j = 0; j < n; j++) { struct ctables_freq *f = sorted[j]; @@ -2036,45 +2085,73 @@ ctables_execute (struct dataset *ds, struct ctables *ct) } else new_subtable = true; + if (new_subtable) - top = pivot_category_create_group__ ( - d[a]->root, pivot_value_new_variable (va->vars[0])); - printf ("n_common=%zu\n", n_common); + { + enum ctables_vlabel vlabel = ct->vlabels[var_get_dict_index (va->vars[0])]; + top = d[a]->root; + if (vlabel != CTVL_NONE) + top = pivot_category_create_group__ ( + top, pivot_value_new_variable (va->vars[0])); + } + if (n_common == va->n) + { + f->axes[a].leaf = prev_leaf; + continue; + } for (size_t k = n_common; k < va->n; k++) { struct pivot_category *parent = k > 0 ? groups[k - 1] : top; + struct pivot_value *label = pivot_value_new_var_value ( + va->vars[k], &f->axes[a].values[k]); + if (k == va->n - 1) { - pivot_category_create_leaf ( - parent, - pivot_value_new_var_value (va->vars[va->n - 1], - &f->axes[a].values[va->n - 1])); + if (a == t->summary_axis) + { + parent = pivot_category_create_group__ (parent, label); + for (size_t m = 0; m < va->n_summaries; m++) + { + int leaf = pivot_category_create_leaf ( + parent, pivot_value_new_text (va->summaries[m].label)); + if (m == 0) + prev_leaf = leaf; + } + } + else + prev_leaf = pivot_category_create_leaf (parent, label); break; } - parent = pivot_category_create_group__ ( - parent, - pivot_value_new_var_value (va->vars[k], &f->axes[a].values[k])); + parent = pivot_category_create_group__ (parent, label); - parent = pivot_category_create_group__ ( - parent, pivot_value_new_variable (va->vars[k])); + enum ctables_vlabel vlabel = ct->vlabels[var_get_dict_index (va->vars[k + 1])]; + if (vlabel != CTVL_NONE) + parent = pivot_category_create_group__ ( + parent, pivot_value_new_variable (va->vars[k + 1])); groups[k] = parent; - -#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 - } } + + f->axes[a].leaf = prev_leaf; + } + free (sorted); free (groups); } + struct ctables_freq *f; + HMAP_FOR_EACH (f, struct ctables_freq, node, &t->ft) + { + size_t dindexes[3]; + size_t n_dindexes = 0; + + for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++) + if (d[a]) + dindexes[n_dindexes++] = f->axes[a].leaf; + pivot_table_put (pt, dindexes, n_dindexes, + pivot_value_new_number (f->count)); + } + pivot_table_submit (pt); } @@ -2363,26 +2440,57 @@ cmd_ctables (struct lexer *lexer, struct dataset *ds) const struct ctables_axis *scales[PIVOT_N_AXES]; size_t n_scales = 0; - for (size_t i = 0; i < 3; i++) + for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++) { - scales[i] = find_scale (t->axes[i]); - if (scales[i]) + scales[a] = find_scale (t->axes[a]); + if (scales[a]) n_scales++; } if (n_scales > 1) { - msg (SE, _("Scale variables may appear only on one dimension.")); + msg (SE, _("Scale variables may appear only on one axis.")); if (scales[PIVOT_AXIS_ROW]) msg_at (SN, scales[PIVOT_AXIS_ROW]->loc, - _("This scale variable appears in the rows dimension.")); + _("This scale variable appears on the rows axis.")); if (scales[PIVOT_AXIS_COLUMN]) msg_at (SN, scales[PIVOT_AXIS_COLUMN]->loc, - _("This scale variable appears in the columns dimension.")); + _("This scale variable appears on the columns axis.")); if (scales[PIVOT_AXIS_LAYER]) msg_at (SN, scales[PIVOT_AXIS_LAYER]->loc, - _("This scale variable appears in the layer dimension.")); + _("This scale variable appears on the layer axis.")); + goto error; + } + + const struct ctables_axis *summaries[PIVOT_N_AXES]; + size_t n_summaries = 0; + for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++) + { + summaries[a] = (scales[a] + ? scales[a] + : find_categorical_summary_spec (t->axes[a])); + if (summaries[a]) + n_summaries++; + } + if (n_summaries > 1) + { + msg (SE, _("Summaries may appear only on one axis.")); + if (summaries[PIVOT_AXIS_ROW]) + msg_at (SN, summaries[PIVOT_AXIS_ROW]->loc, + _("This variable on the rows axis has a summary.")); + if (summaries[PIVOT_AXIS_COLUMN]) + msg_at (SN, summaries[PIVOT_AXIS_COLUMN]->loc, + _("This variable on the columns axis has a summary.")); + if (summaries[PIVOT_AXIS_LAYER]) + msg_at (SN, summaries[PIVOT_AXIS_LAYER]->loc, + _("This variable on the layers axis has a summary.")); goto error; } + for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++) + if (n_summaries ? summaries[a] : t->axes[a]) + { + t->summary_axis = a; + break; + } if (lex_token (lexer) == T_ENDCMD) break;