X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Flanguage%2Fstats%2Fctables.c;h=836a974d824dda2f6f00c7cffa96df4e4b97c559;hb=0891406f7c1039af8c769b8069691246566fd894;hp=1abbf8a667cb31134125a1d87b4f0c6b26dc7e49;hpb=d8b3292a8c12564dbc67e59f24d626dcfbf2e274;p=pspp diff --git a/src/language/stats/ctables.c b/src/language/stats/ctables.c index 1abbf8a667..836a974d82 100644 --- a/src/language/stats/ctables.c +++ b/src/language/stats/ctables.c @@ -735,12 +735,32 @@ static void ctables_axis_destroy (struct ctables_axis *); struct ctables_summary_spec { + /* The calculation to be performed. + + 'function' is the function to calculate. 'weighted' specifies whether + to use weighted or unweighted data (for functions that do not support a + choice, it must be true). 'calc_area' is the area over which the + calculation takes place (for functions that target only an individual + cell, it must be 0). For CTSF_PTILE only, 'percentile' is the + percentile between 0 and 100 (for other functions it must be 0). */ enum ctables_summary_function function; bool weighted; - enum ctables_area_type area; + enum ctables_area_type calc_area; double percentile; /* CTSF_PTILE only. */ - char *label; + /* How to display the result of the calculation. + + 'label' is a user-specified label, NULL if the user didn't specify + one. + + 'user_area' is usually the same as 'calc_area', but when category labels + are rotated from one axis to another it swaps rows and columns. + + 'format' is the format for displaying the output. If + 'is_ctables_format' is true, then 'format.type' is one of the special + CTEF_* formats instead of the standard ones. */ + char *label; + enum ctables_area_type user_area; struct fmt_spec format; bool is_ctables_format; /* Is 'format' one of CTEF_*? */ @@ -965,7 +985,7 @@ static const char * ctables_summary_label__ (const struct ctables_summary_spec *spec) { bool w = spec->weighted; - enum ctables_area_type a = spec->area; + enum ctables_area_type a = spec->user_area; switch (spec->function) { case CTSF_COUNT: @@ -1160,7 +1180,8 @@ add_summary_spec (struct ctables_axis *axis, *dst = (struct ctables_summary_spec) { .function = function, .weighted = weighted, - .area = area, + .calc_area = area, + .user_area = area, .percentile = percentile, .label = xstrdup_if_nonnull (label), .format = (format ? *format @@ -2726,25 +2747,25 @@ ctables_summary_value (const struct ctables_cell *cell, return s->count; case CTSF_areaID: - return cell->areas[ss->area]->sequence; + return cell->areas[ss->calc_area]->sequence; case CTSF_areaPCT_COUNT: { - const struct ctables_area *a = cell->areas[ss->area]; + const struct ctables_area *a = cell->areas[ss->calc_area]; double a_count = ss->weighted ? a->e_count : a->u_count; return a_count ? s->count / a_count * 100 : SYSMIS; } case CTSF_areaPCT_VALIDN: { - const struct ctables_area *a = cell->areas[ss->area]; + const struct ctables_area *a = cell->areas[ss->calc_area]; double a_valid = ss->weighted ? a->e_valid : a->u_valid; return a_valid ? s->count / a_valid * 100 : SYSMIS; } case CTSF_areaPCT_TOTALN: { - const struct ctables_area *a = cell->areas[ss->area]; + const struct ctables_area *a = cell->areas[ss->calc_area]; double a_total = ss->weighted ? a->e_total : a->u_total; return a_total ? s->count / a_total * 100 : SYSMIS; } @@ -2807,7 +2828,7 @@ ctables_summary_value (const struct ctables_cell *cell, if (weight == SYSMIS || mean == SYSMIS) return SYSMIS; - const struct ctables_area *a = cell->areas[ss->area]; + const struct ctables_area *a = cell->areas[ss->calc_area]; const struct ctables_sum *sum = &a->sums[ss->sum_var_idx]; double denom = ss->weighted ? sum->e_sum : sum->u_sum; return denom != 0 ? weight * mean / denom * 100 : SYSMIS; @@ -3499,8 +3520,8 @@ merge_item_compare_3way (const struct merge_item *a, const struct merge_item *b) return as->function > bs->function ? 1 : -1; else if (as->weighted != bs->weighted) return as->weighted > bs->weighted ? 1 : -1; - else if (as->area != bs->area) - return as->area > bs->area ? 1 : -1; + else if (as->calc_area != bs->calc_area) + return as->calc_area > bs->calc_area ? 1 : -1; else if (as->percentile != bs->percentile) return as->percentile < bs->percentile ? 1 : -1; @@ -3996,7 +4017,7 @@ ctables_cell_calculate_postcompute (const struct ctables_section *s, const struct ctables_summary_spec *ss2 = &pc->specs->specs[i]; if (ss->function == ss2->function && ss->weighted == ss2->weighted - && ss->area == ss2->area + && ss->calc_area == ss2->calc_area && ss->percentile == ss2->percentile) { *format = ss2->format; @@ -4575,6 +4596,33 @@ add_sum_var (struct variable *var, return (*n)++; } +static enum ctables_area_type +rotate_area (enum ctables_area_type area) +{ + return area; + switch (area) + { + case CTAT_TABLE: + case CTAT_LAYER: + case CTAT_SUBTABLE: + return area; + + case CTAT_LAYERROW: + return CTAT_LAYERCOL; + + case CTAT_LAYERCOL: + return CTAT_LAYERROW; + + case CTAT_ROW: + return CTAT_COL; + + case CTAT_COL: + return CTAT_ROW; + } + + NOT_REACHED (); +} + static void enumerate_sum_vars (const struct ctables_axis *a, struct variable ***sum_vars, size_t *n, size_t *allocated) @@ -4618,48 +4666,40 @@ ctables_prepare_table (struct ctables_table *t) nest->areas[at] = xmalloc (nest->n * sizeof *nest->areas[at]); nest->n_areas[at] = 0; - for (size_t k = 0; k < nest->n; k++) + bool add_vars = (at == CTAT_LAYER ? a == PIVOT_AXIS_LAYER + : at == CTAT_LAYERROW ? a != PIVOT_AXIS_COLUMN + : at == CTAT_LAYERCOL ? a != PIVOT_AXIS_ROW + : at == CTAT_TABLE ? false + : true); + if (add_vars) + for (size_t k = 0; k < nest->n; k++) + { + if (k == nest->scale_idx) + continue; + nest->areas[at][nest->n_areas[at]++] = k; + } + else if ((at == CTAT_COL || at == CTAT_LAYERCOL) && a == PIVOT_AXIS_ROW && t->label_axis[PIVOT_AXIS_ROW] == PIVOT_AXIS_COLUMN) { - if (k == nest->scale_idx) - continue; - - switch (at) + for (size_t k = nest->n - 1; k < nest->n; k--) { - case CTAT_TABLE: - continue; - - case CTAT_LAYER: - if (a != PIVOT_AXIS_LAYER) - continue; - break; - - case CTAT_SUBTABLE: - case CTAT_ROW: - case CTAT_COL: - if (at == CTAT_SUBTABLE ? a != PIVOT_AXIS_LAYER - : at == CTAT_ROW ? a == PIVOT_AXIS_COLUMN - : a == PIVOT_AXIS_ROW) - { - if (k == nest->n - 1 - || (nest->scale_idx == nest->n - 1 - && k == nest->n - 2)) - continue; - } - break; - - case CTAT_LAYERROW: - if (a == PIVOT_AXIS_COLUMN) - continue; - break; - - case CTAT_LAYERCOL: - if (a == PIVOT_AXIS_ROW) + if (k == nest->scale_idx) continue; + nest->areas[at][nest->n_areas[at]++] = k; break; } - - nest->areas[at][nest->n_areas[at]++] = k; } + + bool drop_last = (at == CTAT_SUBTABLE ? a != PIVOT_AXIS_LAYER + : at == CTAT_ROW ? a == PIVOT_AXIS_COLUMN + : at == CTAT_COL ? a == PIVOT_AXIS_ROW + : false); + if (drop_last && nest->n_areas[at] > 0) + nest->n_areas[at]--; + + bool drop_additional + = (((at == CTAT_ROW || at == CTAT_LAYERROW || at == CTAT_COL) && a == PIVOT_AXIS_ROW && t->label_axis[PIVOT_AXIS_ROW] == PIVOT_AXIS_COLUMN)); + if (drop_additional && nest->n_areas[at] > 0) + nest->n_areas[at]--; } } } @@ -4702,6 +4742,20 @@ ctables_prepare_table (struct ctables_table *t) ctables_summary_spec_set_clone (&nest->specs[CSV_TOTAL], &nest->specs[CSV_CELL]); + if (t->label_axis[PIVOT_AXIS_ROW] == PIVOT_AXIS_COLUMN + || t->label_axis[PIVOT_AXIS_COLUMN] == PIVOT_AXIS_ROW) + { + for (enum ctables_summary_variant sv = 0; sv < N_CSVS; sv++) + for (size_t i = 0; i < nest->specs[sv].n; i++) + { + struct ctables_summary_spec *ss = &nest->specs[sv].specs[i]; + const struct ctables_function_info *cfi = + &ctables_function_info[ss->function]; + if (cfi->is_area) + ss->calc_area = rotate_area (ss->calc_area); + } + } + if (t->ctables->smissing_listwise) { struct variable **listwise_vars = NULL; @@ -5691,7 +5745,8 @@ ctables_parse_pproperties_format (struct lexer *lexer, sss->specs[sss->n++] = (struct ctables_summary_spec) { .function = function, .weighted = weighted, - .area = area, + .calc_area = area, + .user_area = area, .percentile = percentile, .format = format, .is_ctables_format = is_ctables_format,