1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2017-2018 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
17 #ifndef OUTPUT_PIVOT_TABLE_H
18 #define OUTPUT_PIVOT_TABLE_H 1
22 #include "data/format.h"
23 #include "data/settings.h"
24 #include "libpspp/compiler.h"
25 #include "libpspp/hmap.h"
26 #include "output/table.h"
34 Pivot tables are PSPP's primary form of output. They are analogous to the
35 pivot tables you might be familiar with from spreadsheets and databases.
36 See https://en.wikipedia.org/wiki/Pivot_table for a brief introduction to
37 the overall concept of a pivot table.
39 In PSPP, the most important internal pieces of a pivot table are:
41 - Title. Every pivot table has a title that is displayed above it. It also
42 has an optional caption (displayed below it) and corner text (displayed in
43 the upper left corner).
45 - Dimensions. A dimension consists of zero or more categories. A category
46 has a label, such as "df" or "Asymp. Sig." or 123 or a variable name. The
47 categories are the leaves of a tree whose non-leaf nodes form groups of
48 categories. The tree always has a root group whose label is the name of
51 - Axes. A table has three axes: column, row, and layer. Each dimension is
52 assigned to an axis, and each axis has zero or more dimensions. When an
53 axis has more than one dimension, they are ordered from innermost to
56 - Data. A table's data consists of zero or more cells. Each cell maps from
57 a category for each dimension to a value, which is commonly a number but
58 could also be a variable name or an arbitrary text string.
60 Creating a pivot table usually consists of the following steps:
62 1. Create the table with pivot_table_create(), passing in the title.
64 2. Create each dimension with pivot_dimension_create() and populate it with
65 categories and, possibly, with groups that contain the categories. This
66 call also assigns the dimension to an axis.
68 In simple cases, only a call to pivot_dimension_create() is needed.
69 Other functions such as pivot__create_group() can be used for
70 hierarchies of categories.
72 Sometimes it's easier to create categories in tandem with inserting data,
73 for example by adding a category for a variable just before inserting the
74 first cell for that variable. In that case, creating categories and
75 inserting data can be interleaved.
77 3. Insert data. For each cell, supply the category indexes, which are
78 assigned starting from 0 in the order in which the categories were
79 created in step 2, and the value to go in the cell. If the table has a
80 small, fixed number of dimensions, functions like, e.g.
81 pivot_table_put3() for 3 dimensions, can be used. The general function
82 pivot_table_put() works for other cases.
84 4. Output the table for user consumption. Use pivot_table_submit(). */
86 /* Pivot table display styling. */
88 /* Areas of a pivot table for styling purposes. */
93 PIVOT_AREA_FOOTER, /* Footnotes. */
94 PIVOT_AREA_CORNER, /* Top-left corner. */
95 PIVOT_AREA_COLUMN_LABELS,
96 PIVOT_AREA_ROW_LABELS,
98 PIVOT_AREA_LAYERS, /* Layer indication. */
102 const char *pivot_area_to_string (enum pivot_area);
103 void pivot_area_get_default_style (enum pivot_area, struct area_style *);
105 /* Table borders for styling purposes. */
111 PIVOT_BORDER_OUTER_LEFT,
112 PIVOT_BORDER_OUTER_TOP,
113 PIVOT_BORDER_OUTER_RIGHT,
114 PIVOT_BORDER_OUTER_BOTTOM,
117 PIVOT_BORDER_INNER_LEFT,
118 PIVOT_BORDER_INNER_TOP,
119 PIVOT_BORDER_INNER_RIGHT,
120 PIVOT_BORDER_INNER_BOTTOM,
123 PIVOT_BORDER_DATA_LEFT,
124 PIVOT_BORDER_DATA_TOP,
127 PIVOT_BORDER_DIM_ROW_HORZ,
128 PIVOT_BORDER_DIM_ROW_VERT,
129 PIVOT_BORDER_DIM_COL_HORZ,
130 PIVOT_BORDER_DIM_COL_VERT,
133 PIVOT_BORDER_CAT_ROW_HORZ,
134 PIVOT_BORDER_CAT_ROW_VERT,
135 PIVOT_BORDER_CAT_COL_HORZ,
136 PIVOT_BORDER_CAT_COL_VERT,
141 const char *pivot_border_to_string (enum pivot_border);
142 void pivot_border_get_default_style (enum pivot_border,
143 struct table_border_style *);
145 /* Sizing for rows or columns of a rendered table. The comments below talk
146 about columns and their widths but they apply equally to rows and their
148 struct pivot_table_sizing
150 /* Minimum and maximum column width, in 1/96" units. */
153 /* Specific column widths, in 1/96" units. */
157 /* Specific page breaks: 0-based columns after which a page break must
158 occur, e.g. a value of 1 requests a break after the second column. */
162 /* Keeps: columns to keep together on a page if possible. */
163 struct pivot_keep *keeps;
167 void pivot_table_sizing_uninit (struct pivot_table_sizing *);
169 /* A set of columns to keep together on a page if possible, e.g. ofs=1, n=10
170 requests keeping together the 2nd through 11th columns. */
173 size_t ofs; /* 0-based first column. */
174 size_t n; /* Number of columns. */
188 const char *pivot_axis_type_to_string (enum pivot_axis_type);
190 /* An axis within a pivot table. */
193 /* dimensions[0] is the innermost dimension,
194 dimensions[1] is the next outer dimension,
196 dimensions[n_dimensions - 1] is the outermost dimension. */
197 struct pivot_dimension **dimensions;
200 /* The number of rows or columns along the axis,
201 that is, the product of dimension[*]->n_leaves.
202 It is 0 if any dimension has 0 leaves. */
205 /* Sum of dimensions[*]->label_depth. */
209 /* Successively assigns to INDEXES (which should be a "size_t *") each of the
210 combinations of the categories in AXIS's dimensions, in lexicographic order
211 with the innermost dimension iterating most quickly.
213 The value assigned to INDEXES is dynamically allocated. If the client
214 breaks out of the loop prematurely, it needs to free it with free(). */
215 #define PIVOT_AXIS_FOR_EACH(INDEXES, AXIS) \
216 for ((INDEXES) = NULL; \
217 ((INDEXES) = pivot_axis_iterator_next (INDEXES, AXIS)) != NULL; )
218 size_t *pivot_axis_iterator_next (size_t *indexes, const struct pivot_axis *);
222 A pivot_dimension identifies the categories associated with a single
223 dimension within a multidimensional pivot table.
225 A dimension contains a collection of categories, which are the leaves in a
228 (A dimension or a group can contain zero categories, but this is unusual.
229 If a dimension contains no categories, then its table cannot contain any
232 struct pivot_dimension
234 /* table->axes[axis_type]->dimensions[level] == dimension. */
235 struct pivot_table *table;
236 enum pivot_axis_type axis_type;
237 size_t level; /* 0 for innermost dimension within axis. */
239 /* table->dimensions[top_index] == dimension. */
242 /* Hierarchy of categories within the dimension. The groups and categories
243 are sorted in the order that should be used for display. This might be
244 different from the original order produced for output if the user
247 The root must always be a group, although it is allowed to have no
249 struct pivot_category *root;
251 /* All of the leaves reachable via the root.
253 The indexing for presentation_leaves is presentation order, thus
254 presentation_leaves[i]->presentation_index == i. This order is the same
255 as would be produced by an in-order traversal of the groups. It is the
256 order into which the user reordered or sorted the categories.
258 The indexing for data_leaves is that used for idx[] in struct
259 pivot_cell, thus data_leaves[i]->data_index == i. This might differ
260 from what an in-order traversal of 'root' would yield, if the user
261 reordered categories. */
262 struct pivot_category **data_leaves;
263 struct pivot_category **presentation_leaves;
264 size_t n_leaves, allocated_leaves;
267 bool hide_all_labels;
269 /* Number of rows or columns needed to express the labels. */
273 struct pivot_dimension *pivot_dimension_create (
274 struct pivot_table *, enum pivot_axis_type, const char *name, ...)
276 #define pivot_dimension_create(...) \
277 pivot_dimension_create(__VA_ARGS__, NULL_SENTINEL)
278 struct pivot_dimension *pivot_dimension_create__ (struct pivot_table *,
279 enum pivot_axis_type,
280 struct pivot_value *name);
282 void pivot_dimension_destroy (struct pivot_dimension *);
284 void pivot_dimension_dump (const struct pivot_dimension *, int indentation);
286 /* A pivot_category is a leaf (a category) or a group:
288 - For a leaf, neither index is SIZE_MAX.
290 - For a group, both indexes are SIZE_MAX.
292 Do not use 'subs' or 'n_subs' to determine whether a category is a group,
293 because a group may (pathologically) have no leaves. */
294 struct pivot_category
296 struct pivot_value *name;
297 struct pivot_category *parent;
298 struct pivot_dimension *dimension;
299 size_t label_depth, extra_depth;
303 If show_label is true, then the group itself has a row (or a column)
304 giving the group's name. Otherwise, the group's own name is not
306 struct pivot_category **subs; /* Child categories or groups. */
307 size_t n_subs, allocated_subs;
308 bool show_label; /* Display a label for the group itself? */
309 bool show_label_in_corner;
312 struct fmt_spec format;
313 size_t group_index; /* In ->parent->subs[]. */
314 size_t data_index; /* In ->dimension->data_leaves[]. */
315 size_t presentation_index; /* In ->dimension->presentation_leaves[]. */
319 pivot_category_is_group (const struct pivot_category *category)
321 return category->data_index == SIZE_MAX;
325 pivot_category_is_leaf (const struct pivot_category *category)
327 return !pivot_category_is_group (category);
330 /* Creating leaf categories. */
331 int pivot_category_create_leaves (struct pivot_category *parent, ...)
333 #define pivot_category_create_leaves(...) \
334 pivot_category_create_leaves(__VA_ARGS__, NULL_SENTINEL)
336 int pivot_category_create_leaf (
337 struct pivot_category *parent, struct pivot_value *name);
338 int pivot_category_create_leaf_rc (
339 struct pivot_category *parent, struct pivot_value *name, const char *rc);
341 /* Creating category groups. */
342 struct pivot_category *pivot_category_create_group (
343 struct pivot_category *parent, const char *name, ...) SENTINEL (0);
344 #define pivot_category_create_group(...) \
345 pivot_category_create_group(__VA_ARGS__, NULL_SENTINEL)
346 struct pivot_category *pivot_category_create_group__ (
347 struct pivot_category *parent, struct pivot_value *name);
349 void pivot_category_destroy (struct pivot_category *);
351 /* Pivot result classes.
353 These are used to mark leaf categories as having particular types of data,
354 to set their numeric formats. The formats that actually get used for these
355 classes are in the result_classes[] global array in pivot-table.c, except
356 that PIVOT_RC_OTHER comes from settings_get_format() and PIVOT_RC_COUNT
357 should come from the weight variable in the dataset's dictionary. */
358 #define PIVOT_RC_OTHER ("RC_OTHER")
359 #define PIVOT_RC_INTEGER ("RC_INTEGER")
360 #define PIVOT_RC_CORRELATION ("RC_CORRELATIONS")
361 #define PIVOT_RC_SIGNIFICANCE ("RC_SIGNIFICANCE")
362 #define PIVOT_RC_PERCENT ("RC_PERCENT")
363 #define PIVOT_RC_RESIDUAL ("RC_RESIDUAL")
364 #define PIVOT_RC_COUNT ("RC_COUNT")
366 bool pivot_result_class_change (const char *, const struct fmt_spec *);
368 /* A pivot table. See the top of this file for more information. */
371 /* Reference count. A pivot_table may be shared between multiple owners,
372 indicated by a reference count greater than 1. When this is the case,
373 the output item must not be modified. */
376 /* Display settings. */
377 bool rotate_inner_column_labels;
378 bool rotate_outer_row_labels;
379 bool row_labels_in_corner;
380 bool show_grid_lines;
382 size_t *current_layer; /* axis[PIVOT_AXIS_LAYER]->n_dimensions elements. */
384 enum settings_value_show show_values;
385 enum settings_value_show show_variables;
386 struct fmt_spec weight_format;
388 /* Footnote display settings. */
389 bool show_numeric_markers;
390 bool footnote_marker_superscripts;
392 /* Column and row sizing and page breaks.
393 sizing[TABLE_HORZ] is for columns, sizing[TABLE_VERT] is for rows. */
394 struct pivot_table_sizing sizing[TABLE_N_AXES];
396 /* Print settings. */
397 bool print_all_layers;
398 bool paginate_layers;
399 bool shrink_to_fit[TABLE_N_AXES];
400 bool top_continuation, bottom_continuation;
402 size_t n_orphan_lines;
404 /* Format settings. */
406 char decimal; /* Usually ',' or '.'. */
407 char grouping; /* Usually '.' or ','. */
408 char *ccs[5]; /* Custom currency. */
411 /* Command information. */
412 char *command_local; /* May be NULL. */
413 char *command_c; /* May be NULL. */
414 char *language; /* May be NULL. */
415 char *locale; /* May be NULL. */
417 /* Source information. */
418 char *dataset; /* May be NULL. */
419 char *datafile; /* May be NULL. */
420 time_t date; /* May be 0 if unknown. */
423 struct pivot_footnote **footnotes;
424 size_t n_footnotes, allocated_footnotes;
427 struct pivot_value *title;
428 struct pivot_value *subtype; /* Same as pivot_item's subtype. */
429 struct pivot_value *corner_text;
430 struct pivot_value *caption;
434 struct area_style areas[PIVOT_N_AREAS];
435 struct table_border_style borders[PIVOT_N_BORDERS];
438 struct pivot_dimension **dimensions;
441 /* Allocation of dimensions to rows, columns, and layers. */
442 struct pivot_axis axes[PIVOT_N_AXES];
444 struct hmap cells; /* Contains "struct pivot_cell"s. */
447 /* Creating and destroy pivot tables. */
448 struct pivot_table *pivot_table_create (const char *title);
449 struct pivot_table *pivot_table_create__ (struct pivot_value *title);
450 struct pivot_table *pivot_table_create_for_text (struct pivot_value *title,
451 struct pivot_value *content);
453 struct pivot_table *pivot_table_ref (const struct pivot_table *);
454 void pivot_table_unref (struct pivot_table *);
455 bool pivot_table_is_shared (const struct pivot_table *);
457 /* Format of PIVOT_RC_COUNT cells. */
458 void pivot_table_set_weight_var (struct pivot_table *,
459 const struct variable *);
460 void pivot_table_set_weight_format (struct pivot_table *,
461 const struct fmt_spec *);
464 bool pivot_table_is_empty (const struct pivot_table *);
467 void pivot_table_submit (struct pivot_table *);
470 void pivot_table_put (struct pivot_table *, const size_t *dindexes, size_t n,
471 struct pivot_value *);
472 void pivot_table_put1 (struct pivot_table *, size_t idx1,
473 struct pivot_value *);
474 void pivot_table_put2 (struct pivot_table *, size_t idx1, size_t idx2,
475 struct pivot_value *);
476 void pivot_table_put3 (struct pivot_table *, size_t idx1, size_t idx2,
477 size_t idx3, struct pivot_value *);
478 void pivot_table_put4 (struct pivot_table *, size_t idx1, size_t idx2,
479 size_t idx3, size_t idx4, struct pivot_value *);
481 const struct pivot_value *pivot_table_get (const struct pivot_table *,
482 const size_t *dindexes);
484 struct pivot_value *pivot_table_get_rw (struct pivot_table *,
485 const size_t *dindexes);
489 Use pivot_table_create_footnote() to create a footnote.
490 Use pivot_value_add_footnote() to add a reference to a footnote. */
491 struct pivot_footnote
494 struct pivot_value *content;
495 struct pivot_value *marker;
498 struct pivot_footnote *pivot_table_create_footnote (
499 struct pivot_table *, struct pivot_value *content);
500 struct pivot_footnote *pivot_table_create_footnote__ (
501 struct pivot_table *, size_t idx,
502 struct pivot_value *marker, struct pivot_value *content);
504 void pivot_footnote_destroy (struct pivot_footnote *);
507 void pivot_table_convert_indexes_ptod (const struct pivot_table *,
508 const size_t *pindexes[PIVOT_N_AXES],
510 size_t *pivot_table_enumerate_axis (const struct pivot_table *,
511 enum pivot_axis_type,
512 const size_t *layer_indexes,
513 bool omit_empty, size_t *n);
514 #define PIVOT_ENUMERATION_FOR_EACH(INDEXES, ENUMERATION, AXIS) \
515 for ((INDEXES) = (ENUMERATION); *(INDEXES) != SIZE_MAX; \
516 (INDEXES) += MAX (1, (AXIS)->n_dimensions))
518 void pivot_table_assign_label_depth (struct pivot_table *);
520 void pivot_table_dump (const struct pivot_table *, int indentation);
524 enum pivot_value_type
526 PIVOT_VALUE_NUMERIC, /* A value of a numeric variable. */
527 PIVOT_VALUE_STRING, /* A value of a string variable. */
528 PIVOT_VALUE_VARIABLE, /* Name of a variable. */
529 PIVOT_VALUE_TEXT, /* Text. */
530 PIVOT_VALUE_TEMPLATE, /* Templated text. */
533 /* A pivot_value is the content of a single pivot table cell. A pivot_value is
534 also a pivot table's title, caption, footnote marker and contents, and so
537 A given pivot_value is one of:
539 1. A number resulting from a calculation (PIVOT_VALUE_NUMERIC). Use
540 pivot_value_new_number() to create such a pivot_value.
542 A numeric pivot_value has an associated display format (usually an F or
543 PCT format). This format can be set directly on the pivot_value, but
544 that is not usually the easiest way. Instead, it is usually true that
545 all of the values in a single category should have the same format
546 (e.g. all "Significance" values might use format F40.3), so PSPP makes
547 it easy to set the default format for a category while creating the
548 category. See pivot_dimension_create() for more details.
550 For numbers that should be displayed as integers,
551 pivot_value_new_integer() can occasionally be a useful special case.
553 2. A numeric or string value obtained from data (PIVOT_VALUE_NUMERIC or
554 PIVOT_VALUE_STRING). If such a value corresponds to a variable, then the
555 variable's name can be attached to the pivot_value. If the value has a
556 value label, then that can also be attached. When a label is present,
557 the user can control whether to show the value or the label or both.
559 Use pivot_value_new_var_value() to create pivot_values of these kinds.
561 3. A variable name (PIVOT_VALUE_VARIABLE). The variable label, if any, can
562 be attached too, and again the user can control whether to show the value
563 or the label or both.
565 4. A text string (PIVOT_VALUE_TEXT). The value stores the string in English
566 and translated into the output language (localized). Use
567 pivot_value_new_text() or pivot_value_new_text_format() for those cases.
568 In some cases, only an English or a localized version is available for
569 one reason or another, although this is regrettable; in those cases, use
570 pivot_value_new_user_text() or pivot_value_new_user_text_nocopy().
572 (There is also a PIVOT_VALUE_TEMPLATE but PSPP does not yet create these
579 A pivot_value may reference any number of footnotes. Use
580 pivot_value_add_footnote() to add a footnote reference. The footnotes being
581 referenced must first be created with pivot_table_create_footnote().
587 A pivot_value can have specific font and cell styles. Only the user should
592 struct font_style *font_style;
593 struct cell_style *cell_style;
597 struct pivot_footnote **footnotes;
600 enum pivot_value_type type;
603 /* PIVOT_VALUE_NUMERIC. */
606 double x; /* The numeric value. */
607 struct fmt_spec format; /* Format to display 'x'. */
608 char *var_name; /* May be NULL. */
609 char *value_label; /* May be NULL. */
610 enum settings_value_show show; /* Show value or label or both? */
614 /* PIVOT_VALUE_STRING. */
617 char *s; /* The string value. */
618 bool hex; /* Display in hex? */
619 char *var_name; /* May be NULL. */
620 char *value_label; /* May be NULL. */
621 enum settings_value_show show; /* Show value or label or both? */
625 /* PIVOT_VALUE_VARIABLE. */
629 char *var_label; /* May be NULL. */
630 enum settings_value_show show; /* Show name or label or both? */
634 /* PIVOT_VALUE_TEXT. */
637 char *local; /* Localized. */
638 char *c; /* English. */
639 char *id; /* Identifier. */
644 /* PIVOT_VALUE_TEMPLATE. */
647 char *local; /* Localized. */
648 char *id; /* Identifier. */
649 struct pivot_argument *args;
656 /* Numbers resulting from calculations. */
657 struct pivot_value *pivot_value_new_number (double);
658 struct pivot_value *pivot_value_new_integer (double);
660 /* Values from data. */
661 struct pivot_value *pivot_value_new_var_value (
662 const struct variable *, const union value *);
663 struct pivot_value *pivot_value_new_value (const union value *, int width,
664 const struct fmt_spec *,
665 const char *encoding);
667 /* Values from variable names. */
668 struct pivot_value *pivot_value_new_variable (const struct variable *);
670 /* Values from text strings. */
671 struct pivot_value *pivot_value_new_text (const char *);
672 struct pivot_value *pivot_value_new_text_format (const char *, ...)
673 PRINTF_FORMAT (1, 2);
675 struct pivot_value *pivot_value_new_user_text (const char *, size_t length);
676 struct pivot_value *pivot_value_new_user_text_nocopy (char *);
679 void pivot_value_add_footnote (struct pivot_value *, struct pivot_footnote *);
681 /* Numeric formats. */
682 void pivot_value_set_rc (struct pivot_table *, struct pivot_value *,
685 /* Converting a pivot_value to a string for display. */
686 char *pivot_value_to_string (const struct pivot_value *,
687 enum settings_value_show show_values,
688 enum settings_value_show show_variables);
689 void pivot_value_format (const struct pivot_value *,
690 enum settings_value_show show_values,
691 enum settings_value_show show_variables,
693 bool pivot_value_format_body (const struct pivot_value *,
694 enum settings_value_show show_values,
695 enum settings_value_show show_variables,
698 void pivot_value_destroy (struct pivot_value *);
701 void pivot_value_get_style (struct pivot_value *,
702 const struct font_style *base_font_style,
703 const struct cell_style *base_cell_style,
704 struct area_style *);
705 void pivot_value_set_style (struct pivot_value *, const struct area_style *);
707 /* Template arguments. */
708 struct pivot_argument
711 struct pivot_value **values;
714 void pivot_argument_uninit (struct pivot_argument *);
716 /* One piece of data within a pivot table. */
719 struct hmap_node hmap_node; /* In struct pivot_table's 'cells' hmap. */
720 struct pivot_value *value;
721 unsigned int idx[]; /* One index per table dimension. */
724 #endif /* output/pivot-table.h */