From 5cab4cf3322f29c0ed7134d23740e07382914f20 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Mon, 17 Jul 2017 15:13:16 -0700 Subject: [PATCH] output: Introduce pivot tables. --- Smake | 1 + doc/statistics.texi | 10 +- doc/tutorial.texi | 360 +-- doc/utilities.texi | 21 +- perl-module/t/Pspp.t | 18 +- src/data/settings.c | 30 +- src/data/settings.h | 32 +- src/data/variable.c | 52 +- src/language/data-io/data-parser.c | 103 +- src/language/data-io/dataset.c | 44 +- src/language/data-io/list.c | 57 +- src/language/data-io/print.c | 82 +- src/language/dictionary/mrsets.c | 100 +- src/language/dictionary/split-file.c | 49 +- src/language/dictionary/sys-file-info.c | 592 ++--- src/language/stats/binomial.c | 140 +- src/language/stats/chisquare.c | 373 +-- src/language/stats/cochran.c | 125 +- src/language/stats/correlations.c | 255 +- src/language/stats/crosstabs.q | 1641 ++++++------- src/language/stats/descriptives.c | 161 +- src/language/stats/examine.c | 1136 +++------ src/language/stats/factor.c | 879 ++----- src/language/stats/frequencies.c | 308 +-- src/language/stats/friedman.c | 114 +- src/language/stats/glm.c | 193 +- src/language/stats/graph.c | 2 - src/language/stats/jonckheere-terpstra.c | 126 +- src/language/stats/kruskal-wallis.c | 154 +- src/language/stats/ks-one-sample.c | 144 +- src/language/stats/logistic.c | 590 ++--- src/language/stats/mann-whitney.c | 218 +- src/language/stats/mcnemar.c | 184 +- src/language/stats/means.c | 291 +-- src/language/stats/median.c | 187 +- src/language/stats/npar-summary.c | 102 +- src/language/stats/npar-summary.h | 4 +- src/language/stats/npar.c | 3 +- src/language/stats/oneway.c | 900 +++---- src/language/stats/quick-cluster.c | 166 +- src/language/stats/rank.c | 110 +- src/language/stats/regression.c | 375 ++- src/language/stats/reliability.c | 446 ++-- src/language/stats/roc.c | 284 +-- src/language/stats/runs.c | 125 +- src/language/stats/sign.c | 130 +- src/language/stats/t-test-indep.c | 293 +-- src/language/stats/t-test-one-sample.c | 217 +- src/language/stats/t-test-paired.c | 323 ++- src/language/stats/wilcoxon.c | 221 +- src/language/utilities/output.c | 100 +- src/language/utilities/set.q | 24 +- src/math/categoricals.c | 44 +- src/math/categoricals.h | 8 +- src/math/covariance.c | 83 +- src/math/covariance.h | 12 +- src/math/interaction.c | 2 +- src/output/ascii.c | 3 +- src/output/automake.mk | 4 +- src/output/cairo.c | 4 +- src/output/html.c | 4 - src/output/odt.c | 1 - src/output/pivot-output.c | 509 ++++ src/output/pivot-table.c | 2076 +++++++++++++++++ src/output/pivot-table.h | 703 ++++++ src/output/tab.c | 410 +--- src/output/tab.h | 64 - src/output/table-casereader.c | 166 -- src/output/table.c | 1 + src/output/table.h | 7 - src/ui/gui/psppire-output-window.c | 1 - tests/automake.mk | 1 - tests/data/pc+-file-reader.at | 69 +- tests/data/por-file.at | 19 +- tests/data/sys-file-reader.at | 124 +- tests/data/sys-file.at | 43 +- tests/language/data-io/data-list.at | 4 +- tests/language/data-io/dataset.at | 66 +- tests/language/data-io/get-data-psql.at | 6 +- .../language/data-io/get-data-spreadsheet.at | 34 +- tests/language/data-io/get-data-txt.at | 40 +- tests/language/data-io/list.at | 46 +- tests/language/data-io/matrix-data.at | 136 +- tests/language/data-io/save.at | 4 +- tests/language/dictionary/attributes.at | 4 +- tests/language/dictionary/mrsets.at | 134 +- tests/language/dictionary/split-file.at | 10 +- tests/language/dictionary/sys-file-info.at | 31 +- tests/language/dictionary/value-labels.at | 36 +- tests/language/dictionary/variable-display.at | 45 +- tests/language/dictionary/vector.at | 12 +- tests/language/dictionary/weight.at | 135 +- tests/language/expressions/evaluate.at | 8 +- tests/language/lexer/variable-parser.at | 26 +- tests/language/stats/aggregate.at | 4 +- tests/language/stats/autorecode.at | 24 +- tests/language/stats/correlations.at | 66 +- tests/language/stats/crosstabs.at | 1265 +++++----- tests/language/stats/descriptives.at | 189 +- tests/language/stats/examine.at | 192 +- tests/language/stats/factor.at | 122 +- tests/language/stats/flip.at | 48 +- tests/language/stats/frequencies.at | 393 ++-- tests/language/stats/glm.at | 28 +- tests/language/stats/logistic.at | 192 +- tests/language/stats/means.at | 100 +- tests/language/stats/npar.at | 153 +- tests/language/stats/oneway.at | 196 +- tests/language/stats/quick-cluster.at | 17 +- tests/language/stats/rank.at | 170 +- tests/language/stats/regression.at | 226 +- tests/language/stats/reliability.at | 46 +- tests/language/stats/roc.at | 40 +- tests/language/stats/t-test.at | 216 +- tests/language/utilities/set.at | 6 +- tests/language/utilities/title.at | 72 +- tests/language/xforms/compute.at | 4 +- tests/language/xforms/count.at | 4 +- tests/language/xforms/recode.at | 94 +- tests/output/ascii.at | 16 +- tests/output/render.at | 12 +- tests/output/tables.at | 30 +- tests/perl-module.at | 88 +- 123 files changed, 10889 insertions(+), 10854 deletions(-) create mode 100644 src/output/pivot-output.c create mode 100644 src/output/pivot-table.c create mode 100644 src/output/pivot-table.h delete mode 100644 src/output/table-casereader.c diff --git a/Smake b/Smake index 91b4230f5c..5669ad079f 100644 --- a/Smake +++ b/Smake @@ -70,6 +70,7 @@ GNULIB_MODULES = \ memcasecmp \ memchr \ memchr2 \ + memmem \ mempcpy \ memrchr \ minmax \ diff --git a/doc/statistics.texi b/doc/statistics.texi index c46189bd07..9e9ed9081b 100644 --- a/doc/statistics.texi +++ b/doc/statistics.texi @@ -70,11 +70,8 @@ excluded on a variable by variable basis; if @subcmd{LISTWISE} is set, then the entire case is excluded whenever any value in that case has a system-missing or, if @subcmd{INCLUDE} is set, user-missing value. -The @subcmd{FORMAT} subcommand affects the output format. Currently the -@subcmd{LABELS/NOLABELS} and @subcmd{NOINDEX/INDEX} settings are not used. -When @subcmd{SERIAL} is -set, both valid and missing number of cases are listed in the output; -when @subcmd{NOSERIAL} is set, only valid cases are listed. +The @subcmd{FORMAT} subcommand has no effect. It is accepted for +backward compatibility. The @subcmd{SAVE} subcommand causes @cmd{DESCRIPTIVES} to calculate Z scores for all the specified variables. The Z scores are saved to new variables. @@ -646,8 +643,7 @@ When set to @subcmd{TABLE}, the default, missing values are dropped on a table b table basis. When set to @subcmd{INCLUDE}, user-missing values are included in tables and statistics. When set to @subcmd{REPORT}, which is allowed only in integer mode, user-missing values are included in tables but marked with -an @samp{M} (for ``missing'') and excluded from statistical -calculations. +a footnote and excluded from statistical calculations. Currently the @subcmd{WRITE} subcommand is ignored. diff --git a/doc/tutorial.texi b/doc/tutorial.texi index 47f22cc103..c6928c810c 100644 --- a/doc/tutorial.texi +++ b/doc/tutorial.texi @@ -197,12 +197,15 @@ shown along with the data. It should show the following output: @example @group -Case# forename height ------ ------------ -------- - 1 Ahmed 188.00 - 2 Bertram 167.00 - 3 Catherine 134.23 - 4 David 109.10 + Data List ++-----------+---------+------+ +|Case Number| forename|height| ++-----------+---------+------+ +|1 |Ahmed |188.00| +|2 |Bertram |167.00| +|3 |Catherine|134.23| +|4 |David |109.10| ++-----------+---------+------+ @end group @end example @noindent @@ -350,14 +353,16 @@ data and identify the erroneous values. Output: @example -DESCRIPTIVES. Valid cases = 40; cases with missing value(s) = 0. -+--------#--+-------+-------+-------+-------+ -|Variable# N| Mean |Std Dev|Minimum|Maximum| -#========#==#=======#=======#=======#=======# -|sex #40| .45| .50| .00| 1.00| -|height #40|1677.12| 262.87| 179.00|1903.00| -|weight #40| 72.12| 26.70| -55.60| 92.07| -+--------#--+-------+-------+-------+-------+ + Descriptive Statistics ++---------------------+--+-------+-------+-------+-------+ +| | N| Mean |Std Dev|Minimum|Maximum| ++---------------------+--+-------+-------+-------+-------+ +|Sex of subject |40| .45| .50|Male |Female | +|Weight in kilograms |40| 72.12| 26.70| -55.6| 92.1| +|Height in millimeters|40|1677.12| 262.87| 179| 1903| +|Valid N (listwise) |40| | | | | +|Missing N (listwise) | 0| | | | | ++---------------------+--+-------+-------+-------+-------+ @end example @end cartouche @caption{Using the @cmd{DESCRIPTIVES} command to display simple @@ -395,25 +400,24 @@ represent data entry errors. Output: @example -#===============================#===========#=======# -# #Case Number| Value # -#===============================#===========#=======# -#Height in millimetres Highest 1# 14|1903.00# -# 2# 15|1884.00# -# 3# 12|1801.65# -# ----------#-----------+-------# -# Lowest 1# 30| 179.00# -# 2# 31|1598.00# -# 3# 28|1601.00# -# ----------#-----------+-------# -#Weight in kilograms Highest 1# 13| 92.07# -# 2# 5| 92.07# -# 3# 17| 91.74# -# ----------#-----------+-------# -# Lowest 1# 38| -55.60# -# 2# 39| 54.48# -# 3# 33| 55.45# -#===============================#===========#=======# + Extreme Values ++-------------------------------+-----------+-----+ +| |Case Number|Value| ++-------------------------------+-----------+-----+ +|Height in millimeters Highest 1| 14| 1903| +| 2| 15| 1884| +| 3| 12| 1802| +| Lowest 1| 30| 179| +| 2| 31| 1598| +| 3| 28| 1601| ++-------------------------------+-----------+-----+ +|Weight in kilograms Highest 1| 13| 92.1| +| 2| 5| 92.1| +| 3| 17| 91.7| +| Lowest 1| 38|-55.6| +| 2| 39| 54.5| +| 3| 33| 55.4| ++-------------------------------+-----------+-----+ @end example @end cartouche @caption{Using the @cmd{EXAMINE} command to see the extremities of the data @@ -523,21 +527,23 @@ negatively scaled variables) requests reliability statistics for Output (dictionary information omitted for clarity): @example -1.1 RELIABILITY. Case Processing Summary -#==============#==#======# -# # N| % # -#==============#==#======# -#Cases Valid #17|100.00# -# Excluded# 0| .00# -# Total #17|100.00# -#==============#==#======# - -1.2 RELIABILITY. Reliability Statistics -#================#==========# -#Cronbach's Alpha#N of Items# -#================#==========# -# .81# 3# -#================#==========# +Scale: ANY + +Case Processing Summary ++--------+--+-------+ +|Cases | N|Percent| ++--------+--+-------+ +|Valid |17| 100.0%| +|Excluded| 0| .0%| +|Total |17| 100.0%| ++--------+--+-------+ + + Reliability Statistics ++----------------+----------+ +|Cronbach's Alpha|N of Items| ++----------------+----------+ +| .81| 3| ++----------------+----------+ @end example @end cartouche @caption{Recoding negatively scaled variables, and testing for @@ -606,43 +612,66 @@ an appropriate non-parametric test instead of a linear one. Output: @example -1.2 EXAMINE. Descriptives -#====================================================#=========#==========# -# #Statistic|Std. Error# -#====================================================#=========#==========# -#mtbf Mean # 8.32 | 1.62 # -# 95% Confidence Interval for Mean Lower Bound# 4.85 | # -# Upper Bound# 11.79 | # -# 5% Trimmed Mean # 7.69 | # -# Median # 8.12 | # -# Variance # 39.21 | # -# Std. Deviation # 6.26 | # -# Minimum # 1.63 | # -# Maximum # 26.47 | # -# Range # 24.84 | # -# Interquartile Range # 5.83 | # -# Skewness # 1.85 | .58 # -# Kurtosis # 4.49 | 1.12 # -#====================================================#=========#==========# - -2.2 EXAMINE. Descriptives -#====================================================#=========#==========# -# #Statistic|Std. Error# -#====================================================#=========#==========# -#mtbf_ln Mean # 1.88 | .19 # -# 95% Confidence Interval for Mean Lower Bound# 1.47 | # -# Upper Bound# 2.29 | # -# 5% Trimmed Mean # 1.88 | # -# Median # 2.09 | # -# Variance # .54 | # -# Std. Deviation # .74 | # -# Minimum # .49 | # -# Maximum # 3.28 | # -# Range # 2.79 | # -# Interquartile Range # .92 | # -# Skewness # -.16 | .58 # -# Kurtosis # -.09 | 1.12 # -#====================================================#=========#==========# + Case Processing Summary ++-----------------------------------+-------------------------------+ +| | Cases | +| +----------+---------+----------+ +| | Valid | Missing | Total | +| | N|Percent|N|Percent| N|Percent| ++-----------------------------------+--+-------+-+-------+--+-------+ +|Mean time between failures (months)|15| 100.0%|0| .0%|15| 100.0%| ++-----------------------------------+--+-------+-+-------+--+-------+ + + Descriptives ++----------------------------------------------------------+---------+--------+ +| | | Std. | +| |Statistic| Error | ++----------------------------------------------------------+---------+--------+ +|Mean time between Mean | 8.32| 1.62| +|failures (months) 95% Confidence Interval Lower | 4.85| | +| for Mean Bound | | | +| Upper | 11.79| | +| Bound | | | +| 5% Trimmed Mean | 7.69| | +| Median | 8.12| | +| Variance | 39.21| | +| Std. Deviation | 6.26| | +| Minimum | 1.63| | +| Maximum | 26.47| | +| Range | 24.84| | +| Interquartile Range | 5.83| | +| Skewness | 1.85| .58| +| Kurtosis | 4.49| 1.12| ++----------------------------------------------------------+---------+--------+ + + Case Processing Summary ++-------+-------------------------------+ +| | Cases | +| +----------+---------+----------+ +| | Valid | Missing | Total | +| | N|Percent|N|Percent| N|Percent| ++-------+--+-------+-+-------+--+-------+ +|mtbf_ln|15| 100.0%|0| .0%|15| 100.0%| ++-------+--+-------+-+-------+--+-------+ + + Descriptives ++----------------------------------------------------+---------+----------+ +| |Statistic|Std. Error| ++----------------------------------------------------+---------+----------+ +|mtbf_ln Mean | 1.88| .19| +| 95% Confidence Interval for Mean Lower Bound| 1.47| | +| Upper Bound| 2.29| | +| 5% Trimmed Mean | 1.88| | +| Median | 2.09| | +| Variance | .54| | +| Std. Deviation | .74| | +| Minimum | .49| | +| Maximum | 3.28| | +| Range | 2.79| | +| Interquartile Range | .92| | +| Skewness | -.16| .58| +| Kurtosis | -.09| 1.12| ++----------------------------------------------------+---------+----------+ @end example @end cartouche @caption{Testing for normality using the @cmd{EXAMINE} command and applying @@ -752,28 +781,82 @@ suggest that the body temperature of male and female persons are different. @end example Output: @example -1.1 T-TEST. Group Statistics -#==================#==#=======#==============#========# -# sex | N| Mean |Std. Deviation|SE. Mean# -#==================#==#=======#==============#========# -#height Male |22|1796.49| 49.71| 10.60# -# Female|17|1610.77| 25.43| 6.17# -#temperature Male |22| 36.68| 1.95| .42# -# Female|18| 37.43| 1.61| .38# -#==================#==#=======#==============#========# -1.2 T-TEST. Independent Samples Test -#===========================#=========#=============================== =# -# # Levene's| t-test for Equality of Means # -# #----+----+------+-----+------+---------+- -# -# # | | | | | | # -# # | | | |Sig. 2| | # -# # F |Sig.| t | df |tailed|Mean Diff| # -#===========================#====#====#======#=====#======#=========#= =# -#height Equal variances# .97| .33| 14.02|37.00| .00| 185.72| ... # -# Unequal variances# | | 15.15|32.71| .00| 185.72| ... # -#temperature Equal variances# .31| .58| -1.31|38.00| .20| -.75| ... # -# Unequal variances# | | -1.33|37.99| .19| -.75| ... # -#===========================#====#====#======#=====#======#=========#= =# + Group Statistics ++-------------------------------------------+--+-------+-------------+--------+ +| | | | Std. | S.E. | +| Group | N| Mean | Deviation | Mean | ++-------------------------------------------+--+-------+-------------+--------+ +|Height in millimeters Male |22|1796.49| 49.71| 10.60| +| Female|17|1610.77| 25.43| 6.17| ++-------------------------------------------+--+-------+-------------+--------+ +|Internal body temperature in degrees Male |22| 36.68| 1.95| .42| +|Celcius Female|18| 37.43| 1.61| .38| ++-------------------------------------------+--+-------+-------------+--------+ + + Independent Samples Test ++---------------------+----------------------------------------------------- +| | Levene's +| | Test for +| | Equality +| | of +| | Variances T-Test for Equality of Means +| +----+-----+-----+-----+-------+----------+----------+ +| | | | | | | | | +| | | | | | | | | +| | | | | | | | | +| | | | | | | | | +| | | | | | Sig. | | | +| | | | | | (2- | Mean |Std. Error| +| | F | Sig.| t | df |tailed)|Difference|Difference| ++---------------------+----+-----+-----+-----+-------+----------+----------+ +|Height in Equal | .97| .331|14.02|37.00| .000| 185.72| 13.24| +|millimeters variances| | | | | | | | +| assumed | | | | | | | | +| Equal | | |15.15|32.71| .000| 185.72| 12.26| +| variances| | | | | | | | +| not | | | | | | | | +| assumed | | | | | | | | ++---------------------+----+-----+-----+-----+-------+----------+----------+ +|Internal Equal | .31| .581|-1.31|38.00| .198| -.75| .57| +|body variances| | | | | | | | +|temperature assumed | | | | | | | | +|in degrees Equal | | |-1.33|37.99| .190| -.75| .56| +|Celcius variances| | | | | | | | +| not | | | | | | | | +| assumed | | | | | | | | ++---------------------+----+-----+-----+-----+-------+----------+----------+ + ++---------------------+-------------+ +| | | +| | | +| | | +| | | +| | | +| +-------------+ +| | 95% | +| | Confidence | +| | Interval of | +| | the | +| | Difference | +| +------+------+ +| | Lower| Upper| ++---------------------+------+------+ +|Height in Equal |158.88|212.55| +|millimeters variances| | | +| assumed | | | +| Equal |160.76|210.67| +| variances| | | +| not | | | +| assumed | | | ++---------------------+------+------+ +|Internal Equal | -1.91| .41| +|body variances| | | +|temperature assumed | | | +|in degrees Equal | -1.89| .39| +|Celcius variances| | | +| not | | | +| assumed | | | ++---------------------+------+------+ @end example @end cartouche @caption{The @cmd{T-TEST} command tests for differences of means. @@ -816,44 +899,33 @@ identifies the potential linear relationship. @xref{REGRESSION}. @prompt{PSPP>} regression /variables = mtbf duty_cycle /dependent = mttr. @prompt{PSPP>} regression /variables = mtbf /dependent = mttr. @end example -Output: +Output (excerpts): @example -1.3(1) REGRESSION. Coefficients -#=============================================#====#==========#====#=====# -# # B |Std. Error|Beta| t # -#========#====================================#====#==========#====#=====# -# |(Constant) #9.81| 1.50| .00| 6.54# -# |Mean time between failures (months) #3.10| .10| .99|32.43# -# |Ratio of working to non-working time#1.09| 1.78| .02| .61# -# | # | | | # -#========#====================================#====#==========#====#=====# - -1.3(2) REGRESSION. Coefficients -#=============================================#============# -# #Significance# -#========#====================================#============# -# |(Constant) # .10# -# |Mean time between failures (months) # .00# -# |Ratio of working to non-working time# .55# -# | # # -#========#====================================#============# -2.3(1) REGRESSION. Coefficients -#============================================#=====#==========#====#=====# -# # B |Std. Error|Beta| t # -#========#===================================#=====#==========#====#=====# -# |(Constant) #10.50| .96| .00|10.96# -# |Mean time between failures (months)# 3.11| .09| .99|33.39# -# | # | | | # -#========#===================================#=====#==========#====#=====# - -2.3(2) REGRESSION. Coefficients -#============================================#============# -# #Significance# -#========#===================================#============# -# |(Constant) # .06# -# |Mean time between failures (months)# .00# -# | # # -#========#===================================#============# + Coefficients (Mean time to repair (hours) ) ++------------------------+-----------------------------------------+-----+----+ +| | Unstandardized Standardized | | | +| | Coefficients Coefficients | | | +| +---------+-----------+-------------------+ | | +| | B | Std. Error| Beta | t |Sig.| ++------------------------+---------+-----------+-------------------+-----+----+ +|(Constant) | 9.81| 1.50| .00| 6.54|.000| +|Mean time between | 3.10| .10| .99|32.43|.000| +|failures (months) | | | | | | +|Ratio of working to non-| 1.09| 1.78| .02| .61|.552| +|working time | | | | | | ++------------------------+---------+-----------+-------------------+-----+----+ + + Coefficients (Mean time to repair (hours) ) ++-----------------------+------------------------------------------+-----+----+ +| | Unstandardized Standardized | | | +| | Coefficients Coefficients | | | +| +---------+------------+-------------------+ | | +| | B | Std. Error | Beta | t |Sig.| ++-----------------------+---------+------------+-------------------+-----+----+ +|(Constant) | 10.50| .96| .00|10.96|.000| +|Mean time between | 3.11| .09| .99|33.39|.000| +|failures (months) | | | | | | ++-----------------------+---------+------------+-------------------+-----+----+ @end example @end cartouche @caption{Linear regression analysis to find a predictor for diff --git a/doc/utilities.texi b/doc/utilities.texi index c2dba0e479..598431d5ef 100644 --- a/doc/utilities.texi +++ b/doc/utilities.texi @@ -353,7 +353,7 @@ otherwise it is @code{Auto}. @display OUTPUT MODIFY /SELECT TABLES - /TABLECELLS SELECT = [ @{SIGNIFICANCE, COUNT@} ] + /TABLECELLS SELECT = [ @var{class}... ] FORMAT = @var{fmt_spec}. @end display @note{In the above synopsis the characters @samp{[} and @samp{]} are literals. @@ -370,13 +370,27 @@ brackets. This list determines the classes of values should be selected for mod Each class can be: @table @asis +@item RESIDUAL +Residual values. Default: @t{F40.2}. + +@item CORRELATION +Correlations. Default: @t{F40.3}. + +@item PERCENT +Percentages. Default: @t{PCT40.1}. + @item SIGNIFICANCE -Significance of tests (p-values). +Significance of tests (p-values). Default: @t{F40.3}. @item COUNT -Counts or sums of weights. +Counts or sums of weights. For a weighted data set, the default is +the weight variable's print format. For an unweighted data set, the +default is F40.0. @end table +For most other numeric values that appear in tables, @code{SET FORMAT} +may be used to specify the format (@pxref{SET FORMAT}). + The value of @var{fmt_spec} must be a valid output format (@pxref{Input and Output Formats}). Note that not all possible formats are meaningful for all classes. @@ -531,6 +545,7 @@ as a field separator in the @cmd{DATA LIST} command (@pxref{DATA LIST}). The default value is determined from the system locale. @item FORMAT +@anchor{SET FORMAT} Allows the default numeric input/output format to be specified. The default is F8.2. @xref{Input and Output Formats}. diff --git a/perl-module/t/Pspp.t b/perl-module/t/Pspp.t index f7ff632cf7..61ed4616b9 100644 --- a/perl-module/t/Pspp.t +++ b/perl-module/t/Pspp.t @@ -180,15 +180,15 @@ Name,Position,Label,Measurement Level,Role,Width,Alignment,Print Format,Write Fo id,1,,Scale,Input,8,Right,F2.0,F2.0, name,2,,Nominal,Input,20,Left,A20,A20, -File label: This is the file label - -Documents in the active dataset: +Table: File Label +Label,This is the file label +Table: Documents This is a document line Table: Data List id,name -21,wheelbarrow +21,wheelbarrow RESULT @@ -251,13 +251,13 @@ string,2,My String,Nominal,Input,8,Left,A8,A8,"""this ""; ""that """ longstring,3,My Long String,Nominal,Input,9,Left,A9,A9, Table: Value Labels -Variable,Value,Label -integer,0,Zero +Variable Value,,Label +My Integer,0,Zero ,1,Unity ,2,Duality -string,xx ,foo -,yy ,bar -longstring,xxx ,xfoo +My String,xx,foo +,yy,bar +My Long String,xxx,xfoo RESULT } diff --git a/src/data/settings.c b/src/data/settings.c index 114200cf06..f4efb99fa8 100644 --- a/src/data/settings.c +++ b/src/data/settings.c @@ -76,8 +76,8 @@ struct settings enum settings_output_devices output_routing[SETTINGS_N_OUTPUT_TYPES]; - enum settings_var_style var_output_style; - enum settings_value_style value_output_style; + enum settings_value_show show_values; + enum settings_value_show show_variables; }; static struct settings the_settings = { @@ -121,8 +121,8 @@ static struct settings the_settings = { 0, SETTINGS_DEVICE_LISTING | SETTINGS_DEVICE_TERMINAL}, - SETTINGS_VAR_STYLE_LABELS, - SETTINGS_VAL_STYLE_LABELS + SETTINGS_VALUE_SHOW_LABEL, + SETTINGS_VALUE_SHOW_LABEL }; /* Initializes the settings module. */ @@ -707,29 +707,27 @@ settings_get_output_routing (enum settings_output_type type) return the_settings.output_routing[type] | SETTINGS_DEVICE_UNFILTERED; } -enum settings_value_style -settings_get_value_style (void) +enum settings_value_show +settings_get_show_values (void) { - return the_settings.value_output_style; + return the_settings.show_values; } void -settings_set_value_style (enum settings_value_style s) +settings_set_show_values (enum settings_value_show s) { - the_settings.value_output_style = s; + the_settings.show_values = s; } - -enum settings_var_style -settings_get_var_style (void) +enum settings_value_show +settings_get_show_variables (void) { - return the_settings.var_output_style; + return the_settings.show_variables; } - void -settings_set_var_style (enum settings_var_style s) +settings_set_show_variables (enum settings_value_show s) { - the_settings.var_output_style = s; + the_settings.show_variables = s; } diff --git a/src/data/settings.h b/src/data/settings.h index c499293ebb..cc16576d31 100644 --- a/src/data/settings.h +++ b/src/data/settings.h @@ -105,26 +105,26 @@ void settings_set_testing_mode (bool); int settings_get_fuzzbits (void); void settings_set_fuzzbits (int); -enum settings_var_style +/* Whether to show variable or value labels or the underlying value or variable + name. */ +enum settings_value_show { - SETTINGS_VAR_STYLE_NAMES, - SETTINGS_VAR_STYLE_LABELS, - SETTINGS_VAR_STYLE_BOTH + /* Use higher-level default. + In a pivot_value, the default is taken from the pivot_table. + In a pivot_table, the default is a global default. + As a global default, this is invalid. */ + SETTINGS_VALUE_SHOW_DEFAULT = 0, + + SETTINGS_VALUE_SHOW_VALUE = 1, /* Show value or variable name only. */ + SETTINGS_VALUE_SHOW_LABEL = 2, /* Show label only. */ + SETTINGS_VALUE_SHOW_BOTH = 3, /* Show both value/name and label. */ }; -enum settings_value_style - { - SETTINGS_VAL_STYLE_VALUES, - SETTINGS_VAL_STYLE_LABELS, - SETTINGS_VAL_STYLE_BOTH - }; - - -enum settings_value_style settings_get_value_style (void); -enum settings_var_style settings_get_var_style (void); +enum settings_value_show settings_get_show_values (void); +enum settings_value_show settings_get_show_variables (void); -void settings_set_value_style (enum settings_value_style s); -void settings_set_var_style (enum settings_var_style s); +void settings_set_show_values (enum settings_value_show); +void settings_set_show_variables (enum settings_value_show); enum behavior_mode { diff --git a/src/data/variable.c b/src/data/variable.c index 14b122fee0..25b3228de3 100644 --- a/src/data/variable.c +++ b/src/data/variable.c @@ -571,33 +571,28 @@ void var_append_value_name (const struct variable *v, const union value *value, struct string *str) { - enum settings_value_style style = settings_get_value_style (); - const char *name = var_lookup_value_label (v, value); + const char *label = var_lookup_value_label (v, value); - switch (style) + switch (settings_get_show_values ()) { - case SETTINGS_VAL_STYLE_VALUES: + case SETTINGS_VALUE_SHOW_VALUE: append_value (v, value, str); break; - case SETTINGS_VAL_STYLE_LABELS: - if (name == NULL) - append_value (v, value, str); + default: + case SETTINGS_VALUE_SHOW_LABEL: + if (label) + ds_put_cstr (str, label); else - ds_put_cstr (str, name); + append_value (v, value, str); break; - case SETTINGS_VAL_STYLE_BOTH: - default: + case SETTINGS_VALUE_SHOW_BOTH: append_value (v, value, str); - if (name != NULL) - { - ds_put_cstr (str, " ("); - ds_put_cstr (str, name); - ds_put_cstr (str, ")"); - } + if (label != NULL) + ds_put_format (str, " %s", label); break; - }; + } } /* Print and write formats. */ @@ -720,24 +715,19 @@ update_vl_string (const struct variable *v) const char * var_to_string (const struct variable *v) { - enum settings_var_style style = settings_get_var_style (); - - switch (style) - { - case SETTINGS_VAR_STYLE_NAMES: + switch (settings_get_show_variables ()) + { + case SETTINGS_VALUE_SHOW_VALUE: return v->name; - break; - case SETTINGS_VAR_STYLE_LABELS: + + case SETTINGS_VALUE_SHOW_LABEL: + default: return v->label != NULL ? v->label : v->name; - break; - case SETTINGS_VAR_STYLE_BOTH: + + case SETTINGS_VALUE_SHOW_BOTH: update_vl_string (v); return ds_cstr (&v->name_and_label); - break; - default: - NOT_REACHED (); - break; - }; + } } /* Returns V's variable label, or a null pointer if it has none. */ diff --git a/src/language/data-io/data-parser.c b/src/language/data-io/data-parser.c index 1d8a493e0d..d223b05304 100644 --- a/src/language/data-io/data-parser.c +++ b/src/language/data-io/data-parser.c @@ -31,11 +31,12 @@ #include "language/data-io/data-reader.h" #include "libpspp/message.h" #include "libpspp/str.h" -#include "output/tab.h" +#include "output/pivot-table.h" #include "gl/xalloc.h" #include "gettext.h" +#define N_(msgid) msgid #define _(msgid) gettext (msgid) /* Data parser for textual data like that read by DATA LIST. */ @@ -664,37 +665,48 @@ static void dump_fixed_table (const struct data_parser *parser, const struct file_handle *fh) { - struct tab_table *t; - size_t i; - - t = tab_create (4, parser->field_cnt + 1); - tab_headers (t, 0, 0, 1, 0); - tab_text (t, 0, 0, TAB_CENTER | TAT_TITLE, _("Variable")); - tab_text (t, 1, 0, TAB_CENTER | TAT_TITLE, _("Record")); - tab_text (t, 2, 0, TAB_CENTER | TAT_TITLE, _("Columns")); - tab_text (t, 3, 0, TAB_CENTER | TAT_TITLE, _("Format")); - tab_box (t, TAL_1, TAL_1, TAL_0, TAL_1, 0, 0, 3, parser->field_cnt); - tab_hline (t, TAL_2, 0, 3, 1); - - for (i = 0; i < parser->field_cnt; i++) + /* XXX This should not be preformatted. */ + char *title = xasprintf (ngettext ("Reading %d record from %s.", + "Reading %d records from %s.", + parser->records_per_case), + parser->records_per_case, fh_get_name (fh)); + struct pivot_table *table = pivot_table_create__ ( + pivot_value_new_user_text (title, -1)); + free (title); + + pivot_dimension_create ( + table, PIVOT_AXIS_COLUMN, N_("Attributes"), + N_("Record"), N_("Columns"), N_("Format")); + + struct pivot_dimension *variables = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Variable")); + variables->root->show_label = true; + for (size_t i = 0; i < parser->field_cnt; i++) { struct field *f = &parser->fields[i]; - char fmt_string[FMT_STRING_LEN_MAX + 1]; - int row = i + 1; - - tab_text (t, 0, row, TAB_LEFT, f->name); - tab_text_format (t, 1, row, 0, "%d", f->record); - tab_text_format (t, 2, row, 0, "%3d-%3d", - f->first_column, f->first_column + f->format.w - 1); - tab_text (t, 3, row, TAB_LEFT | TAB_FIX, - fmt_to_string (&f->format, fmt_string)); + + /* XXX It would be better to have the actual variable here. */ + int variable_idx = pivot_category_create_leaf ( + variables->root, pivot_value_new_user_text (f->name, -1)); + + pivot_table_put2 (table, 0, variable_idx, + pivot_value_new_integer (f->record)); + + int first_column = f->first_column; + int last_column = f->first_column + f->format.w - 1; + char *columns = xasprintf ("%3d-%3d", first_column, last_column); + pivot_table_put2 (table, 1, variable_idx, + pivot_value_new_user_text (columns, -1)); + free (columns); + + char str[FMT_STRING_LEN_MAX + 1]; + pivot_table_put2 (table, 2, variable_idx, + pivot_value_new_user_text ( + fmt_to_string (&f->format, str), -1)); + } - tab_title (t, ngettext ("Reading %d record from %s.", - "Reading %d records from %s.", - parser->records_per_case), - parser->records_per_case, fh_get_name (fh)); - tab_submit (t); + pivot_table_submit (table); } /* Displays a table giving information on free-format variable parsing @@ -703,30 +715,31 @@ static void dump_delimited_table (const struct data_parser *parser, const struct file_handle *fh) { - struct tab_table *t; - size_t i; + struct pivot_table *table = pivot_table_create__ ( + pivot_value_new_text_format (N_("Reading free-form data from %s."), + fh_get_name (fh))); - t = tab_create (2, parser->field_cnt + 1); - tab_headers (t, 0, 0, 1, 0); - tab_text (t, 0, 0, TAB_CENTER | TAT_TITLE, _("Variable")); - tab_text (t, 1, 0, TAB_CENTER | TAT_TITLE, _("Format")); - tab_box (t, TAL_1, TAL_1, TAL_0, TAL_1, 0, 0, 1, parser->field_cnt); - tab_hline (t, TAL_2, 0, 1, 1); + pivot_dimension_create ( + table, PIVOT_AXIS_COLUMN, N_("Attributes"), N_("Format")); - for (i = 0; i < parser->field_cnt; i++) + struct pivot_dimension *variables = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Variable")); + variables->root->show_label = true; + for (size_t i = 0; i < parser->field_cnt; i++) { struct field *f = &parser->fields[i]; - char str[FMT_STRING_LEN_MAX + 1]; - int row = i + 1; - tab_text (t, 0, row, TAB_LEFT, f->name); - tab_text (t, 1, row, TAB_LEFT | TAB_FIX, - fmt_to_string (&f->format, str)); - } + /* XXX It would be better to have the actual variable here. */ + int variable_idx = pivot_category_create_leaf ( + variables->root, pivot_value_new_user_text (f->name, -1)); - tab_title (t, _("Reading free-form data from %s."), fh_get_name (fh)); + char str[FMT_STRING_LEN_MAX + 1]; + pivot_table_put2 (table, 0, variable_idx, + pivot_value_new_user_text ( + fmt_to_string (&f->format, str), -1)); + } - tab_submit (t); + pivot_table_submit (table); } /* Displays a table giving information on how PARSER will read diff --git a/src/language/data-io/dataset.c b/src/language/data-io/dataset.c index dbf0d35573..cf25f74799 100644 --- a/src/language/data-io/dataset.c +++ b/src/language/data-io/dataset.c @@ -22,9 +22,10 @@ #include "data/session.h" #include "language/lexer/lexer.h" #include "libpspp/message.h" -#include "output/tab.h" +#include "output/pivot-table.h" #include "gettext.h" +#define N_(msgid) msgid #define _(msgid) gettext (msgid) static int @@ -240,22 +241,19 @@ int cmd_dataset_display (struct lexer *lexer UNUSED, struct dataset *ds) { struct session *session = dataset_session (ds); - struct dataset **datasets, **p; - struct tab_table *t; - size_t i, n; - - n = session_n_datasets (session); - datasets = xmalloc (n * sizeof *datasets); - p = datasets; + size_t n = session_n_datasets (session); + struct dataset **datasets = xmalloc (n * sizeof *datasets); + struct dataset **p = datasets; session_for_each_dataset (session, dataset_display_cb, &p); qsort (datasets, n, sizeof *datasets, sort_datasets); - t = tab_create (1, n + 1); - tab_headers (t, 0, 0, 1, 0); - tab_box (t, TAL_1, TAL_1, -1, TAL_1, 0, 0, tab_nc (t) - 1, tab_nr (t) - 1); - tab_hline (t, TAL_2, 0, 0, 1); - tab_text (t, 0, 0, TAB_LEFT | TAT_TITLE, _("Dataset")); - for (i = 0; i < n; i++) + struct pivot_table *table = pivot_table_create (N_("Datasets")); + + struct pivot_dimension *datasets_dim = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Dataset")); + datasets_dim->hide_all_labels = true; + + for (size_t i = 0; i < n; i++) { struct dataset *ds = datasets[i]; const char *name; @@ -264,16 +262,18 @@ cmd_dataset_display (struct lexer *lexer UNUSED, struct dataset *ds) if (name[0] == '\0') name = _("unnamed dataset"); - if (ds == session_active_dataset (session)) - tab_text_format (t, 0, i + 1, TAB_LEFT, "%s %s", - name, _("(active dataset)")); - else - tab_text (t, 0, i + 1, TAB_LEFT, name); + char *text = (ds == session_active_dataset (session) + ? xasprintf ("%s (%s)", name, _("active dataset")) + : xstrdup (name)); + + int dataset_idx = pivot_category_create_leaf ( + datasets_dim->root, pivot_value_new_integer (i)); + + pivot_table_put1 (table, dataset_idx, + pivot_value_new_user_text_nocopy (text)); } - tab_title (t, "Open datasets."); - tab_submit (t); - free (datasets); + pivot_table_submit (table); return CMD_SUCCESS; } diff --git a/src/language/data-io/list.c b/src/language/data-io/list.c index 55ccc4d2da..920d66e322 100644 --- a/src/language/data-io/list.c +++ b/src/language/data-io/list.c @@ -36,7 +36,7 @@ #include "libpspp/ll.h" #include "libpspp/message.h" #include "libpspp/misc.h" -#include "output/tab.h" +#include "output/pivot-table.h" #include "output/table-item.h" #include "gl/intprops.h" @@ -45,6 +45,7 @@ #include "gl/xmalloca.h" #include "gettext.h" +#define N_(msgid) msgid #define _(msgid) gettext (msgid) enum numbering @@ -84,52 +85,48 @@ list_execute (const struct lst_cmd *lcmd, struct dataset *ds) grouper = casegrouper_create_splits (proc_open (ds), dict); while (casegrouper_get_next_group (grouper, &group)) { - struct ccase *ccase; - struct table *t = NULL; - - ccase = casereader_peek (group, 0); - if (ccase != NULL) + struct ccase *c = casereader_peek (group, 0); + if (c != NULL) { - output_split_file_values (ds, ccase); - case_unref (ccase); + output_split_file_values (ds, c); + case_unref (c); } group = casereader_project (group, &sc); - if (lcmd->numbering == format_numbered) - group = casereader_create_arithmetic_sequence (group, 1, 1); group = casereader_select (group, lcmd->first - 1, (lcmd->last != LONG_MAX ? lcmd->last : CASENUMBER_MAX), lcmd->step); - if (lcmd->numbering == format_numbered) - { - struct fmt_spec fmt; - size_t col; - int width; + struct pivot_table *table = pivot_table_create (N_("Data List")); + table->show_values = table->show_variables = SETTINGS_VALUE_SHOW_VALUE; - width = lcmd->last == LONG_MAX ? 5 : intlog10 (lcmd->last); - fmt = fmt_for_output (FMT_F, width, 0); - col = caseproto_get_n_widths (casereader_get_proto (group)) - 1; + struct pivot_dimension *variables = pivot_dimension_create ( + table, PIVOT_AXIS_COLUMN, N_("Variables")); + for (int i = 0; i < lcmd->n_variables; i++) + pivot_category_create_leaf ( + variables->root, pivot_value_new_variable (lcmd->v_variables[i])); - t = table_from_casereader (group, col, _("Case Number"), &fmt); - } + struct pivot_dimension *cases = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Case Number")); + if (lcmd->numbering == format_numbered) + cases->root->show_label = true; else - t = NULL; + cases->hide_all_labels = true; - for (i = 0; i < lcmd->n_variables; i++) + casenumber case_num = 1; + for (; (c = casereader_read (group)) != NULL; case_unref (c)) { - const struct variable *var = lcmd->v_variables[i]; - struct table *c; + int case_idx = pivot_category_create_leaf ( + cases->root, pivot_value_new_integer (case_num++)); - c = table_from_casereader (group, i, var_get_name (var), - var_get_print_format (var)); - t = table_hpaste (t, c); + for (int i = 0; i < lcmd->n_variables; i++) + pivot_table_put2 (table, i, case_idx, + pivot_value_new_var_value ( + lcmd->v_variables[i], case_data_idx (c, i))); } - casereader_destroy (group); - if (t) - table_item_submit (table_item_create (t, "Data List", NULL)); + pivot_table_submit (table); } ok = casegrouper_destroy (grouper); ok = proc_commit (ds) && ok; diff --git a/src/language/data-io/print.c b/src/language/data-io/print.c index 0396df55b0..4545a222df 100644 --- a/src/language/data-io/print.c +++ b/src/language/data-io/print.c @@ -40,12 +40,14 @@ #include "libpspp/misc.h" #include "libpspp/pool.h" #include "libpspp/u8-line.h" +#include "output/pivot-table.h" #include "output/tab.h" #include "output/text-item.h" #include "gl/xalloc.h" #include "gettext.h" +#define N_(msgid) msgid #define _(msgid) gettext (msgid) /* Describes what to do when an output field is encountered. */ @@ -99,7 +101,7 @@ static trns_proc_func print_text_trns_proc, print_binary_trns_proc; static trns_free_func print_trns_free; static bool parse_specs (struct lexer *, struct pool *tmp_pool, struct print_trns *, struct dictionary *dict, enum which_formats); -static void dump_table (struct print_trns *, const struct file_handle *); +static void dump_table (struct print_trns *); /* Basic parsing. */ @@ -233,7 +235,7 @@ internal_cmd_print (struct lexer *lexer, struct dataset *ds, /* Output the variable table if requested. */ if (print_table) - dump_table (trns, fh); + dump_table (trns); /* Put the transformation in the queue. */ add_transformation (ds, @@ -425,59 +427,43 @@ parse_variable_argument (struct lexer *lexer, const struct dictionary *dict, /* Prints the table produced by the TABLE subcommand to the listing file. */ static void -dump_table (struct print_trns *trns, const struct file_handle *fh) +dump_table (struct print_trns *trns) { + struct pivot_table *table = pivot_table_create (N_("Print Summary")); + + pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Attributes"), + N_("Record"), N_("Columns"), N_("Format")); + + struct pivot_dimension *variables = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Variable")); + struct prt_out_spec *spec; - struct tab_table *t; - int spec_cnt; - int row; - - spec_cnt = ll_count (&trns->specs); - t = tab_create (4, spec_cnt + 1); - tab_box (t, TAL_1, TAL_1, TAL_0, TAL_1, 0, 0, 3, spec_cnt); - tab_hline (t, TAL_2, 0, 3, 1); - tab_headers (t, 0, 0, 1, 0); - tab_text (t, 0, 0, TAB_CENTER | TAT_TITLE, _("Variable")); - tab_text (t, 1, 0, TAB_CENTER | TAT_TITLE, _("Record")); - tab_text (t, 2, 0, TAB_CENTER | TAT_TITLE, _("Columns")); - tab_text (t, 3, 0, TAB_CENTER | TAT_TITLE, _("Format")); - row = 1; ll_for_each (spec, struct prt_out_spec, ll, &trns->specs) { + if (spec->type != PRT_VAR) + continue; + + int row = pivot_category_create_leaf ( + variables->root, pivot_value_new_variable (spec->var)); + + pivot_table_put2 (table, 0, row, + pivot_value_new_integer (spec->record)); + int last_column = spec->first_column + spec->format.w - 1; + pivot_table_put2 (table, 1, row, pivot_value_new_user_text_nocopy ( + xasprintf ("%3d-%3d", + spec->first_column, last_column))); + char fmt_string[FMT_STRING_LEN_MAX + 1]; - int width; - switch (spec->type) - { - case PRT_LITERAL: - tab_text_format (t, 0, row, TAB_LEFT | TAB_FIX, "`%.*s'", - (int) ds_length (&spec->string), - ds_data (&spec->string)); - width = ds_length (&spec->string); - break; - case PRT_VAR: - tab_text (t, 0, row, TAB_LEFT, var_get_name (spec->var)); - tab_text (t, 3, row, TAB_LEFT | TAB_FIX, - fmt_to_string (&spec->format, fmt_string)); - width = spec->format.w; - break; - default: - NOT_REACHED (); - } - tab_text_format (t, 1, row, 0, "%d", spec->record); - tab_text_format (t, 2, row, 0, "%3d-%3d", - spec->first_column, spec->first_column + width - 1); - row++; + pivot_table_put2 (table, 2, row, pivot_value_new_user_text ( + fmt_to_string (&spec->format, fmt_string), -1)); } - if (fh != NULL) - tab_title (t, ngettext ("Writing %zu record to %s.", - "Writing %zu records to %s.", trns->record_cnt), - trns->record_cnt, fh_get_name (fh)); - else - tab_title (t, ngettext ("Writing %zu record.", - "Writing %zu records.", trns->record_cnt), - trns->record_cnt); - tab_submit (t); + int row = pivot_category_create_leaf ( + variables->root, pivot_value_new_text (N_("N of Records"))); + pivot_table_put2 (table, 0, row, + pivot_value_new_integer (trns->record_cnt)); + + pivot_table_submit (table); } /* Transformation, for all-text output. */ diff --git a/src/language/dictionary/mrsets.c b/src/language/dictionary/mrsets.c index 621516b9ec..97ab2c1fb4 100644 --- a/src/language/dictionary/mrsets.c +++ b/src/language/dictionary/mrsets.c @@ -32,11 +32,12 @@ #include "libpspp/str.h" #include "libpspp/stringi-map.h" #include "libpspp/stringi-set.h" -#include "output/tab.h" +#include "output/pivot-table.h" #include "gl/xalloc.h" #include "gettext.h" +#define N_(msgid) msgid #define _(msgid) gettext (msgid) static bool parse_group (struct lexer *, struct dictionary *, enum mrset_type); @@ -521,16 +522,11 @@ parse_delete (struct lexer *lexer, struct dictionary *dict) static bool parse_display (struct lexer *lexer, struct dictionary *dict) { - struct string details, var_names; struct stringi_set mrset_names_set; - char **mrset_names; - struct tab_table *table; - size_t i, n; - if (!parse_mrset_names (lexer, dict, &mrset_names_set)) return false; - n = stringi_set_count (&mrset_names_set); + size_t n = stringi_set_count (&mrset_names_set); if (n == 0) { if (dict_get_n_mrsets (dict) == 0) @@ -540,71 +536,53 @@ parse_display (struct lexer *lexer, struct dictionary *dict) return true; } - table = tab_create (3, n + 1); - tab_headers (table, 0, 0, 1, 0); - tab_box (table, TAL_1, TAL_1, TAL_1, TAL_1, 0, 0, 2, n); - tab_hline (table, TAL_2, 0, 2, 1); - tab_title (table, "%s", _("Multiple Response Sets")); - tab_text (table, 0, 0, TAB_EMPH | TAB_LEFT, _("Name")); - tab_text (table, 1, 0, TAB_EMPH | TAB_LEFT, _("Variables")); - tab_text (table, 2, 0, TAB_EMPH | TAB_LEFT, _("Details")); - - ds_init_empty (&details); - ds_init_empty (&var_names); - mrset_names = stringi_set_get_sorted_array (&mrset_names_set); - for (i = 0; i < n; i++) + struct pivot_table *table = pivot_table_create ( + N_("Multiple Response Sets")); + + pivot_dimension_create ( + table, PIVOT_AXIS_COLUMN, N_("Attributes"), + N_("Label"), N_("Encoding"), N_("Counted Value"), N_("Member Variables")); + + struct pivot_dimension *mrsets = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Name")); + mrsets->root->show_label = true; + + char **mrset_names = stringi_set_get_sorted_array (&mrset_names_set); + for (size_t i = 0; i < n; i++) { const struct mrset *mrset = dict_lookup_mrset (dict, mrset_names[i]); - const int row = i + 1; - size_t j; - - /* Details. */ - ds_clear (&details); - ds_put_format (&details, "%s\n", (mrset->type == MRSET_MD - ? _("Multiple dichotomy set") - : _("Multiple category set"))); + + int row = pivot_category_create_leaf ( + mrsets->root, pivot_value_new_user_text (mrset->name, -1)); + if (mrset->label != NULL) - ds_put_format (&details, "%s: %s\n", _("Label"), mrset->label); + pivot_table_put2 (table, 0, row, + pivot_value_new_user_text (mrset->label, -1)); + + pivot_table_put2 (table, 1, row, + pivot_value_new_text (mrset->type == MRSET_MD + ? _("Dichotomies") + : _("Categories"))); + if (mrset->type == MRSET_MD) - { - if (mrset->label != NULL || mrset->label_from_var_label) - ds_put_format (&details, "%s: %s\n", _("Label source"), - (mrset->label_from_var_label - ? _("First variable label among variables") - : _("Provided by user"))); - ds_put_format (&details, "%s: ", _("Counted value")); - if (mrset->width == 0) - ds_put_format (&details, "%.0f\n", mrset->counted.f); - else - { - const uint8_t *raw = value_str (&mrset->counted, mrset->width); - char *utf8 = recode_string ("UTF-8", dict_get_encoding (dict), - CHAR_CAST (const char *, raw), - mrset->width); - ds_put_format (&details, "`%s'\n", utf8); - free (utf8); - } - ds_put_format (&details, "%s: %s\n", _("Category label source"), - (mrset->cat_source == MRSET_VARLABELS - ? _("Variable labels") - : _("Value labels of counted value"))); - } + pivot_table_put2 (table, 2, row, + pivot_value_new_value ( + &mrset->counted, mrset->width, + &F_8_0, dict_get_encoding (dict))); /* Variable names. */ - ds_clear (&var_names); - for (j = 0; j < mrset->n_vars; j++) + struct string var_names = DS_EMPTY_INITIALIZER; + for (size_t j = 0; j < mrset->n_vars; j++) ds_put_format (&var_names, "%s\n", var_get_name (mrset->vars[j])); - - tab_text (table, 0, row, TAB_LEFT, mrset_names[i]); - tab_text (table, 1, row, TAB_LEFT, ds_cstr (&var_names)); - tab_text (table, 2, row, TAB_LEFT, ds_cstr (&details)); + ds_chomp_byte (&var_names, '\n'); + pivot_table_put2 (table, 3, row, + pivot_value_new_user_text_nocopy ( + ds_steal_cstr (&var_names))); } free (mrset_names); - ds_destroy (&var_names); - ds_destroy (&details); stringi_set_destroy (&mrset_names_set); - tab_submit (table); + pivot_table_submit (table); return true; } diff --git a/src/language/dictionary/split-file.c b/src/language/dictionary/split-file.c index fda5cfd00c..73cc20a057 100644 --- a/src/language/dictionary/split-file.c +++ b/src/language/dictionary/split-file.c @@ -31,11 +31,12 @@ #include "language/lexer/variable-parser.h" #include "libpspp/message.h" #include "libpspp/str.h" -#include "output/tab.h" +#include "output/pivot-table.h" #include "gl/xalloc.h" #include "gettext.h" +#define N_(msgid) msgid #define _(msgid) gettext (msgid) int @@ -67,38 +68,26 @@ void output_split_file_values (const struct dataset *ds, const struct ccase *c) { const struct dictionary *dict = dataset_dict (ds); - const struct variable *const *split; - struct tab_table *t; - size_t split_cnt; - int i; - - split_cnt = dict_get_split_cnt (dict); - if (split_cnt == 0) + size_t n_vars = dict_get_split_cnt (dict); + if (n_vars == 0) return; - t = tab_create (3, split_cnt + 1); - tab_text (t, 0, 0, TAB_NONE, _("Variable")); - tab_text (t, 1, 0, TAB_LEFT, _("Value")); - tab_text (t, 2, 0, TAB_LEFT, _("Label")); - split = dict_get_split_vars (dict); - for (i = 0; i < split_cnt; i++) - { - const struct variable *v = split[i]; - char *s; - const char *val_lab; - const struct fmt_spec *print = var_get_print_format (v); - - tab_text_format (t, 0, i + 1, TAB_LEFT, "%s", var_get_name (v)); - - s = data_out (case_data (c, v), dict_get_encoding (dict), print); + struct pivot_table *table = pivot_table_create (N_("Split Values")); + pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Value"), + N_("Value")); + struct pivot_dimension *variables = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Variable")); + variables->root->show_label = true; - tab_text_format (t, 1, i + 1, 0, "%.*s", print->w, s); - - free (s); + for (size_t i = 0; i < n_vars; i++) + { + const struct variable *v = dict_get_split_vars (dict)[i]; + int row = pivot_category_create_leaf (variables->root, + pivot_value_new_variable (v)); - val_lab = var_lookup_value_label (v, case_data (c, v)); - if (val_lab) - tab_text (t, 2, i + 1, TAB_LEFT, val_lab); + pivot_table_put2 (table, 0, row, + pivot_value_new_var_value (v, case_data (c, v))); } - tab_submit (t); + + pivot_table_submit (table); } diff --git a/src/language/dictionary/sys-file-info.c b/src/language/dictionary/sys-file-info.c index a0e6086232..9cb5510449 100644 --- a/src/language/dictionary/sys-file-info.c +++ b/src/language/dictionary/sys-file-info.c @@ -42,7 +42,7 @@ #include "libpspp/misc.h" #include "libpspp/pool.h" #include "libpspp/string-array.h" -#include "output/tab.h" +#include "output/pivot-table.h" #include "output/text-item.h" #include "output/table-item.h" @@ -89,6 +89,16 @@ static void report_encodings (const struct file_handle *, struct pool *, char **titles, bool *ids, char **strings, size_t n_strings); +static void +add_row (struct pivot_table *table, const char *attribute, + struct pivot_value *value) +{ + int row = pivot_category_create_leaf (table->dimensions[0]->root, + pivot_value_new_text (attribute)); + if (value) + pivot_table_put1 (table, row, value); +} + /* SYSFILE INFO utility. */ int cmd_sysfile_info (struct lexer *lexer, struct dataset *ds UNUSED) @@ -96,11 +106,9 @@ cmd_sysfile_info (struct lexer *lexer, struct dataset *ds UNUSED) struct any_reader *any_reader; struct file_handle *h; struct dictionary *d; - struct tab_table *t; struct casereader *reader; struct any_read_info info; char *encoding; - int r; h = NULL; encoding = NULL; @@ -171,76 +179,67 @@ cmd_sysfile_info (struct lexer *lexer, struct dataset *ds UNUSED) goto error; casereader_destroy (reader); - t = tab_create (2, 11 + (info.product_ext != NULL)); - r = 0; - - tab_text (t, 0, r, TAB_LEFT, _("File:")); - tab_text (t, 1, r++, TAB_LEFT, fh_get_file_name (h)); - - tab_text (t, 0, r, TAB_LEFT, _("Label:")); - { - const char *label = dict_get_label (d); - if (label == NULL) - label = _("No label."); - tab_text (t, 1, r++, TAB_LEFT, label); - } - - tab_text (t, 0, r, TAB_LEFT, _("Created:")); - tab_text_format (t, 1, r++, TAB_LEFT, "%s %s by %s", - info.creation_date, info.creation_time, info.product); - - if (info.product_ext) - { - tab_text (t, 0, r, TAB_LEFT, _("Product:")); - tab_text (t, 1, r++, TAB_LEFT, info.product_ext); - } - - tab_text (t, 0, r, TAB_LEFT, _("Integer Format:")); - tab_text (t, 1, r++, TAB_LEFT, - info.integer_format == INTEGER_MSB_FIRST ? _("Big Endian") - : info.integer_format == INTEGER_LSB_FIRST ? _("Little Endian") - : _("Unknown")); - - tab_text (t, 0, r, TAB_LEFT, _("Real Format:")); - tab_text (t, 1, r++, TAB_LEFT, - info.float_format == FLOAT_IEEE_DOUBLE_LE ? _("IEEE 754 LE.") - : info.float_format == FLOAT_IEEE_DOUBLE_BE ? _("IEEE 754 BE.") - : info.float_format == FLOAT_VAX_D ? _("VAX D.") - : info.float_format == FLOAT_VAX_G ? _("VAX G.") - : info.float_format == FLOAT_Z_LONG ? _("IBM 390 Hex Long.") - : _("Unknown")); - - tab_text (t, 0, r, TAB_LEFT, _("Variables:")); - tab_text_format (t, 1, r++, TAB_LEFT, "%zu", dict_get_var_cnt (d)); - - tab_text (t, 0, r, TAB_LEFT, _("Cases:")); - if (info.case_cnt == -1) - tab_text (t, 1, r, TAB_LEFT, _("Unknown")); - else - tab_text_format (t, 1, r, TAB_LEFT, "%ld", (long int) info.case_cnt); - r++; - - tab_text (t, 0, r, TAB_LEFT, _("Type:")); - tab_text (t, 1, r++, TAB_LEFT, gettext (info.klass->name)); + struct pivot_table *table = pivot_table_create (N_("File Information")); + pivot_dimension_create (table, PIVOT_AXIS_ROW, N_("Attribute")); - tab_text (t, 0, r, TAB_LEFT, _("Weight:")); - { - struct variable *weight_var = dict_get_weight (d); - tab_text (t, 1, r++, TAB_LEFT, - (weight_var != NULL - ? var_get_name (weight_var) : _("Not weighted."))); - } + add_row (table, N_("File"), + pivot_value_new_user_text (fh_get_file_name (h), -1)); - tab_text (t, 0, r, TAB_LEFT, _("Compression:")); - tab_text_format (t, 1, r++, TAB_LEFT, - info.compression == ANY_COMP_NONE ? _("None") - : info.compression == ANY_COMP_SIMPLE ? "SAV" - : "ZSAV"); + const char *label = dict_get_label (d); + add_row (table, N_("Label"), + label ? pivot_value_new_user_text (label, -1) : NULL); - tab_text (t, 0, r, TAB_LEFT, _("Encoding:")); - tab_text (t, 1, r++, TAB_LEFT, dict_get_encoding (d)); + add_row (table, N_("Created"), + pivot_value_new_user_text_nocopy ( + xasprintf ("%s %s by %s", info.creation_date, + info.creation_time, info.product))); - tab_submit (t); + if (info.product_ext) + add_row (table, N_("Product"), + pivot_value_new_user_text (info.product_ext, -1)); + + add_row (table, N_("Integer Format"), + pivot_value_new_text ( + info.integer_format == INTEGER_MSB_FIRST ? N_("Big Endian") + : info.integer_format == INTEGER_LSB_FIRST ? N_("Little Endian") + : N_("Unknown"))); + + add_row (table, N_("Real Format"), + pivot_value_new_text ( + info.float_format == FLOAT_IEEE_DOUBLE_LE ? N_("IEEE 754 LE.") + : info.float_format == FLOAT_IEEE_DOUBLE_BE ? N_("IEEE 754 BE.") + : info.float_format == FLOAT_VAX_D ? N_("VAX D.") + : info.float_format == FLOAT_VAX_G ? N_("VAX G.") + : info.float_format == FLOAT_Z_LONG ? N_("IBM 390 Hex Long.") + : N_("Unknown"))); + + add_row (table, N_("Variables"), + pivot_value_new_integer (dict_get_var_cnt (d))); + + add_row (table, N_("Cases"), + (info.case_cnt == -1 + ? pivot_value_new_text (N_("Unknown")) + : pivot_value_new_integer (info.case_cnt))); + + add_row (table, N_("Type"), + pivot_value_new_text (info.klass->name)); + + struct variable *weight_var = dict_get_weight (d); + add_row (table, N_("Weight"), + (weight_var + ? pivot_value_new_variable (weight_var) + : pivot_value_new_text (N_("Not weighted")))); + + add_row (table, N_("Compression"), + (info.compression == ANY_COMP_NONE + ? pivot_value_new_text (N_("None")) + : pivot_value_new_user_text ( + info.compression == ANY_COMP_SIMPLE ? "SAV" : "ZSAV", -1))); + + add_row (table, N_("Encoding"), + pivot_value_new_user_text (dict_get_encoding (d), -1)); + + pivot_table_submit (table); size_t n_vars = dict_get_var_cnt (d); const struct variable **vars = xnmalloc (n_vars, sizeof *vars); @@ -288,12 +287,16 @@ cmd_display (struct lexer *lexer, struct dataset *ds) { if (!lex_force_match_id (lexer, "LABEL")) return CMD_FAILURE; - if (dict_get_label (dataset_dict (ds)) == NULL) - tab_output_text (TAB_LEFT, - _("The active dataset does not have a file label.")); - else - tab_output_text_format (TAB_LEFT, _("File label: %s"), - dict_get_label (dataset_dict (ds))); + + const char *label = dict_get_label (dataset_dict (ds)); + + struct pivot_table *table = pivot_table_create (N_("File Label")); + pivot_dimension_create (table, PIVOT_AXIS_ROW, N_("Label"), + N_("Label")); + pivot_table_put1 (table, 0, + (label ? pivot_value_new_user_text (label, -1) + : pivot_value_new_text (N_("(none)")))); + pivot_table_submit (table); } else { @@ -391,36 +394,43 @@ cmd_display (struct lexer *lexer, struct dataset *ds) static void display_macros (void) { - tab_output_text (TAB_LEFT, _("Macros not supported.")); + msg (SW, _("Macros not supported.")); } static void display_documents (const struct dictionary *dict) { - const struct string_array *documents = dict_get_documents (dict); + struct pivot_table *table = pivot_table_create (N_("Documents")); + struct pivot_dimension *d = pivot_dimension_create ( + table, PIVOT_AXIS_COLUMN, N_("Documents"), N_("Document")); + d->hide_all_labels = true; - if (string_array_is_empty (documents)) - tab_output_text (TAB_LEFT, _("The active dataset dictionary does not " - "contain any documents.")); + const struct string_array *documents = dict_get_documents (dict); + if (!documents->n) + pivot_table_put1 (table, 0, pivot_value_new_text (N_("(none)"))); else { - size_t i; - - tab_output_text (TAB_LEFT | TAT_TITLE, - _("Documents in the active dataset:")); - for (i = 0; i < dict_get_document_line_cnt (dict); i++) - tab_output_text (TAB_LEFT | TAB_FIX, dict_get_document_line (dict, i)); + struct string s = DS_EMPTY_INITIALIZER; + for (size_t i = 0; i < documents->n; i++) + { + if (i) + ds_put_byte (&s, '\n'); + ds_put_cstr (&s, documents->strings[i]); + } + pivot_table_put1 (table, 0, + pivot_value_new_user_text_nocopy (ds_steal_cstr (&s))); } + + pivot_table_submit (table); } static void display_variables (const struct variable **vl, size_t n, int flags) { - int nc = count_one_bits (flags); - struct tab_table *t = tab_create (nc, n + 1); - tab_title (t, "%s", _("Variables")); - tab_headers (t, 0, 0, 1, 0); - tab_hline (t, TAL_2, 0, nc - 1, 1); + struct pivot_table *table = pivot_table_create (N_("Variables")); + + struct pivot_dimension *attributes = pivot_dimension_create ( + table, PIVOT_AXIS_COLUMN, N_("Attributes")); struct heading { @@ -428,7 +438,6 @@ display_variables (const struct variable **vl, size_t n, int flags) const char *title; }; static const struct heading headings[] = { - { DF_NAME, N_("Name") }, { DF_POSITION, N_("Position") }, { DF_LABEL, N_("Label") }, { DF_MEASUREMENT_LEVEL, N_("Measurement Level") }, @@ -439,97 +448,121 @@ display_variables (const struct variable **vl, size_t n, int flags) { DF_WRITE_FORMAT, N_("Write Format") }, { DF_MISSING_VALUES, N_("Missing Values") }, }; - for (size_t i = 0, x = 0; i < sizeof headings / sizeof *headings; i++) + for (size_t i = 0; i < sizeof headings / sizeof *headings; i++) if (flags & headings[i].flag) - tab_text (t, x++, 0, TAB_LEFT | TAT_TITLE, gettext (headings[i].title)); + pivot_category_create_leaf (attributes->root, + pivot_value_new_text (headings[i].title)); + + struct pivot_dimension *names = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Name")); + names->root->show_label = true; for (size_t i = 0; i < n; i++) { const struct variable *v = vl[i]; - size_t y = i + 1; - size_t x = 0; - if (flags & DF_NAME) - tab_text (t, x++, y, TAB_LEFT, var_get_name (v)); + + struct pivot_value *name = pivot_value_new_variable (v); + name->variable.show = SETTINGS_VALUE_SHOW_VALUE; + int row = pivot_category_create_leaf (names->root, name); + + int x = 0; if (flags & DF_POSITION) - { - char s[INT_BUFSIZE_BOUND (size_t)]; + pivot_table_put2 (table, x++, row, pivot_value_new_integer ( + var_get_dict_index (v) + 1)); - sprintf (s, "%zu", var_get_dict_index (v) + 1); - tab_text (t, x++, y, TAB_LEFT, s); - } if (flags & DF_LABEL) { const char *label = var_get_label (v); if (label) - tab_text (t, x, y, TAB_LEFT, label); + pivot_table_put2 (table, x, row, + pivot_value_new_user_text (label, -1)); x++; } + if (flags & DF_MEASUREMENT_LEVEL) - tab_text (t, x++, y, TAB_LEFT, - gettext (measure_to_string (var_get_measure (v)))); + pivot_table_put2 ( + table, x++, row, + pivot_value_new_text (measure_to_string (var_get_measure (v)))); + if (flags & DF_ROLE) - tab_text (t, x++, y, TAB_LEFT, - gettext (var_role_to_string (var_get_role (v)))); + pivot_table_put2 ( + table, x++, row, + pivot_value_new_text (var_role_to_string (var_get_role (v)))); + if (flags & DF_WIDTH) - { - char s[INT_BUFSIZE_BOUND (int)]; - sprintf (s, "%d", var_get_display_width (v)); - tab_text (t, x++, y, TAB_RIGHT, s); - } + pivot_table_put2 ( + table, x++, row, + pivot_value_new_integer (var_get_display_width (v))); + if (flags & DF_ALIGNMENT) - tab_text (t, x++, y, TAB_LEFT, - gettext (alignment_to_string (var_get_alignment (v)))); + pivot_table_put2 ( + table, x++, row, + pivot_value_new_text (alignment_to_string ( + var_get_alignment (v)))); + if (flags & DF_PRINT_FORMAT) { const struct fmt_spec *print = var_get_print_format (v); char s[FMT_STRING_LEN_MAX + 1]; - tab_text (t, x++, y, TAB_LEFT, fmt_to_string (print, s)); + pivot_table_put2 ( + table, x++, row, + pivot_value_new_user_text (fmt_to_string (print, s), -1)); } + if (flags & DF_WRITE_FORMAT) { const struct fmt_spec *write = var_get_write_format (v); char s[FMT_STRING_LEN_MAX + 1]; - tab_text (t, x++, y, TAB_LEFT, fmt_to_string (write, s)); + pivot_table_put2 ( + table, x++, row, + pivot_value_new_user_text (fmt_to_string (write, s), -1)); } + if (flags & DF_MISSING_VALUES) { - const struct missing_values *mv = var_get_missing_values (v); - - char *s = mv_to_string (mv, var_get_encoding (v)); + char *s = mv_to_string (var_get_missing_values (v), + var_get_encoding (v)); if (s) - { - tab_text (t, x, y, TAB_LEFT, s); - free (s); - } - x++; + pivot_table_put2 ( + table, x, row, + pivot_value_new_user_text_nocopy (s)); - assert (x == nc); + x++; } } - tab_submit (t); + pivot_table_submit (table); +} + +static bool +any_value_labels (const struct variable **vars, size_t n_vars) +{ + for (size_t i = 0; i < n_vars; i++) + if (val_labs_count (var_get_value_labels (vars[i]))) + return true; + return false; } static void display_value_labels (const struct variable **vars, size_t n_vars) { - size_t n_value_labels = 0; - for (size_t i = 0; i < n_vars; i++) - n_value_labels += val_labs_count (var_get_value_labels (vars[i])); - if (!n_value_labels) + if (!any_value_labels (vars, n_vars)) return; - struct tab_table *t = tab_create (3, n_value_labels + 1); - tab_title (t, "%s", _("Value Labels")); - tab_headers (t, 0, 0, 1, 0); - tab_hline (t, TAL_2, 0, 2, 1); - tab_text (t, 0, 0, TAB_LEFT | TAT_TITLE, _("Variable")); - tab_text (t, 1, 0, TAB_LEFT | TAT_TITLE, _("Value")); - tab_text (t, 2, 0, TAB_LEFT | TAT_TITLE, _("Label")); + struct pivot_table *table = pivot_table_create (N_("Value Labels")); + + pivot_dimension_create (table, PIVOT_AXIS_COLUMN, + N_("Label"), N_("Label")); + + struct pivot_dimension *values = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Variable Value")); + values->root->show_label = true; + + struct pivot_footnote *missing_footnote = pivot_table_create_footnote ( + table, pivot_value_new_text (N_("User-missing value"))); - int y = 1; for (size_t i = 0; i < n_vars; i++) { const struct val_labs *val_labs = var_get_value_labels (vars[i]); @@ -537,21 +570,44 @@ display_value_labels (const struct variable **vars, size_t n_vars) if (!n_labels) continue; - tab_joint_text (t, 0, y, 0, y + (n_labels - 1), TAB_LEFT, - var_get_name (vars[i])); + struct pivot_category *group = pivot_category_create_group__ ( + values->root, pivot_value_new_variable (vars[i])); const struct val_lab **labels = val_labs_sorted (val_labs); for (size_t j = 0; j < n_labels; j++) { const struct val_lab *vl = labels[j]; - tab_value (t, 1, y, TAB_NONE, &vl->value, vars[i], NULL); - tab_text (t, 2, y, TAB_LEFT, val_lab_get_escaped_label (vl)); - y++; + struct pivot_value *value = pivot_value_new_var_value ( + vars[i], &vl->value); + if (value->type == PIVOT_VALUE_NUMERIC) + value->numeric.show = SETTINGS_VALUE_SHOW_VALUE; + else + value->string.show = SETTINGS_VALUE_SHOW_VALUE; + if (var_is_value_missing (vars[i], &vl->value, MV_USER)) + pivot_value_add_footnote (value, missing_footnote); + int row = pivot_category_create_leaf (group, value); + + struct pivot_value *label = pivot_value_new_var_value ( + vars[i], &vl->value); + char *escaped_label = xstrdup (val_lab_get_escaped_label (vl)); + if (label->type == PIVOT_VALUE_NUMERIC) + { + free (label->numeric.value_label); + label->numeric.value_label = escaped_label; + label->numeric.show = SETTINGS_VALUE_SHOW_LABEL; + } + else + { + free (label->string.value_label); + label->string.value_label = escaped_label; + label->string.show = SETTINGS_VALUE_SHOW_LABEL; + } + pivot_table_put2 (table, 0, row, label); } free (labels); } - tab_submit (t); + pivot_table_submit (table); } static bool @@ -575,15 +631,19 @@ count_attributes (const struct attrset *set, int flags) return n_attrs; } -static int -display_attrset (const char *name, const struct attrset *set, int flags, - struct tab_table *t, int y) +static void +display_attrset (struct pivot_table *table, struct pivot_value *set_name, + const struct attrset *set, int flags) { size_t n_total = count_attributes (set, flags); if (!n_total) - return y; + { + pivot_value_destroy (set_name); + return; + } - tab_joint_text (t, 0, y, 0, y + (n_total - 1), TAB_LEFT, name); + struct pivot_category *group = pivot_category_create_group__ ( + table->dimensions[1]->root, set_name); size_t n_attrs = attrset_count (set); struct attribute **attrs = attrset_sorted (set); @@ -598,43 +658,44 @@ display_attrset (const char *name, const struct attrset *set, int flags, size_t n_values = attribute_get_n_values (attr); for (size_t j = 0; j < n_values; j++) { - if (n_values > 1) - tab_text_format (t, 1, y, TAB_LEFT, "%s[%zu]", name, j + 1); - else - tab_text (t, 1, y, TAB_LEFT, name); - tab_text (t, 2, y, TAB_LEFT, attribute_get_value (attr, j)); - y++; + int row = pivot_category_create_leaf ( + group, + (n_values > 1 + ? pivot_value_new_user_text_nocopy (xasprintf ( + "%s[%zu]", name, j + 1)) + : pivot_value_new_user_text (name, -1))); + pivot_table_put2 (table, 0, row, + pivot_value_new_user_text ( + attribute_get_value (attr, j), -1)); } } free (attrs); - - return y; } static void display_attributes (const struct attrset *dict_attrset, const struct variable **vars, size_t n_vars, int flags) { - size_t n_attributes = count_attributes (dict_attrset, flags); - for (size_t i = 0; i < n_vars; i++) - n_attributes += count_attributes (var_get_attributes (vars[i]), flags); - if (!n_attributes) - return; + struct pivot_table *table = pivot_table_create ( + N_("Variable and Dataset Attributes")); - struct tab_table *t = tab_create (3, n_attributes + 1); - tab_title (t, "%s", _("Variable and Dataset Attributes")); - tab_headers (t, 0, 0, 1, 0); - tab_hline (t, TAL_2, 0, 2, 1); - tab_text (t, 0, 0, TAB_LEFT | TAT_TITLE, _("Variable")); - tab_text (t, 1, 0, TAB_LEFT | TAT_TITLE, _("Name")); - tab_text (t, 2, 0, TAB_LEFT | TAT_TITLE, _("Value")); + pivot_dimension_create (table, PIVOT_AXIS_COLUMN, + N_("Value"), N_("Value")); - int y = display_attrset (_("(dataset)"), dict_attrset, flags, t, 1); + struct pivot_dimension *variables = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Variable and Name")); + variables->root->show_label = true; + + display_attrset (table, pivot_value_new_text (N_("(dataset)")), + dict_attrset, flags); for (size_t i = 0; i < n_vars; i++) - y = display_attrset (var_get_name (vars[i]), var_get_attributes (vars[i]), - flags, t, y); + display_attrset (table, pivot_value_new_variable (vars[i]), + var_get_attributes (vars[i]), flags); - tab_submit (t); + if (pivot_table_is_empty (table)) + pivot_table_destroy (table); + else + pivot_table_submit (table); } /* Display a list of vectors. If SORTED is nonzero then they are @@ -642,66 +703,52 @@ display_attributes (const struct attrset *dict_attrset, static void display_vectors (const struct dictionary *dict, int sorted) { - const struct vector **vl; - int i; - struct tab_table *t; - size_t nvec; - size_t nrow; - size_t row; - - nvec = dict_get_vector_cnt (dict); - if (nvec == 0) + size_t n_vectors = dict_get_vector_cnt (dict); + if (n_vectors == 0) { msg (SW, _("No vectors defined.")); return; } - vl = xnmalloc (nvec, sizeof *vl); - nrow = 0; - for (i = 0; i < nvec; i++) - { - vl[i] = dict_get_vector (dict, i); - nrow += vector_get_var_cnt (vl[i]); - } + const struct vector **vectors = xnmalloc (n_vectors, sizeof *vectors); + for (size_t i = 0; i < n_vectors; i++) + vectors[i] = dict_get_vector (dict, i); if (sorted) - qsort (vl, nvec, sizeof *vl, compare_vector_ptrs_by_name); - - t = tab_create (4, nrow + 1); - tab_headers (t, 0, 0, 1, 0); - tab_box (t, TAL_1, TAL_1, -1, -1, 0, 0, 3, nrow); - tab_box (t, -1, -1, -1, TAL_1, 0, 0, 3, nrow); - tab_hline (t, TAL_2, 0, 3, 1); - tab_text (t, 0, 0, TAT_TITLE | TAB_LEFT, _("Vector")); - tab_text (t, 1, 0, TAT_TITLE | TAB_LEFT, _("Position")); - tab_text (t, 2, 0, TAT_TITLE | TAB_LEFT, _("Variable")); - tab_text (t, 3, 0, TAT_TITLE | TAB_LEFT, _("Print Format")); - - row = 1; - for (i = 0; i < nvec; i++) + qsort (vectors, n_vectors, sizeof *vectors, compare_vector_ptrs_by_name); + + struct pivot_table *table = pivot_table_create (N_("Vectors")); + pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Attributes"), + N_("Variable"), N_("Print Format")); + struct pivot_dimension *vector_dim = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Vector and Position")); + vector_dim->root->show_label = true; + + for (size_t i = 0; i < n_vectors; i++) { - const struct vector *vec = vl[i]; - size_t j; + const struct vector *vec = vectors[i]; - tab_joint_text (t, 0, row, 0, row + vector_get_var_cnt (vec) - 1, - TAB_LEFT, vector_get_name (vl[i])); + struct pivot_category *group = pivot_category_create_group__ ( + vector_dim->root, pivot_value_new_user_text ( + vector_get_name (vectors[i]), -1)); - for (j = 0; j < vector_get_var_cnt (vec); j++) + for (size_t j = 0; j < vector_get_var_cnt (vec); j++) { struct variable *var = vector_get_var (vec, j); + + int row = pivot_category_create_leaf ( + group, pivot_value_new_integer (j + 1)); + + pivot_table_put2 (table, 0, row, pivot_value_new_variable (var)); char fmt_string[FMT_STRING_LEN_MAX + 1]; fmt_to_string (var_get_print_format (var), fmt_string); - - tab_text_format (t, 1, row, TAB_RIGHT, "%zu", j + 1); - tab_text (t, 2, row, TAB_LEFT, var_get_name (var)); - tab_text (t, 3, row, TAB_LEFT, fmt_string); - row++; + pivot_table_put2 (table, 1, row, + pivot_value_new_user_text (fmt_string, -1)); } - tab_hline (t, TAL_1, 0, 3, row); } - tab_submit (t); + pivot_table_submit (table); - free (vl); + free (vectors); } /* Encoding analysis. */ @@ -901,12 +948,9 @@ report_encodings (const struct file_handle *h, struct pool *pool, { struct encoding encodings[N_ENCODING_NAMES]; size_t n_encodings, n_unique_strings; - size_t i, j; - struct tab_table *t; - size_t row; n_encodings = 0; - for (i = 0; i < N_ENCODING_NAMES; i++) + for (size_t i = 0; i < N_ENCODING_NAMES; i++) { char **utf8_strings; struct encoding *e; @@ -919,7 +963,7 @@ report_encodings (const struct file_handle *h, struct pool *pool, /* Hash utf8_strings. */ hash = 0; - for (j = 0; j < n_strings; j++) + for (size_t j = 0; j < n_strings; j++) hash = hash_string (utf8_strings[j], hash); /* If there's a duplicate encoding, just mark it. */ @@ -942,68 +986,78 @@ report_encodings (const struct file_handle *h, struct pool *pool, return; } - t = tab_create (2, n_encodings + 1); - tab_title (t, _("Usable encodings for %s."), fh_get_name (h)); - tab_caption (t, _("Encodings that can successfully read %s (by specifying " - "the encoding name on the GET command's ENCODING " - "subcommand). Encodings that yield identical text are " - "listed together."), fh_get_name (h)); - tab_headers (t, 1, 0, 1, 0); - tab_box (t, TAL_1, TAL_1, -1, -1, 0, 0, 1, n_encodings); - tab_hline (t, TAL_1, 0, 1, 1); - tab_text (t, 0, 0, TAB_RIGHT, "#"); - tab_text (t, 1, 0, TAB_LEFT, _("Encodings")); - for (i = 0; i < n_encodings; i++) + /* Table of valid encodings. */ + struct pivot_table *table = pivot_table_create__ ( + pivot_value_new_text_format (N_("Usable encodings for %s."), + fh_get_name (h))); + table->caption = pivot_value_new_text_format ( + N_("Encodings that can successfully read %s (by specifying the encoding " + "name on the GET command's ENCODING subcommand). Encodings that " + "yield identical text are listed together."), + fh_get_name (h)); + + pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Encodings"), + N_("Encodings")); + struct pivot_dimension *number = pivot_dimension_create__ ( + table, PIVOT_AXIS_ROW, pivot_value_new_user_text ("#", -1)); + number->root->show_label = true; + + for (size_t i = 0; i < n_encodings; i++) { - struct string s; - - ds_init_empty (&s); - for (j = 0; j < 64; j++) + struct string s = DS_EMPTY_INITIALIZER; + for (size_t j = 0; j < 64; j++) if (encodings[i].encodings & (UINT64_C (1) << j)) ds_put_format (&s, "%s, ", encoding_names[j]); ds_chomp (&s, ss_cstr (", ")); - tab_text_format (t, 0, i + 1, TAB_RIGHT, "%zu", i + 1); - tab_text (t, 1, i + 1, TAB_LEFT, ds_cstr (&s)); - ds_destroy (&s); + int row = pivot_category_create_leaf (number->root, + pivot_value_new_integer (i + 1)); + pivot_table_put2 ( + table, 0, row, pivot_value_new_user_text_nocopy (ds_steal_cstr (&s))); } - tab_submit (t); + pivot_table_submit (table); n_unique_strings = 0; - for (i = 0; i < n_strings; i++) + for (size_t i = 0; i < n_strings; i++) if (!all_equal (encodings, n_encodings, i)) n_unique_strings++; if (!n_unique_strings) return; - t = tab_create (3, (n_encodings * n_unique_strings) + 1); - tab_title (t, _("%s encoded text strings."), fh_get_name (h)); - tab_caption (t, _("Text strings in the file dictionary that the previously " - "listed encodings interpret differently, along with the " - "interpretations.")); - tab_headers (t, 1, 0, 1, 0); - tab_box (t, TAL_1, TAL_1, -1, -1, 0, 0, 2, n_encodings * n_unique_strings); - tab_hline (t, TAL_1, 0, 2, 1); - - tab_text (t, 0, 0, TAB_LEFT, _("Purpose")); - tab_text (t, 1, 0, TAB_RIGHT, "#"); - tab_text (t, 2, 0, TAB_LEFT, _("Text")); - - row = 1; - for (i = 0; i < n_strings; i++) + /* Table of alternative interpretations. */ + table = pivot_table_create__ ( + pivot_value_new_text_format (N_("%s Encoded Text Strings"), + fh_get_name (h))); + table->caption = pivot_value_new_text ( + N_("Text strings in the file dictionary that the previously listed " + "encodings interpret differently, along with the interpretations.")); + + pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Text"), N_("Text")); + + number = pivot_dimension_create__ (table, PIVOT_AXIS_ROW, + pivot_value_new_user_text ("#", -1)); + number->root->show_label = true; + for (size_t i = 0; i < n_encodings; i++) + pivot_category_create_leaf (number->root, + pivot_value_new_integer (i + 1)); + + struct pivot_dimension *purpose = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Purpose")); + purpose->root->show_label = true; + + for (size_t i = 0; i < n_strings; i++) if (!all_equal (encodings, n_encodings, i)) { int prefix = equal_prefix (encodings, n_encodings, i); int suffix = equal_suffix (encodings, n_encodings, i); - tab_joint_text (t, 0, row, 0, row + n_encodings - 1, - TAB_LEFT, titles[i]); - tab_hline (t, TAL_1, 0, 2, row); - for (j = 0; j < n_encodings; j++) + int purpose_idx = pivot_category_create_leaf ( + purpose->root, pivot_value_new_user_text (titles[i], -1)); + + for (size_t j = 0; j < n_encodings; j++) { const char *s = encodings[j].utf8_strings[i] + prefix; - tab_text_format (t, 1, row, TAB_RIGHT, "%zu", j + 1); if (prefix || suffix) { size_t len = strlen (s) - suffix; @@ -1015,12 +1069,16 @@ report_encodings (const struct file_handle *h, struct pool *pool, ds_put_substring (&entry, ss_buffer (s, len)); if (suffix) ds_put_cstr (&entry, "..."); - tab_text (t, 2, row, TAB_LEFT, ds_cstr (&entry)); + + pivot_table_put3 (table, 0, j, purpose_idx, + pivot_value_new_user_text_nocopy ( + ds_steal_cstr (&entry))); } else - tab_text (t, 2, row, TAB_LEFT, s); - row++; + pivot_table_put3 (table, 0, j, purpose_idx, + pivot_value_new_user_text (s, -1)); } } - tab_submit (t); + + pivot_table_submit (table); } diff --git a/src/language/stats/binomial.c b/src/language/stats/binomial.c index 00f37ab8b7..0ab004364d 100644 --- a/src/language/stats/binomial.c +++ b/src/language/stats/binomial.c @@ -35,12 +35,13 @@ #include "libpspp/compiler.h" #include "libpspp/message.h" #include "libpspp/misc.h" -#include "output/tab.h" +#include "output/pivot-table.h" #include "gl/xalloc.h" #include "gl/minmax.h" #include "gettext.h" +#define N_(msgid) msgid #define _(msgid) gettext (msgid) static double calculate_binomial_internal (double n1, double n2, @@ -151,7 +152,6 @@ binomial_execute (const struct dataset *ds, bool exact UNUSED, double timer UNUSED) { - int v; const struct dictionary *dict = dataset_dict (ds); const struct one_sample_test *ost = UP_CAST (test, const struct one_sample_test, parent); const struct binomial_test *bst = UP_CAST (ost, const struct binomial_test, parent); @@ -170,7 +170,7 @@ binomial_execute (const struct dataset *ds, value = bst->category2; cat[i] = xnmalloc (ost->n_vars, sizeof *cat[i]); - for (v = 0; v < ost->n_vars; v++) + for (size_t v = 0; v < ost->n_vars; v++) { cat[i][v].values[0].f = value; cat[i][v].count = 0; @@ -179,88 +179,76 @@ binomial_execute (const struct dataset *ds, if (do_binomial (dataset_dict (ds), input, ost, cat[0], cat[1], exclude)) { - const struct fmt_spec *wfmt = dict_get_weight_format (dict); - - struct tab_table *table = tab_create (7, ost->n_vars * 3 + 1); - tab_set_format (table, RC_WEIGHT, wfmt); - - tab_title (table, _("Binomial Test")); - - tab_headers (table, 2, 0, 1, 0); - - tab_box (table, TAL_1, TAL_1, -1, TAL_1, - 0, 0, tab_nc (table) - 1, tab_nr(table) - 1 ); - - for (v = 0 ; v < ost->n_vars; ++v) + struct pivot_table *table = pivot_table_create (N_("Binomial Test")); + pivot_table_set_weight_var (table, dict_get_weight (dict)); + + pivot_dimension_create ( + table, PIVOT_AXIS_COLUMN, N_("Statistics"), + N_("Category"), + N_("N"), PIVOT_RC_COUNT, + N_("Observed Prop."), PIVOT_RC_OTHER, + N_("Test Prop."), PIVOT_RC_OTHER, + (bst->p == 0.5 + ? N_("Exact Sig. (2-tailed)") + : N_("Exact Sig. (1-tailed)")), PIVOT_RC_SIGNIFICANCE); + + pivot_dimension_create (table, PIVOT_AXIS_ROW, N_("Groups"), + N_("Group 1"), N_("Group 2"), N_("Total")); + + struct pivot_dimension *variables = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Variables")); + + for (size_t v = 0; v < ost->n_vars; ++v) { - double n_total, sig; - struct string catstr[2]; const struct variable *var = ost->vars[v]; - ds_init_empty (&catstr[0]); - ds_init_empty (&catstr[1]); + int var_idx = pivot_category_create_leaf ( + variables->root, pivot_value_new_variable (var)); - if ( bst->cutpoint != SYSMIS) - { - ds_put_format (&catstr[0], "<= %.*g", - DBL_DIG + 1, bst->cutpoint); - } + /* Category. */ + if (bst->cutpoint != SYSMIS) + pivot_table_put3 ( + table, 0, 0, var_idx, + pivot_value_new_user_text_nocopy ( + xasprintf ("<= %.*g", DBL_DIG + 1, bst->cutpoint))); else + for (int i = 0; i < 2; i++) + pivot_table_put3 ( + table, 0, i, var_idx, + pivot_value_new_var_value (var, cat[i][v].values)); + + double n_total = cat[0][v].count + cat[1][v].count; + double sig = calculate_binomial (cat[0][v].count, cat[1][v].count, + bst->p); + struct entry { - var_append_value_name (var, cat[0][v].values, &catstr[0]); - var_append_value_name (var, cat[1][v].values, &catstr[1]); + int stat_idx; + int group_idx; + double x; + } + entries[] = { + /* N. */ + { 1, 0, cat[0][v].count }, + { 1, 1, cat[1][v].count }, + { 1, 2, n_total }, + /* Observed Prop. */ + { 2, 0, cat[0][v].count / n_total }, + { 2, 1, cat[1][v].count / n_total }, + { 2, 2, 1.0 }, + /* Test Prop. */ + { 3, 0, bst->p }, + /* Significance. */ + { 4, 0, sig } + }; + for (size_t i = 0; i < sizeof entries / sizeof *entries; i++) + { + const struct entry *e = &entries[i]; + pivot_table_put3 (table, e->stat_idx, e->group_idx, + var_idx, pivot_value_new_number (e->x)); } - - tab_hline (table, TAL_1, 0, tab_nc (table) -1, 1 + v * 3); - - /* Titles */ - tab_text (table, 0, 1 + v * 3, TAB_LEFT, var_to_string (var)); - tab_text (table, 1, 1 + v * 3, TAB_LEFT, _("Group1")); - tab_text (table, 1, 2 + v * 3, TAB_LEFT, _("Group2")); - tab_text (table, 1, 3 + v * 3, TAB_LEFT, _("Total")); - - /* Test Prop */ - tab_double (table, 5, 1 + v * 3, TAB_NONE, bst->p, NULL, RC_OTHER); - - /* Category labels */ - tab_text (table, 2, 1 + v * 3, TAB_NONE, ds_cstr (&catstr[0])); - tab_text (table, 2, 2 + v * 3, TAB_NONE, ds_cstr (&catstr[1])); - - /* Observed N */ - tab_double (table, 3, 1 + v * 3, TAB_NONE, cat[0][v].count, NULL, RC_WEIGHT); - tab_double (table, 3, 2 + v * 3, TAB_NONE, cat[1][v].count, NULL, RC_WEIGHT); - - n_total = cat[0][v].count + cat[1][v].count; - tab_double (table, 3, 3 + v * 3, TAB_NONE, n_total, NULL, RC_WEIGHT); - - /* Observed Proportions */ - tab_double (table, 4, 1 + v * 3, TAB_NONE, - cat[0][v].count / n_total, NULL, RC_OTHER); - tab_double (table, 4, 2 + v * 3, TAB_NONE, - cat[1][v].count / n_total, NULL, RC_OTHER); - - tab_double (table, 4, 3 + v * 3, TAB_NONE, - (cat[0][v].count + cat[1][v].count) / n_total, NULL, RC_OTHER); - - /* Significance */ - sig = calculate_binomial (cat[0][v].count, cat[1][v].count, bst->p); - tab_double (table, 6, 1 + v * 3, TAB_NONE, sig, NULL, RC_PVALUE); - - ds_destroy (&catstr[0]); - ds_destroy (&catstr[1]); } - tab_text (table, 2, 0, TAB_CENTER, _("Category")); - tab_text (table, 3, 0, TAB_CENTER, _("N")); - tab_text (table, 4, 0, TAB_CENTER, _("Observed Prop.")); - tab_text (table, 5, 0, TAB_CENTER, _("Test Prop.")); - - tab_text_format (table, 6, 0, TAB_CENTER, - _("Exact Sig. (%d-tailed)"), - bst->p == 0.5 ? 2 : 1); - - tab_vline (table, TAL_2, 2, 0, tab_nr (table) -1); - tab_submit (table); + pivot_table_submit (table); } for (i = 0; i < 2; i++) diff --git a/src/language/stats/chisquare.c b/src/language/stats/chisquare.c index dd04749f98..df540651d7 100644 --- a/src/language/stats/chisquare.c +++ b/src/language/stats/chisquare.c @@ -38,11 +38,12 @@ #include "libpspp/hash-functions.h" #include "libpspp/message.h" #include "libpspp/taint.h" -#include "output/tab.h" +#include "output/pivot-table.h" #include "gl/xalloc.h" #include "gettext.h" +#define N_(msgid) msgid #define _(msgid) gettext (msgid) /* Adds frequency counts of each value of VAR in INPUT between LO and HI to @@ -125,158 +126,6 @@ create_freq_hash (const struct dictionary *dict, return casereader_destroy (input); } -static struct tab_table * -create_variable_frequency_table (const struct dictionary *dict, - struct casereader *input, - const struct chisquare_test *test, - int v, struct hmap *freq_hash) - -{ - int i; - const struct one_sample_test *ost = (const struct one_sample_test*)test; - int n_cells; - struct tab_table *table ; - const struct variable *var = ost->vars[v]; - - const struct variable *wvar = dict_get_weight (dict); - const struct fmt_spec *wfmt = wvar ? var_get_print_format (wvar) : & F_8_0; - - hmap_init (freq_hash); - if (!create_freq_hash (dict, input, var, freq_hash)) - { - freq_hmap_destroy (freq_hash, var_get_width (var)); - return NULL; - } - - n_cells = hmap_count (freq_hash); - - if ( test->n_expected > 0 && n_cells != test->n_expected ) - { - msg(ME, _("CHISQUARE test specified %d expected values, but" - " %d distinct values were encountered in variable %s."), - test->n_expected, n_cells, - var_get_name (var) - ); - freq_hmap_destroy (freq_hash, var_get_width (var)); - return NULL; - } - - table = tab_create(4, n_cells + 2); - tab_set_format (table, RC_WEIGHT, wfmt); - - tab_title (table, "%s", var_to_string(var)); - tab_text (table, 1, 0, TAB_LEFT, _("Observed N")); - tab_text (table, 2, 0, TAB_LEFT, _("Expected N")); - tab_text (table, 3, 0, TAB_LEFT, _("Residual")); - - tab_headers (table, 1, 0, 1, 0); - - tab_box (table, TAL_1, TAL_1, -1, -1, - 0, 0, tab_nc (table) - 1, tab_nr(table) - 1 ); - - tab_hline (table, TAL_1, 0, tab_nc(table) - 1, 1); - - tab_vline (table, TAL_2, 1, 0, tab_nr(table) - 1); - for ( i = 2 ; i < 4 ; ++i ) - tab_vline (table, TAL_1, i, 0, tab_nr(table) - 1); - - - tab_text (table, 0, tab_nr (table) - 1, TAB_LEFT, _("Total")); - - return table; -} - - -static struct tab_table * -create_combo_frequency_table (const struct dictionary *dict, const struct chisquare_test *test) -{ - int i; - const struct one_sample_test *ost = (const struct one_sample_test*)test; - - struct tab_table *table ; - - const struct fmt_spec *wfmt = dict_get_weight_format (dict); - - int n_cells = test->hi - test->lo + 1; - - table = tab_create(1 + ost->n_vars * 4, n_cells + 3); - tab_set_format (table, RC_WEIGHT, wfmt); - - tab_title (table, _("Frequencies")); - for ( i = 0 ; i < ost->n_vars ; ++i ) - { - const struct variable *var = ost->vars[i]; - tab_text (table, i * 4 + 1, 1, TAB_LEFT, _("Category")); - tab_text (table, i * 4 + 2, 1, TAB_LEFT, _("Observed N")); - tab_text (table, i * 4 + 3, 1, TAB_LEFT, _("Expected N")); - tab_text (table, i * 4 + 4, 1, TAB_LEFT, _("Residual")); - - tab_vline (table, TAL_2, i * 4 + 1, - 0, tab_nr (table) - 1); - - tab_vline (table, TAL_1, i * 4 + 2, - 0, tab_nr (table) - 1); - - tab_vline (table, TAL_1, i * 4 + 3, - 1, tab_nr (table) - 1); - - tab_vline (table, TAL_1, i * 4 + 4, - 1, tab_nr (table) - 1); - - - tab_joint_text (table, - i * 4 + 1, 0, - i * 4 + 4, 0, - TAB_CENTER, - var_to_string (var)); - } - - for ( i = test->lo ; i <= test->hi ; ++i ) - tab_double (table, 0, 2 + i - test->lo, TAB_LEFT, 1 + i - test->lo, NULL, RC_INTEGER); - - tab_headers (table, 1, 0, 2, 0); - - tab_box (table, TAL_1, TAL_1, -1, -1, - 0, 0, tab_nc (table) - 1, tab_nr(table) - 1 ); - - tab_hline (table, TAL_1, 1, tab_nc(table) - 1, 1); - tab_hline (table, TAL_1, 0, tab_nc(table) - 1, 2); - - tab_text (table, 0, tab_nr (table) - 1, TAB_LEFT, _("Total")); - - return table; -} - - -static struct tab_table * -create_stats_table (const struct chisquare_test *test) -{ - const struct one_sample_test *ost = (const struct one_sample_test*) test; - - struct tab_table *table; - table = tab_create (1 + ost->n_vars, 4); - tab_title (table, _("Test Statistics")); - tab_headers (table, 1, 0, 1, 0); - - tab_box (table, TAL_1, TAL_1, -1, -1, - 0, 0, tab_nc(table) - 1, tab_nr(table) - 1 ); - - tab_box (table, -1, -1, -1, TAL_1, - 1, 0, tab_nc(table) - 1, tab_nr(table) - 1 ); - - - tab_vline (table, TAL_2, 1, 0, tab_nr (table) - 1); - tab_hline (table, TAL_1, 0, tab_nc (table) - 1, 1); - - - tab_text (table, 0, 1, TAB_LEFT, _("Chi-Square")); - tab_text (table, 0, 2, TAB_LEFT, _("df")); - tab_text (table, 0, 3, TAB_LEFT, _("Asymp. Sig.")); - - return table; -} - - void chisquare_execute (const struct dataset *ds, struct casereader *input, @@ -290,7 +139,6 @@ chisquare_execute (const struct dataset *ds, struct chisquare_test *cst = UP_CAST (test, struct chisquare_test, parent.parent); struct one_sample_test *ost = &cst->parent; - int n_cells = 0; double total_expected = 0.0; double *df = xzalloc (sizeof (*df) * ost->n_vars); @@ -305,66 +153,78 @@ chisquare_execute (const struct dataset *ds, for ( v = 0 ; v < ost->n_vars ; ++v ) { const struct variable *var = ost->vars[v]; - double total_obs = 0.0; - struct hmap freq_hash; + + struct hmap freq_hash = HMAP_INITIALIZER (freq_hash); struct casereader *reader = casereader_create_filter_missing (casereader_clone (input), &var, 1, exclude, NULL, NULL); - struct tab_table *freq_table = - create_variable_frequency_table (dict, reader, cst, v, &freq_hash); + if (!create_freq_hash (dict, reader, var, &freq_hash)) + { + freq_hmap_destroy (&freq_hash, var_get_width (var)); + return; + } - struct freq **ff; + size_t n_cells = hmap_count (&freq_hash); + if (cst->n_expected > 0 && n_cells != cst->n_expected) + { + msg (ME, _("CHISQUARE test specified %d expected values, but " + "variable %s has %d distinct values."), + cst->n_expected, var_get_name (var), n_cells); + freq_hmap_destroy (&freq_hash, var_get_width (var)); + continue; + } + + struct pivot_table *table = pivot_table_create__ ( + pivot_value_new_variable (var)); + pivot_table_set_weight_var (table, dict_get_weight (dict)); - if ( NULL == freq_table ) - continue; - ff = freq_hmap_sort (&freq_hash, var_get_width (var)); + pivot_dimension_create ( + table, PIVOT_AXIS_COLUMN, N_("Statistics"), + N_("Observed N"), PIVOT_RC_COUNT, + N_("Expected N"), PIVOT_RC_OTHER, + N_("Residual"), PIVOT_RC_RESIDUAL); - n_cells = hmap_count (&freq_hash); + struct freq **ff = freq_hmap_sort (&freq_hash, var_get_width (var)); - for ( i = 0 ; i < n_cells ; ++i ) + double total_obs = 0.0; + for (size_t i = 0; i < n_cells; i++) total_obs += ff[i]->count; + struct pivot_dimension *values = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Value")); + values->root->show_label = true; + xsq[v] = 0.0; - for ( i = 0 ; i < n_cells ; ++i ) + for (size_t i = 0; i < n_cells; i++) { - struct string str; - double exp; - const union value *observed_value = &ff[i]->values[0]; - - ds_init_empty (&str); - var_append_value_name (var, observed_value, &str); - - /* The key */ - tab_text (freq_table, 0, i + 1, TAB_LEFT, ds_cstr (&str)); - ds_destroy (&str); - - - /* The observed N */ - tab_double (freq_table, 1, i + 1, TAB_NONE, - ff[i]->count, NULL, RC_WEIGHT); - - if ( cst->n_expected > 0 ) - exp = cst->expected[i] * total_obs / total_expected ; - else - exp = total_obs / (double) n_cells; - - tab_double (freq_table, 2, i + 1, TAB_NONE, - exp, NULL, RC_OTHER); - - /* The residual */ - tab_double (freq_table, 3, i + 1, TAB_NONE, - ff[i]->count - exp, NULL, RC_OTHER); + int row = pivot_category_create_leaf ( + values->root, pivot_value_new_var_value ( + var, &ff[i]->values[0])); + + double exp = (cst->n_expected > 0 + ? cst->expected[i] * total_obs / total_expected + : total_obs / (double) n_cells); + double entries[] = { + ff[i]->count, + exp, + ff[i]->count - exp, + }; + for (size_t j = 0; j < sizeof entries / sizeof *entries; j++) + pivot_table_put2 ( + table, j, row, pivot_value_new_number (entries[j])); xsq[v] += (ff[i]->count - exp) * (ff[i]->count - exp) / exp; } df[v] = n_cells - 1.0; - tab_double (freq_table, 1, i + 1, TAB_NONE, - total_obs, NULL, RC_WEIGHT); + int row = pivot_category_create_leaf ( + values->root, pivot_value_new_text (N_("Total"))); + pivot_table_put2 (table, 0, row, + pivot_value_new_number (total_obs)); - tab_submit (freq_table); + pivot_table_submit (table); freq_hmap_destroy (&freq_hash, var_get_width (var)); free (ff); @@ -372,22 +232,38 @@ chisquare_execute (const struct dataset *ds, } else /* ranged == true */ { - struct tab_table *freq_table = create_combo_frequency_table (dict, cst); - - n_cells = cst->hi - cst->lo + 1; - - for ( v = 0 ; v < ost->n_vars ; ++v ) + struct pivot_table *table = pivot_table_create (N_("Frequencies")); + pivot_table_set_weight_var (table, dict_get_weight (dict)); + + pivot_dimension_create ( + table, PIVOT_AXIS_COLUMN, N_("Statistics"), + N_("Category"), + N_("Observed N"), PIVOT_RC_COUNT, + N_("Expected N"), PIVOT_RC_OTHER, + N_("Residual"), PIVOT_RC_RESIDUAL); + + struct pivot_dimension *var_dim + = pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Variable")); + for ( size_t i = 0 ; i < ost->n_vars ; ++i ) + pivot_category_create_leaf (var_dim->root, + pivot_value_new_variable (ost->vars[i])); + + struct pivot_dimension *category_dim + = pivot_dimension_create (table, PIVOT_AXIS_ROW, N_("Category")); + size_t n_cells = cst->hi - cst->lo + 1; + for (size_t i = 0 ; i < n_cells; ++i ) + pivot_category_create_leaf (category_dim->root, + pivot_value_new_integer (i + 1)); + pivot_category_create_leaves (category_dim->root, N_("Total")); + + for ( size_t v = 0 ; v < ost->n_vars ; ++v ) { const struct variable *var = ost->vars[v]; - double total_obs = 0.0; struct casereader *reader = casereader_create_filter_missing (casereader_clone (input), &var, 1, exclude, NULL, NULL); - struct hmap freq_hash; - struct freq **ff; - - hmap_init (&freq_hash); + struct hmap freq_hash = HMAP_INITIALIZER (freq_hash); if (!create_freq_hash_with_range (dict, reader, var, cst->lo, cst->hi, &freq_hash)) { @@ -395,79 +271,76 @@ chisquare_execute (const struct dataset *ds, continue; } - ff = freq_hmap_sort (&freq_hash, var_get_width (var)); + struct freq **ff = freq_hmap_sort (&freq_hash, var_get_width (var)); - for ( i = 0 ; i < hmap_count (&freq_hash) ; ++i ) + double total_obs = 0.0; + for ( size_t i = 0 ; i < hmap_count (&freq_hash) ; ++i ) total_obs += ff[i]->count; xsq[v] = 0.0; - for ( i = 0 ; i < hmap_count (&freq_hash) ; ++i ) + for ( size_t i = 0 ; i < hmap_count (&freq_hash) ; ++i ) { - struct string str; - double exp; - - const union value *observed_value = &ff[i]->values[0]; + /* Category. */ + pivot_table_put3 (table, 0, v, i, + pivot_value_new_var_value ( + var, &ff[i]->values[0])); + + double exp = (cst->n_expected > 0 + ? cst->expected[i] * total_obs / total_expected + : total_obs / (double) hmap_count (&freq_hash)); + double entries[] = { + ff[i]->count, + exp, + ff[i]->count - exp, + }; + for (size_t j = 0; j < sizeof entries / sizeof *entries; j++) + pivot_table_put3 (table, j + 1, v, i, + pivot_value_new_number (entries[j])); - ds_init_empty (&str); - var_append_value_name (ost->vars[v], observed_value, &str); - /* The key */ - tab_text (freq_table, v * 4 + 1, i + 2 , TAB_LEFT, - ds_cstr (&str)); - ds_destroy (&str); - - /* The observed N */ - tab_double (freq_table, v * 4 + 2, i + 2 , TAB_NONE, - ff[i]->count, NULL, RC_WEIGHT); - - if ( cst->n_expected > 0 ) - exp = cst->expected[i] * total_obs / total_expected ; - else - exp = total_obs / (double) hmap_count (&freq_hash); - - /* The expected N */ - tab_double (freq_table, v * 4 + 3, i + 2 , TAB_NONE, - exp, NULL, RC_OTHER); - - /* The residual */ - tab_double (freq_table, v * 4 + 4, i + 2 , TAB_NONE, - ff[i]->count - exp, NULL, RC_OTHER); xsq[v] += (ff[i]->count - exp) * (ff[i]->count - exp) / exp; } - - tab_double (freq_table, v * 4 + 2, tab_nr (freq_table) - 1, TAB_NONE, - total_obs, NULL, RC_WEIGHT); - df[v] = n_cells - 1.0; freq_hmap_destroy (&freq_hash, var_get_width (var)); free (ff); + + pivot_table_put3 (table, 1, v, n_cells, + pivot_value_new_number (total_obs)); } - tab_submit (freq_table); + pivot_table_submit (table); } ok = !taint_has_tainted_successor (casereader_get_taint (input)); casereader_destroy (input); if (ok) { - struct tab_table *stats_table = create_stats_table (cst); + struct pivot_table *table = pivot_table_create (N_("Test Statistics")); - /* Populate the summary statistics table */ - for ( v = 0 ; v < ost->n_vars ; ++v ) + pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Statistics"), + N_("Chi-square"), PIVOT_RC_OTHER, + N_("df"), PIVOT_RC_INTEGER, + N_("Asymp. Sig."), PIVOT_RC_SIGNIFICANCE); + + struct pivot_dimension *variables = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Variable")); + + for ( size_t v = 0 ; v < ost->n_vars ; ++v ) { const struct variable *var = ost->vars[v]; - tab_text (stats_table, 1 + v, 0, TAB_CENTER, var_get_name (var)); - - tab_double (stats_table, 1 + v, 1, TAB_NONE, xsq[v], NULL, RC_OTHER); - tab_double (stats_table, 1 + v, 2, TAB_NONE, df[v], NULL, RC_INTEGER); + int row = pivot_category_create_leaf ( + variables->root, pivot_value_new_variable (var)); - tab_double (stats_table, 1 + v, 3, TAB_NONE, - gsl_cdf_chisq_Q (xsq[v], df[v]), NULL, RC_PVALUE); + double sig = gsl_cdf_chisq_Q (xsq[v], df[v]); + double entries[] = { xsq[v], df[v], sig }; + for (size_t i = 0; i < sizeof entries / sizeof *entries; i++) + pivot_table_put2 (table, i, row, + pivot_value_new_number (entries[i])); } - tab_submit (stats_table); + pivot_table_submit (table); } free (xsq); diff --git a/src/language/stats/cochran.c b/src/language/stats/cochran.c index 091715694e..480248637f 100644 --- a/src/language/stats/cochran.c +++ b/src/language/stats/cochran.c @@ -32,9 +32,10 @@ #include "libpspp/cast.h" #include "libpspp/message.h" #include "libpspp/misc.h" -#include "output/tab.h" +#include "output/pivot-table.h" #include "gettext.h" +#define N_(msgid) msgid #define _(msgid) gettext (msgid) struct cochran @@ -146,103 +147,53 @@ cochran_execute (const struct dataset *ds, static void show_freqs_box (const struct one_sample_test *ost, const struct cochran *ct) { - int i; - const struct fmt_spec *wfmt = dict_get_weight_format (ct->dict); - - const int row_headers = 1; - const int column_headers = 2; - struct tab_table *table = - tab_create (row_headers + 2, column_headers + ost->n_vars); - tab_set_format (table, RC_WEIGHT, wfmt); - - tab_headers (table, row_headers, 0, column_headers, 0); - - tab_title (table, _("Frequencies")); - - /* Vertical lines inside the box */ - tab_box (table, 1, 0, -1, TAL_1, - row_headers, 0, tab_nc (table) - 1, tab_nr (table) - 1 ); - - /* Box around the table */ - tab_box (table, TAL_2, TAL_2, -1, -1, - 0, 0, tab_nc (table) - 1, tab_nr (table) - 1 ); - - tab_joint_text (table, 1, 0, 2, 0, - TAT_TITLE | TAB_CENTER, _("Value")); - - tab_text_format (table, 1, 1, 0, _("Success (%.*g)"), - DBL_DIG + 1, ct->success); - tab_text_format (table, 2, 1, 0, _("Failure (%.*g)"), - DBL_DIG + 1, ct->failure); - - tab_hline (table, TAL_2, 0, tab_nc (table) - 1, column_headers); - tab_vline (table, TAL_2, row_headers, 0, tab_nr (table) - 1); - - for (i = 0 ; i < ost->n_vars ; ++i) + struct pivot_table *table = pivot_table_create (N_("Frequencies")); + pivot_table_set_weight_var (table, dict_get_weight (ct->dict)); + + char *success = xasprintf (_("Success (%.*g)"), DBL_DIG + 1, ct->success); + char *failure = xasprintf (_("Failure (%.*g)"), DBL_DIG + 1, ct->failure); + struct pivot_dimension *values = pivot_dimension_create ( + table, PIVOT_AXIS_COLUMN, N_("Value"), + success, PIVOT_RC_COUNT, + failure, PIVOT_RC_COUNT); + values->root->show_label = true; + free (failure); + free (success); + + struct pivot_dimension *variables = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Variable")); + + for (size_t i = 0 ; i < ost->n_vars ; ++i) { - tab_text (table, 0, column_headers + i, - TAB_LEFT, var_to_string (ost->vars[i])); + int row = pivot_category_create_leaf ( + variables->root, pivot_value_new_variable (ost->vars[i])); - tab_double (table, 1, column_headers + i, 0, - ct->hits[i], NULL, RC_WEIGHT); - - tab_double (table, 2, column_headers + i, 0, - ct->misses[i], NULL, RC_WEIGHT); + pivot_table_put2 (table, 0, row, pivot_value_new_number (ct->hits[i])); + pivot_table_put2 (table, 1, row, pivot_value_new_number (ct->misses[i])); } - tab_submit (table); + pivot_table_submit (table); } - - static void show_sig_box (const struct cochran *ch) { - const struct fmt_spec *wfmt = dict_get_weight_format (ch->dict); - - const int row_headers = 1; - const int column_headers = 0; - struct tab_table *table = - tab_create (row_headers + 1, column_headers + 4); - - - tab_set_format (table, RC_WEIGHT, wfmt); - - tab_headers (table, row_headers, 0, column_headers, 0); - - tab_title (table, _("Test Statistics")); - - tab_text (table, 0, column_headers, - TAT_TITLE | TAB_LEFT , _("N")); - - tab_text (table, 0, 1 + column_headers, - TAT_TITLE | TAB_LEFT , _("Cochran's Q")); - - tab_text (table, 0, 2 + column_headers, - TAT_TITLE | TAB_LEFT, _("df")); - - tab_text (table, 0, 3 + column_headers, - TAT_TITLE | TAB_LEFT, _("Asymp. Sig.")); - - /* Box around the table */ - tab_box (table, TAL_2, TAL_2, -1, -1, - 0, 0, tab_nc (table) - 1, tab_nr (table) - 1 ); - - tab_hline (table, TAL_2, 0, tab_nc (table) -1, column_headers); - tab_vline (table, TAL_2, row_headers, 0, tab_nr (table) - 1); - - tab_double (table, 1, column_headers, - 0, ch->cc, NULL, RC_WEIGHT); + struct pivot_table *table = pivot_table_create (N_("Test Statistics")); - tab_double (table, 1, column_headers + 1, - 0, ch->q, NULL, RC_OTHER); + pivot_table_set_weight_format (table, dict_get_weight_format (ch->dict)); - tab_double (table, 1, column_headers + 2, - 0, ch->df, NULL, RC_INTEGER); + pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Value"), N_("Value")); - tab_double (table, 1, column_headers + 3, - 0, gsl_cdf_chisq_Q (ch->q, ch->df), - NULL, RC_PVALUE); + pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Statistics"), + N_("N"), PIVOT_RC_COUNT, + N_("Cochran's Q"), PIVOT_RC_SIGNIFICANCE, + N_("df"), PIVOT_RC_INTEGER, + N_("Asymp. Sig."), PIVOT_RC_SIGNIFICANCE); - tab_submit (table); + double sig = gsl_cdf_chisq_Q (ch->q, ch->df); + double entries[] = { ch->cc, ch->q, ch->df, sig }; + for (size_t i = 0; i < sizeof entries / sizeof *entries; i++) + pivot_table_put2 (table, 0, i, pivot_value_new_number (entries[i])); + pivot_table_submit (table); } diff --git a/src/language/stats/correlations.c b/src/language/stats/correlations.c index 207ec77528..826a640a8e 100644 --- a/src/language/stats/correlations.c +++ b/src/language/stats/correlations.c @@ -36,7 +36,7 @@ #include "math/correlation.h" #include "math/covariance.h" #include "math/moments.h" -#include "output/tab.h" +#include "output/pivot-table.h" #include "gl/xalloc.h" #include "gl/minmax.h" @@ -83,77 +83,39 @@ struct corr_opts static void -output_descriptives (const struct corr *corr, const gsl_matrix *means, +output_descriptives (const struct corr *corr, const struct corr_opts *opts, + const gsl_matrix *means, const gsl_matrix *vars, const gsl_matrix *ns) { - const int nr = corr->n_vars_total + 1; - const int nc = 4; - int c, r; + struct pivot_table *table = pivot_table_create ( + N_("Descriptive Statistics")); + pivot_table_set_weight_var (table, opts->wv); - const int heading_columns = 1; - const int heading_rows = 1; + pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Statistics"), + N_("Mean"), PIVOT_RC_OTHER, + N_("Std. Deviation"), PIVOT_RC_OTHER, + N_("N"), PIVOT_RC_COUNT); - struct tab_table *t = tab_create (nc, nr); - tab_title (t, _("Descriptive Statistics")); + struct pivot_dimension *variables = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Variable")); - tab_headers (t, heading_columns, 0, heading_rows, 0); - - /* Outline the box */ - tab_box (t, - TAL_2, TAL_2, - -1, -1, - 0, 0, - nc - 1, nr - 1); - - /* Vertical lines */ - tab_box (t, - -1, -1, - -1, TAL_1, - heading_columns, 0, - nc - 1, nr - 1); - - tab_vline (t, TAL_2, heading_columns, 0, nr - 1); - tab_hline (t, TAL_1, 0, nc - 1, heading_rows); - - tab_text (t, 1, 0, TAB_CENTER | TAT_TITLE, _("Mean")); - tab_text (t, 2, 0, TAB_CENTER | TAT_TITLE, _("Std. Deviation")); - tab_text (t, 3, 0, TAB_CENTER | TAT_TITLE, _("N")); - - for (r = 0 ; r < corr->n_vars_total ; ++r) + for (size_t r = 0 ; r < corr->n_vars_total ; ++r) { const struct variable *v = corr->vars[r]; - tab_text (t, 0, r + heading_rows, TAB_LEFT | TAT_TITLE, var_to_string (v)); - - for (c = 1 ; c < nc ; ++c) - { - double x ; - double n; - switch (c) - { - case 1: - x = gsl_matrix_get (means, r, 0); - break; - case 2: - x = gsl_matrix_get (vars, r, 0); - /* Here we want to display the non-biased estimator */ - n = gsl_matrix_get (ns, r, 0); - x *= n / (n -1); - - x = sqrt (x); - break; - case 3: - x = gsl_matrix_get (ns, r, 0); - break; - default: - NOT_REACHED (); - }; + int row = pivot_category_create_leaf (variables->root, + pivot_value_new_variable (v)); - tab_double (t, c, r + heading_rows, 0, x, NULL, RC_OTHER); - } + double mean = gsl_matrix_get (means, r, 0); + /* Here we want to display the non-biased estimator */ + double n = gsl_matrix_get (ns, r, 0); + double stddev = sqrt (gsl_matrix_get (vars, r, 0) * n / (n - 1)); + double entries[] = { mean, stddev, n }; + for (size_t i = 0; i < sizeof entries / sizeof *entries; i++) + pivot_table_put2 (table, i, row, pivot_value_new_number (entries[i])); } - tab_submit (t); + pivot_table_submit (table); } static void @@ -161,123 +123,84 @@ output_correlation (const struct corr *corr, const struct corr_opts *opts, const gsl_matrix *cm, const gsl_matrix *samples, const gsl_matrix *cv) { - int r, c; - struct tab_table *t; - int matrix_cols; - int nr = corr->n_vars1; - int nc = matrix_cols = corr->n_vars_total > corr->n_vars1 ? - corr->n_vars_total - corr->n_vars1 : corr->n_vars1; - - const struct fmt_spec *wfmt = opts->wv ? var_get_print_format (opts->wv) : & F_8_0; - - const int heading_columns = 2; - const int heading_rows = 1; - - int rows_per_variable = opts->missing_type == CORR_LISTWISE ? 2 : 3; - - if (opts->statistics & STATS_XPROD) - rows_per_variable += 2; - - /* Two header columns */ - nc += heading_columns; - - /* Three data per variable */ - nr *= rows_per_variable; - - /* One header row */ - nr += heading_rows; - - t = tab_create (nc, nr); - tab_set_format (t, RC_WEIGHT, wfmt); - tab_title (t, _("Correlations")); - - tab_headers (t, heading_columns, 0, heading_rows, 0); - - /* Outline the box */ - tab_box (t, - TAL_2, TAL_2, - -1, -1, - 0, 0, - nc - 1, nr - 1); + struct pivot_table *table = pivot_table_create (N_("Correlations")); + pivot_table_set_weight_var (table, opts->wv); - /* Vertical lines */ - tab_box (t, - -1, -1, - -1, TAL_1, - heading_columns, 0, - nc - 1, nr - 1); + /* Column variable dimension. */ + struct pivot_dimension *columns = pivot_dimension_create ( + table, PIVOT_AXIS_COLUMN, N_("Variables")); - tab_vline (t, TAL_2, heading_columns, 0, nr - 1); - - tab_vline (t, TAL_1, 1, heading_rows, nr - 1); - - /* Row Headers */ - for (r = 0 ; r < corr->n_vars1 ; ++r) - { - tab_text (t, 0, 1 + r * rows_per_variable, TAB_LEFT | TAT_TITLE, - var_to_string (corr->vars[r])); - - tab_text (t, 1, 1 + r * rows_per_variable, TAB_LEFT | TAT_TITLE, _("Pearson Correlation")); - tab_text (t, 1, 2 + r * rows_per_variable, TAB_LEFT | TAT_TITLE, - (opts->tails == 2) ? _("Sig. (2-tailed)") : _("Sig. (1-tailed)")); - - if (opts->statistics & STATS_XPROD) - { - tab_text (t, 1, 3 + r * rows_per_variable, TAB_LEFT | TAT_TITLE, _("Cross-products")); - tab_text (t, 1, 4 + r * rows_per_variable, TAB_LEFT | TAT_TITLE, _("Covariance")); - } - - if ( opts->missing_type != CORR_LISTWISE ) - tab_text (t, 1, rows_per_variable + r * rows_per_variable, TAB_LEFT | TAT_TITLE, _("N")); - - tab_hline (t, TAL_1, 0, nc - 1, r * rows_per_variable + 1); - } - - /* Column Headers */ - for (c = 0 ; c < matrix_cols ; ++c) + int matrix_cols = (corr->n_vars_total > corr->n_vars1 + ? corr->n_vars_total - corr->n_vars1 + : corr->n_vars1); + for (int c = 0; c < matrix_cols; c++) { const struct variable *v = corr->n_vars_total > corr->n_vars1 ? corr->vars[corr->n_vars1 + c] : corr->vars[c]; - tab_text (t, heading_columns + c, 0, TAB_LEFT | TAT_TITLE, var_to_string (v)); + pivot_category_create_leaf (columns->root, pivot_value_new_variable (v)); } - for (r = 0 ; r < corr->n_vars1 ; ++r) - { - const int row = r * rows_per_variable + heading_rows; - for (c = 0 ; c < matrix_cols ; ++c) - { - unsigned char flags = 0; - const int col_index = corr->n_vars_total > corr->n_vars1 ? - corr->n_vars1 + c : - c; - double pearson = gsl_matrix_get (cm, r, col_index); - double w = gsl_matrix_get (samples, r, col_index); - double sig = opts->tails * significance_of_correlation (pearson, w); - - if ( opts->missing_type != CORR_LISTWISE ) - tab_double (t, c + heading_columns, row + rows_per_variable - 1, 0, w, NULL, RC_WEIGHT); + /* Statistics dimension. */ + struct pivot_dimension *statistics = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Statistics"), + N_("Pearson Correlation"), PIVOT_RC_CORRELATION, + opts->tails == 2 ? N_("Sig. (2-tailed)") : N_("Sig. (1-tailed)"), + PIVOT_RC_SIGNIFICANCE); - if ( col_index != r) - tab_double (t, c + heading_columns, row + 1, 0, sig, NULL, RC_PVALUE); + if (opts->statistics & STATS_XPROD) + pivot_category_create_leaves (statistics->root, N_("Cross-products"), + N_("Covariance")); - if ( opts->sig && col_index != r && sig < 0.05) - flags = TAB_EMPH; + if (opts->missing_type != CORR_LISTWISE) + pivot_category_create_leaves (statistics->root, N_("N"), PIVOT_RC_COUNT); - tab_double (t, c + heading_columns, row, flags, pearson, NULL, RC_OTHER); + /* Row variable dimension. */ + struct pivot_dimension *rows = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Variables")); + for (size_t r = 0; r < corr->n_vars1; r++) + pivot_category_create_leaf (rows->root, + pivot_value_new_variable (corr->vars[r])); - if (opts->statistics & STATS_XPROD) - { - double cov = gsl_matrix_get (cv, r, col_index); - const double xprod_dev = cov * w; - cov *= w / (w - 1.0); + struct pivot_footnote *sig_footnote = pivot_table_create_footnote ( + table, pivot_value_new_text (N_("Significant at .05 level"))); - tab_double (t, c + heading_columns, row + 2, 0, xprod_dev, NULL, RC_OTHER); - tab_double (t, c + heading_columns, row + 3, 0, cov, NULL, RC_OTHER); - } - } - } + for (int r = 0; r < corr->n_vars1; r++) + for (int c = 0; c < matrix_cols; c++) + { + const int col_index = (corr->n_vars_total > corr->n_vars1 + ? corr->n_vars1 + c + : c); + double pearson = gsl_matrix_get (cm, r, col_index); + double w = gsl_matrix_get (samples, r, col_index); + double sig = opts->tails * significance_of_correlation (pearson, w); + + double entries[5]; + int n = 0; + entries[n++] = pearson; + entries[n++] = col_index != r ? sig : SYSMIS; + if (opts->statistics & STATS_XPROD) + { + double cov = gsl_matrix_get (cv, r, col_index); + const double xprod_dev = cov * w; + cov *= w / (w - 1.0); + + entries[n++] = xprod_dev; + entries[n++] = cov; + } + if (opts->missing_type != CORR_LISTWISE) + entries[n++] = w; + + for (int i = 0; i < n; i++) + if (entries[i] != SYSMIS) + { + struct pivot_value *v = pivot_value_new_number (entries[i]); + if (!i && opts->sig && col_index != r && sig < 0.05) + pivot_value_add_footnote (v, sig_footnote); + pivot_table_put3 (table, c, i, r, v); + } + } - tab_submit (t); + pivot_table_submit (table); } @@ -319,7 +242,7 @@ run_corr (struct casereader *r, const struct corr_opts *opts, const struct corr corr_matrix = correlation_from_covariance (cov_matrix, var_matrix); if ( opts->statistics & STATS_DESCRIPTIVES) - output_descriptives (corr, mean_matrix, var_matrix, samples_matrix); + output_descriptives (corr, opts, mean_matrix, var_matrix, samples_matrix); output_correlation (corr, opts, corr_matrix, samples_matrix, cov_matrix); diff --git a/src/language/stats/crosstabs.q b/src/language/stats/crosstabs.q index c44ccf64c7..dfafbe9f3e 100644 --- a/src/language/stats/crosstabs.q +++ b/src/language/stats/crosstabs.q @@ -55,7 +55,7 @@ #include "libpspp/misc.h" #include "libpspp/pool.h" #include "libpspp/str.h" -#include "output/tab.h" +#include "output/pivot-table.h" #include "output/chart-item.h" #include "output/charts/barchart.h" @@ -131,6 +131,7 @@ struct crosstabulation /* Constants (0 or more). */ int n_consts; struct xtab_var *const_vars; + size_t *const_indexes; /* Data. */ struct hmap data; @@ -203,7 +204,6 @@ static void tabulate_general_case (struct crosstabulation *, const struct ccase static void tabulate_integer_case (struct crosstabulation *, const struct ccase *, double weight); static void postcalc (struct crosstabs_proc *); -static void submit (struct crosstabulation *, struct tab_table *); static double round_weight (const struct crosstabs_proc *proc, double weight) @@ -211,6 +211,33 @@ round_weight (const struct crosstabs_proc *proc, double weight) return proc->round_down ? floor (weight) : floor (weight + 0.5); } +#define FOR_EACH_POPULATED_COLUMN(C, XT) \ + for (int C = next_populated_column (0, XT); \ + C < (XT)->vars[COL_VAR].n_values; \ + C = next_populated_column (C + 1, XT)) +static int +next_populated_column (int c, const struct crosstabulation *xt) +{ + int n_columns = xt->vars[COL_VAR].n_values; + for (; c < n_columns; c++) + if (xt->col_tot[c]) + break; + return c; +} + +#define FOR_EACH_POPULATED_ROW(R, XT) \ + for (int R = next_populated_row (0, XT); R < (XT)->vars[ROW_VAR].n_values; \ + R = next_populated_row (R + 1, XT)) +static int +next_populated_row (int r, const struct crosstabulation *xt) +{ + int n_rows = xt->vars[ROW_VAR].n_values; + for (; r < n_rows; r++) + if (xt->row_tot[r]) + break; + return r; +} + /* Parses and executes the CROSSTABS procedure. */ int cmd_crosstabs (struct lexer *lexer, struct dataset *ds) @@ -806,16 +833,26 @@ make_crosstabulation_subset (struct crosstabulation *xt, size_t row0, if (xt->n_vars > 2) { assert (xt->n_consts == 0); - subset->missing = xt->missing; subset->n_vars = 2; subset->vars = xt->vars; subset->n_consts = xt->n_vars - 2; subset->const_vars = xt->vars + 2; + subset->const_indexes = xcalloc (subset->n_consts, + sizeof *subset->const_indexes); for (size_t i = 0; i < subset->n_consts; i++) { - subset->const_vars[i].n_values = 1; - subset->const_vars[i].values = &xt->entries[row0]->values[2 + i]; + const union value *value = &xt->entries[row0]->values[2 + i]; + + for (size_t j = 0; j < xt->vars[2 + i].n_values; j++) + if (value_equal (&xt->vars[2 + i].values[j], value, + var_get_width (xt->vars[2 + i].var))) + { + subset->const_indexes[i] = j; + goto found; + } + NOT_REACHED (); + found: ; } } subset->entries = &xt->entries[row0]; @@ -879,115 +916,80 @@ compare_table_entry_3way_inv (const void *ap_, const void *bp_, const void *xt_) return -compare_table_entry_3way (ap_, bp_, xt_); } -static int -find_first_difference (const struct crosstabulation *xt, size_t row) -{ - if (row == 0) - return xt->n_vars - 1; - else - { - const struct freq *a = xt->entries[row]; - const struct freq *b = xt->entries[row - 1]; - int col; - - for (col = xt->n_vars - 1; col >= 0; col--) - if (compare_table_entry_var_3way (a, b, xt, col)) - return col; - NOT_REACHED (); - } -} - /* Output a table summarizing the cases processed. */ static void make_summary_table (struct crosstabs_proc *proc) { - struct tab_table *summary; - struct crosstabulation *xt; - struct string name; - int i; + struct pivot_table *table = pivot_table_create (N_("Summary")); + pivot_table_set_weight_var (table, dict_get_weight (proc->dict)); - summary = tab_create (7, 3 + proc->n_pivots); - tab_set_format (summary, RC_WEIGHT, &proc->weight_format); - tab_title (summary, _("Summary.")); - tab_headers (summary, 1, 0, 3, 0); - tab_joint_text (summary, 1, 0, 6, 0, TAB_CENTER, _("Cases")); - tab_joint_text (summary, 1, 1, 2, 1, TAB_CENTER, _("Valid")); - tab_joint_text (summary, 3, 1, 4, 1, TAB_CENTER, _("Missing")); - tab_joint_text (summary, 5, 1, 6, 1, TAB_CENTER, _("Total")); - tab_hline (summary, TAL_1, 1, 6, 1); - tab_hline (summary, TAL_1, 1, 6, 2); - tab_vline (summary, TAL_1, 3, 1, 1); - tab_vline (summary, TAL_1, 5, 1, 1); - for (i = 0; i < 3; i++) - { - tab_text (summary, 1 + i * 2, 2, TAB_RIGHT, _("N")); - tab_text (summary, 2 + i * 2, 2, TAB_RIGHT, _("Percent")); - } - tab_offset (summary, 0, 3); - - ds_init_empty (&name); - for (xt = &proc->pivots[0]; xt < &proc->pivots[proc->n_pivots]; xt++) - { - double valid; - double n[3]; - size_t i; + pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Statistics"), + N_("N"), PIVOT_RC_COUNT, + N_("Percent"), PIVOT_RC_PERCENT); - tab_hline (summary, TAL_1, 0, 6, 0); + struct pivot_dimension *cases = pivot_dimension_create ( + table, PIVOT_AXIS_COLUMN, N_("Cases"), + N_("Valid"), N_("Missing"), N_("Total")); + cases->root->show_label = true; - ds_clear (&name); - for (i = 0; i < xt->n_vars; i++) + struct pivot_dimension *tables = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Crosstabulation")); + for (struct crosstabulation *xt = &proc->pivots[0]; + xt < &proc->pivots[proc->n_pivots]; xt++) + { + struct string name = DS_EMPTY_INITIALIZER; + for (size_t i = 0; i < xt->n_vars; i++) { if (i > 0) - ds_put_cstr (&name, " * "); + ds_put_cstr (&name, " × "); ds_put_cstr (&name, var_to_string (xt->vars[i].var)); } - tab_text (summary, 0, 0, TAB_LEFT, ds_cstr (&name)); - valid = 0.; - for (i = 0; i < xt->n_entries; i++) + int row = pivot_category_create_leaf ( + tables->root, + pivot_value_new_user_text_nocopy (ds_steal_cstr (&name))); + + double valid = 0.; + for (size_t i = 0; i < xt->n_entries; i++) valid += xt->entries[i]->count; + double n[3]; n[0] = valid; n[1] = xt->missing; n[2] = n[0] + n[1]; - for (i = 0; i < 3; i++) + for (int i = 0; i < 3; i++) { - tab_double (summary, i * 2 + 1, 0, TAB_RIGHT, n[i], NULL, RC_WEIGHT); - tab_text_format (summary, i * 2 + 2, 0, TAB_RIGHT, "%.1f%%", - n[i] / n[2] * 100.); + pivot_table_put3 (table, 0, i, row, pivot_value_new_number (n[i])); + pivot_table_put3 (table, 1, i, row, + pivot_value_new_number (n[i] / n[2] * 100.0)); } - - tab_next_row (summary); } - ds_destroy (&name); - submit (NULL, summary); + pivot_table_submit (table); } /* Output. */ -static struct tab_table *create_crosstab_table (struct crosstabs_proc *, - struct crosstabulation *); -static struct tab_table *create_chisq_table (struct crosstabs_proc *proc, struct crosstabulation *); -static struct tab_table *create_sym_table (struct crosstabs_proc *proc, struct crosstabulation *); -static struct tab_table *create_risk_table (struct crosstabs_proc *proc, struct crosstabulation *); -static struct tab_table *create_direct_table (struct crosstabs_proc *proc, struct crosstabulation *); -static void display_dimensions (struct crosstabs_proc *, struct crosstabulation *, - struct tab_table *, int first_difference); +static struct pivot_table *create_crosstab_table ( + struct crosstabs_proc *, struct crosstabulation *, + size_t crs_leaves[CRS_CL_count]); +static struct pivot_table *create_chisq_table (struct crosstabulation *); +static struct pivot_table *create_sym_table (struct crosstabulation *); +static struct pivot_table *create_risk_table ( + struct crosstabulation *, struct pivot_dimension **risk_statistics); +static struct pivot_table *create_direct_table (struct crosstabulation *); static void display_crosstabulation (struct crosstabs_proc *, struct crosstabulation *, - struct tab_table *); -static void display_chisq (struct crosstabulation *, struct tab_table *, - bool *showed_fisher); -static void display_symmetric (struct crosstabs_proc *, struct crosstabulation *, - struct tab_table *); -static void display_risk (struct crosstabulation *, struct tab_table *); -static void display_directional (struct crosstabs_proc *, struct crosstabulation *, - struct tab_table *); -static void table_value_missing (struct crosstabs_proc *proc, - struct tab_table *table, int c, int r, - unsigned char opt, const union value *v, - const struct variable *var); + struct pivot_table *, + size_t crs_leaves[CRS_CL_count]); +static void display_chisq (struct crosstabulation *, struct pivot_table *); +static void display_symmetric (struct crosstabs_proc *, + struct crosstabulation *, struct pivot_table *); +static void display_risk (struct crosstabulation *, struct pivot_table *, + struct pivot_dimension *risk_statistics); +static void display_directional (struct crosstabs_proc *, + struct crosstabulation *, + struct pivot_table *); static void delete_missing (struct crosstabulation *); static void build_matrix (struct crosstabulation *); @@ -995,15 +997,8 @@ static void build_matrix (struct crosstabulation *); static void output_crosstabulation (struct crosstabs_proc *proc, struct crosstabulation *xt) { - struct tab_table *table = NULL; /* Crosstabulation table. */ - struct tab_table *chisq = NULL; /* Chi-square table. */ - bool showed_fisher = false; - struct tab_table *sym = NULL; /* Symmetric measures table. */ - struct tab_table *risk = NULL; /* Risk estimate table. */ - struct tab_table *direct = NULL; /* Directional measures table. */ - size_t row0, row1; - - enum_var_values (xt, COL_VAR, proc->descending); + for (size_t i = 0; i < xt->n_vars; i++) + enum_var_values (xt, i, proc->descending); if (xt->vars[COL_VAR].n_values == 0) { @@ -1012,7 +1007,7 @@ output_crosstabulation (struct crosstabs_proc *proc, struct crosstabulation *xt) ds_init_cstr (&vars, var_to_string (xt->vars[0].var)); for (i = 1; i < xt->n_vars; i++) - ds_put_format (&vars, " * %s", var_to_string (xt->vars[i].var)); + ds_put_format (&vars, " × %s", var_to_string (xt->vars[i].var)); /* TRANSLATORS: The %s here describes a crosstabulation. It takes the form "var1 * var2 * var3 * ...". */ @@ -1024,32 +1019,38 @@ output_crosstabulation (struct crosstabs_proc *proc, struct crosstabulation *xt) return; } - if (proc->cells) - table = create_crosstab_table (proc, xt); - if (proc->statistics & (1u << CRS_ST_CHISQ)) - chisq = create_chisq_table (proc, xt); - if (proc->statistics & ((1u << CRS_ST_PHI) | (1u << CRS_ST_CC) - | (1u << CRS_ST_BTAU) | (1u << CRS_ST_CTAU) - | (1u << CRS_ST_GAMMA) | (1u << CRS_ST_CORR) - | (1u << CRS_ST_KAPPA))) - sym = create_sym_table (proc, xt); - if (proc->statistics & (1u << CRS_ST_RISK)) - risk = create_risk_table (proc, xt); - if (proc->statistics & ((1u << CRS_ST_LAMBDA) | (1u << CRS_ST_UC) - | (1u << CRS_ST_D) | (1u << CRS_ST_ETA))) - direct = create_direct_table (proc, xt); - - row0 = row1 = 0; + size_t crs_leaves[CRS_CL_count]; + struct pivot_table *table = (proc->cells + ? create_crosstab_table (proc, xt, crs_leaves) + : NULL); + struct pivot_table *chisq = (proc->statistics & (1u << CRS_ST_CHISQ) + ? create_chisq_table (xt) + : NULL); + struct pivot_table *sym + = (proc->statistics & ((1u << CRS_ST_PHI) | (1u << CRS_ST_CC) + | (1u << CRS_ST_BTAU) | (1u << CRS_ST_CTAU) + | (1u << CRS_ST_GAMMA) | (1u << CRS_ST_CORR) + | (1u << CRS_ST_KAPPA)) + ? create_sym_table (xt) + : NULL); + struct pivot_dimension *risk_statistics = NULL; + struct pivot_table *risk = (proc->statistics & (1u << CRS_ST_RISK) + ? create_risk_table (xt, &risk_statistics) + : NULL); + struct pivot_table *direct + = (proc->statistics & ((1u << CRS_ST_LAMBDA) | (1u << CRS_ST_UC) + | (1u << CRS_ST_D) | (1u << CRS_ST_ETA)) + ? create_direct_table (xt) + : NULL); + + size_t row0 = 0; + size_t row1 = 0; while (find_crosstab (xt, &row0, &row1)) { struct crosstabulation x; - int first_difference; make_crosstabulation_subset (xt, row0, row1, &x); - /* Find all the row variable values. */ - enum_var_values (&x, ROW_VAR, proc->descending); - size_t n_rows = x.vars[ROW_VAR].n_values; size_t n_cols = x.vars[COL_VAR].n_values; if (size_overflow_p (xtimes (xtimes (n_rows, n_cols), sizeof (double)))) @@ -1058,71 +1059,52 @@ output_crosstabulation (struct crosstabs_proc *proc, struct crosstabulation *xt) x.col_tot = xmalloc (n_cols * sizeof *x.col_tot); x.mat = xmalloc (n_rows * n_cols * sizeof *x.mat); - /* Allocate table space for the matrix. */ - if (table - && tab_row (table) + (n_rows + 1) * proc->n_cells > tab_nr (table)) - tab_realloc (table, -1, - MAX (tab_nr (table) + (n_rows + 1) * proc->n_cells, - tab_nr (table) * xt->n_entries / x.n_entries)); - build_matrix (&x); /* Find the first variable that differs from the last subtable. */ - first_difference = find_first_difference (xt, row0); if (table) - { - display_dimensions (proc, &x, table, first_difference); - display_crosstabulation (proc, &x, table); - } + display_crosstabulation (proc, &x, table, crs_leaves); if (proc->exclude == MV_NEVER) delete_missing (&x); if (chisq) - { - display_dimensions (proc, &x, chisq, first_difference); - display_chisq (&x, chisq, &showed_fisher); - } + display_chisq (&x, chisq); + if (sym) - { - display_dimensions (proc, &x, sym, first_difference); - display_symmetric (proc, &x, sym); - } + display_symmetric (proc, &x, sym); if (risk) - { - display_dimensions (proc, &x, risk, first_difference); - display_risk (&x, risk); - } + display_risk (&x, risk, risk_statistics); if (direct) - { - display_dimensions (proc, &x, direct, first_difference); - display_directional (proc, &x, direct); - } - - /* Free the parts of x that are not owned by xt. In - particular we must not free x.cols, which is the same as - xt->cols, which is freed at the end of this function. */ - free_var_values (&x, ROW_VAR); + display_directional (proc, &x, direct); free (x.mat); free (x.row_tot); free (x.col_tot); } - submit (NULL, table); + if (table) + pivot_table_submit (table); if (chisq) + pivot_table_submit (chisq); + + if (sym) + pivot_table_submit (sym); + + if (risk) { - if (!showed_fisher) - tab_resize (chisq, 4 + (xt->n_vars - 2), -1); - submit (xt, chisq); + if (!pivot_table_is_empty (risk)) + pivot_table_submit (risk); + else + pivot_table_destroy (risk); } - submit (xt, sym); - submit (xt, risk); - submit (xt, direct); + if (direct) + pivot_table_submit (direct); - free_var_values (xt, COL_VAR); + for (size_t i = 0; i < xt->n_vars; i++) + free_var_values (xt, i); } static void @@ -1210,213 +1192,245 @@ build_matrix (struct crosstabulation *x) x->total += x->col_tot[col]; } -static struct tab_table * -create_crosstab_table (struct crosstabs_proc *proc, struct crosstabulation *xt) +static void +add_var_dimension (struct pivot_table *table, const struct xtab_var *var, + enum pivot_axis_type axis_type, bool total) { - struct tuple - { - int value; - const char *name; - }; - static const struct tuple names[] = - { - {CRS_CL_COUNT, N_("count")}, - {CRS_CL_ROW, N_("row %")}, - {CRS_CL_COLUMN, N_("column %")}, - {CRS_CL_TOTAL, N_("total %")}, - {CRS_CL_EXPECTED, N_("expected")}, - {CRS_CL_RESIDUAL, N_("residual")}, - {CRS_CL_SRESIDUAL, N_("std. resid.")}, - {CRS_CL_ASRESIDUAL, N_("adj. resid.")}, - }; - const int n_names = sizeof names / sizeof *names; - const struct tuple *t; + struct pivot_dimension *d = pivot_dimension_create__ ( + table, axis_type, pivot_value_new_variable (var->var)); - struct tab_table *table; - struct string title; - struct crosstabulation x; + struct pivot_footnote *missing_footnote = pivot_table_create_footnote ( + table, pivot_value_new_text (N_("Missing value"))); - int i; + struct pivot_category *group = pivot_category_create_group__ ( + d->root, pivot_value_new_variable (var->var)); + for (size_t j = 0; j < var->n_values; j++) + { + struct pivot_value *value = pivot_value_new_var_value ( + var->var, &var->values[j]); + if (var_is_value_missing (var->var, &var->values[j], MV_ANY)) + pivot_value_add_footnote (value, missing_footnote); + pivot_category_create_leaf (group, value); + } - make_crosstabulation_subset (xt, 0, 0, &x); - - size_t n_cols = x.vars[COL_VAR].n_values; - table = tab_create (x.n_consts + 1 + n_cols + 1, - (x.n_entries / n_cols) * 3 / 2 * proc->n_cells + 10); - tab_headers (table, x.n_consts + 1, 0, 2, 0); - tab_set_format (table, RC_WEIGHT, &proc->weight_format); - - /* First header line. */ - tab_joint_text (table, x.n_consts + 1, 0, - (x.n_consts + 1) + (n_cols - 1), 0, - TAB_CENTER | TAT_TITLE, var_to_string (x.vars[COL_VAR].var)); - - tab_hline (table, TAL_1, x.n_consts + 1, - x.n_consts + 2 + n_cols - 2, 1); - - /* Second header line. */ - for (i = 2; i < x.n_consts + 2; i++) - tab_joint_text (table, x.n_consts + 2 - i - 1, 0, - x.n_consts + 2 - i - 1, 1, - TAB_RIGHT | TAT_TITLE, var_to_string (x.vars[i].var)); - tab_text (table, x.n_consts + 2 - 2, 1, TAB_RIGHT | TAT_TITLE, - var_to_string (x.vars[ROW_VAR].var)); - for (i = 0; i < n_cols; i++) - table_value_missing (proc, table, x.n_consts + 2 + i - 1, 1, TAB_RIGHT, - &x.vars[COL_VAR].values[i], x.vars[COL_VAR].var); - tab_text (table, x.n_consts + 2 + n_cols - 1, 1, TAB_CENTER, _("Total")); - - tab_hline (table, TAL_1, 0, x.n_consts + 2 + n_cols - 1, 2); - tab_vline (table, TAL_1, x.n_consts + 2 + n_cols - 1, 0, 1); + if (total) + pivot_category_create_leaf (d->root, pivot_value_new_text (N_("Total"))); +} +static struct pivot_table * +create_crosstab_table (struct crosstabs_proc *proc, struct crosstabulation *xt, + size_t crs_leaves[CRS_CL_count]) +{ /* Title. */ - ds_init_empty (&title); - for (i = 0; i < x.n_consts + 2; i++) + struct string title = DS_EMPTY_INITIALIZER; + for (size_t i = 0; i < xt->n_vars; i++) { if (i) - ds_put_cstr (&title, " * "); - ds_put_cstr (&title, var_to_string (x.vars[i].var)); + ds_put_cstr (&title, " × "); + ds_put_cstr (&title, var_to_string (xt->vars[i].var)); } - for (i = 0; i < xt->n_consts; i++) + for (size_t i = 0; i < xt->n_consts; i++) { const struct variable *var = xt->const_vars[i].var; + const union value *value = &xt->entries[0]->values[2 + i]; char *s; ds_put_format (&title, ", %s=", var_to_string (var)); /* Insert the formatted value of VAR without any leading spaces. */ - s = data_out (&xt->const_vars[i].values[0], var_get_encoding (var), - var_get_print_format (var)); + s = data_out (value, var_get_encoding (var), var_get_print_format (var)); ds_put_cstr (&title, s + strspn (s, " ")); free (s); } + struct pivot_table *table = pivot_table_create__ ( + pivot_value_new_user_text_nocopy (ds_steal_cstr (&title))); + pivot_table_set_weight_format (table, &proc->weight_format); + table->omit_empty = true; - ds_put_cstr (&title, " ["); - i = 0; - for (t = names; t < &names[n_names]; t++) - if (proc->cells & (1u << t->value)) - { - if (i++) - ds_put_cstr (&title, ", "); - ds_put_cstr (&title, gettext (t->name)); - } - ds_put_cstr (&title, "]."); + struct pivot_dimension *statistics = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Statistics")); + + struct statistic + { + const char *label; + const char *rc; + }; + static const struct statistic stats[CRS_CL_count] = + { + [CRS_CL_COUNT] = { N_("Count"), PIVOT_RC_COUNT }, + [CRS_CL_ROW] = { N_("Row %"), PIVOT_RC_PERCENT }, + [CRS_CL_COLUMN] = { N_("Column %"), PIVOT_RC_PERCENT }, + [CRS_CL_TOTAL] = { N_("Total %"), PIVOT_RC_PERCENT }, + [CRS_CL_EXPECTED] = { N_("Expected"), PIVOT_RC_OTHER }, + [CRS_CL_RESIDUAL] = { N_("Residual"), PIVOT_RC_RESIDUAL }, + [CRS_CL_SRESIDUAL] = { N_("Std. Residual"), PIVOT_RC_RESIDUAL }, + [CRS_CL_ASRESIDUAL] = { N_("Adjusted Residual"), PIVOT_RC_RESIDUAL }, + }; + for (size_t i = 0; i < CRS_CL_count; i++) + if (proc->cells & (1u << i) && stats[i].label) + crs_leaves[i] = pivot_category_create_leaf_rc ( + statistics->root, pivot_value_new_text (stats[i].label), + stats[i].rc); - tab_title (table, "%s", ds_cstr (&title)); - ds_destroy (&title); + for (size_t i = 0; i < xt->n_vars; i++) + add_var_dimension (table, &xt->vars[i], + i == COL_VAR ? PIVOT_AXIS_COLUMN : PIVOT_AXIS_ROW, + true); - tab_offset (table, 0, 2); return table; } -static struct tab_table * -create_chisq_table (struct crosstabs_proc *proc, struct crosstabulation *xt) +static struct pivot_table * +create_chisq_table (struct crosstabulation *xt) { - struct tab_table *chisq; - - size_t n_cols = xt->vars[COL_VAR].n_values; - chisq = tab_create (6 + (xt->n_vars - 2), - xt->n_entries / n_cols * 3 / 2 * N_CHISQ + 10); - tab_headers (chisq, 1 + (xt->n_vars - 2), 0, 1, 0); - tab_set_format (chisq, RC_WEIGHT, &proc->weight_format); - - tab_title (chisq, _("Chi-square tests.")); - - tab_offset (chisq, xt->n_vars - 2, 0); - tab_text (chisq, 0, 0, TAB_LEFT | TAT_TITLE, _("Statistic")); - tab_text (chisq, 1, 0, TAB_RIGHT | TAT_TITLE, _("Value")); - tab_text (chisq, 2, 0, TAB_RIGHT | TAT_TITLE, _("df")); - tab_text (chisq, 3, 0, TAB_RIGHT | TAT_TITLE, - _("Asymp. Sig. (2-tailed)")); - tab_text_format (chisq, 4, 0, TAB_RIGHT | TAT_TITLE, - _("Exact Sig. (%d-tailed)"), 2); - tab_text_format (chisq, 5, 0, TAB_RIGHT | TAT_TITLE, - _("Exact Sig. (%d-tailed)"), 1); - tab_offset (chisq, 0, 1); + struct pivot_table *chisq = pivot_table_create (N_("Chi-Square Tests")); + pivot_table_set_weight_format (chisq, &xt->weight_format); + chisq->omit_empty = true; + + pivot_dimension_create ( + chisq, PIVOT_AXIS_ROW, N_("Statistics"), + N_("Pearson Chi-Square"), + N_("Likelihood Ratio"), + N_("Fisher's Exact Test"), + N_("Continuity Correction"), + N_("Linear-by-Linear Association"), + N_("N of Valid Cases"), PIVOT_RC_COUNT); + + pivot_dimension_create ( + chisq, PIVOT_AXIS_COLUMN, N_("Statistics"), + N_("Value"), PIVOT_RC_OTHER, + N_("df"), PIVOT_RC_COUNT, + N_("Asymptotic Sig. (2-tailed)"), PIVOT_RC_SIGNIFICANCE, + N_("Exact Sig. (2-tailed)"), PIVOT_RC_SIGNIFICANCE, + N_("Exact Sig. (1-tailed)"), PIVOT_RC_SIGNIFICANCE); + + for (size_t i = 2; i < xt->n_vars; i++) + add_var_dimension (chisq, &xt->vars[i], PIVOT_AXIS_ROW, false); return chisq; } /* Symmetric measures. */ -static struct tab_table * -create_sym_table (struct crosstabs_proc *proc, struct crosstabulation *xt) +static struct pivot_table * +create_sym_table (struct crosstabulation *xt) { - struct tab_table *sym; - - size_t n_cols = xt->vars[COL_VAR].n_values; - sym = tab_create (6 + (xt->n_vars - 2), - xt->n_entries / n_cols * 7 + 10); - - tab_set_format (sym, RC_WEIGHT, &proc->weight_format); - - tab_headers (sym, 2 + (xt->n_vars - 2), 0, 1, 0); - tab_title (sym, _("Symmetric measures.")); - - tab_offset (sym, xt->n_vars - 2, 0); - tab_text (sym, 0, 0, TAB_LEFT | TAT_TITLE, _("Category")); - tab_text (sym, 1, 0, TAB_LEFT | TAT_TITLE, _("Statistic")); - tab_text (sym, 2, 0, TAB_RIGHT | TAT_TITLE, _("Value")); - tab_text (sym, 3, 0, TAB_RIGHT | TAT_TITLE, _("Asymp. Std. Error")); - tab_text (sym, 4, 0, TAB_RIGHT | TAT_TITLE, _("Approx. T")); - tab_text (sym, 5, 0, TAB_RIGHT | TAT_TITLE, _("Approx. Sig.")); - tab_offset (sym, 0, 1); + struct pivot_table *sym = pivot_table_create (N_("Symmetric Measures")); + pivot_table_set_weight_format (sym, &xt->weight_format); + sym->omit_empty = true; + + pivot_dimension_create ( + sym, PIVOT_AXIS_COLUMN, N_("Values"), + N_("Value"), PIVOT_RC_OTHER, + N_("Asymp. Std. Error"), PIVOT_RC_OTHER, + N_("Approx. T"), PIVOT_RC_OTHER, + N_("Approx. Sig."), PIVOT_RC_SIGNIFICANCE); + + struct pivot_dimension *statistics = pivot_dimension_create ( + sym, PIVOT_AXIS_ROW, N_("Statistics")); + pivot_category_create_group ( + statistics->root, N_("Nominal by Nominal"), + N_("Phi"), N_("Cramer's V"), N_("Contingency Coefficient")); + pivot_category_create_group ( + statistics->root, N_("Ordinal by Ordinal"), + N_("Kendall's tau-b"), N_("Kendall's tau-c"), + N_("Gamma"), N_("Spearman Correlation")); + pivot_category_create_group ( + statistics->root, N_("Interval by Interval"), + N_("Pearson's R")); + pivot_category_create_group ( + statistics->root, N_("Measure of Agreement"), + N_("Kappa")); + pivot_category_create_leaves (statistics->root, N_("N of Valid Cases"), + PIVOT_RC_COUNT); + + for (size_t i = 2; i < xt->n_vars; i++) + add_var_dimension (sym, &xt->vars[i], PIVOT_AXIS_ROW, false); return sym; } /* Risk estimate. */ -static struct tab_table * -create_risk_table (struct crosstabs_proc *proc, struct crosstabulation *xt) +static struct pivot_table * +create_risk_table (struct crosstabulation *xt, + struct pivot_dimension **risk_statistics) { - struct tab_table *risk; + struct pivot_table *risk = pivot_table_create (N_("Risk Estimate")); + pivot_table_set_weight_format (risk, &xt->weight_format); + risk->omit_empty = true; - size_t n_cols = xt->vars[COL_VAR].n_values; - risk = tab_create (4 + (xt->n_vars - 2), xt->n_entries / n_cols * 4 + 10); - tab_headers (risk, 1 + xt->n_vars - 2, 0, 2, 0); - tab_title (risk, _("Risk estimate.")); - tab_set_format (risk, RC_WEIGHT, &proc->weight_format); - - tab_offset (risk, xt->n_vars - 2, 0); - tab_joint_text_format (risk, 2, 0, 3, 0, TAB_CENTER | TAT_TITLE, - _("95%% Confidence Interval")); - tab_text (risk, 0, 1, TAB_LEFT | TAT_TITLE, _("Statistic")); - tab_text (risk, 1, 1, TAB_RIGHT | TAT_TITLE, _("Value")); - tab_text (risk, 2, 1, TAB_RIGHT | TAT_TITLE, _("Lower")); - tab_text (risk, 3, 1, TAB_RIGHT | TAT_TITLE, _("Upper")); - tab_hline (risk, TAL_1, 2, 3, 1); - tab_vline (risk, TAL_1, 2, 0, 1); - tab_offset (risk, 0, 2); + struct pivot_dimension *values = pivot_dimension_create ( + risk, PIVOT_AXIS_COLUMN, N_("Values"), + N_("Value"), PIVOT_RC_OTHER); + pivot_category_create_group ( + values->root, N_("95% Confidence Interval"), + N_("Lower"), PIVOT_RC_OTHER, + N_("Upper"), PIVOT_RC_OTHER); + + *risk_statistics = pivot_dimension_create ( + risk, PIVOT_AXIS_ROW, N_("Statistics")); + + for (size_t i = 2; i < xt->n_vars; i++) + add_var_dimension (risk, &xt->vars[i], PIVOT_AXIS_ROW, false); return risk; } -/* Directional measures. */ -static struct tab_table * -create_direct_table (struct crosstabs_proc *proc, struct crosstabulation *xt) +static void +create_direct_stat (struct pivot_category *parent, + const struct crosstabulation *xt, + const char *name, bool symmetric) { - struct tab_table *direct; + struct pivot_category *group = pivot_category_create_group ( + parent, name); + if (symmetric) + pivot_category_create_leaf (group, pivot_value_new_text (N_("Symmetric"))); + + char *row_label = xasprintf (_("%s Dependent"), + var_to_string (xt->vars[ROW_VAR].var)); + pivot_category_create_leaf (group, pivot_value_new_user_text_nocopy ( + row_label)); + + char *col_label = xasprintf (_("%s Dependent"), + var_to_string (xt->vars[COL_VAR].var)); + pivot_category_create_leaf (group, pivot_value_new_user_text_nocopy ( + col_label)); +} - size_t n_cols = xt->vars[COL_VAR].n_values; - direct = tab_create (7 + (xt->n_vars - 2), - xt->n_entries / n_cols * 7 + 10); - tab_headers (direct, 3 + (xt->n_vars - 2), 0, 1, 0); - tab_title (direct, _("Directional measures.")); - tab_set_format (direct, RC_WEIGHT, &proc->weight_format); - - tab_offset (direct, xt->n_vars - 2, 0); - tab_text (direct, 0, 0, TAB_LEFT | TAT_TITLE, _("Category")); - tab_text (direct, 1, 0, TAB_LEFT | TAT_TITLE, _("Statistic")); - tab_text (direct, 2, 0, TAB_LEFT | TAT_TITLE, _("Type")); - tab_text (direct, 3, 0, TAB_RIGHT | TAT_TITLE, _("Value")); - tab_text (direct, 4, 0, TAB_RIGHT | TAT_TITLE, _("Asymp. Std. Error")); - tab_text (direct, 5, 0, TAB_RIGHT | TAT_TITLE, _("Approx. T")); - tab_text (direct, 6, 0, TAB_RIGHT | TAT_TITLE, _("Approx. Sig.")); - tab_offset (direct, 0, 1); +/* Directional measures. */ +static struct pivot_table * +create_direct_table (struct crosstabulation *xt) +{ + struct pivot_table *direct = pivot_table_create (N_("Directional Measures")); + pivot_table_set_weight_format (direct, &xt->weight_format); + direct->omit_empty = true; + + pivot_dimension_create ( + direct, PIVOT_AXIS_COLUMN, N_("Values"), + N_("Value"), PIVOT_RC_OTHER, + N_("Asymp. Std. Error"), PIVOT_RC_OTHER, + N_("Approx. T"), PIVOT_RC_OTHER, + N_("Approx Sig."), PIVOT_RC_SIGNIFICANCE); + + struct pivot_dimension *statistics = pivot_dimension_create ( + direct, PIVOT_AXIS_ROW, N_("Statistics")); + struct pivot_category *nn = pivot_category_create_group ( + statistics->root, N_("Nominal by Nominal")); + create_direct_stat (nn, xt, N_("Lambda"), true); + create_direct_stat (nn, xt, N_("Goodman and Kruskal tau"), false); + create_direct_stat (nn, xt, N_("Uncertainty Coefficient"), true); + struct pivot_category *oo = pivot_category_create_group ( + statistics->root, N_("Ordinal by Ordinal")); + create_direct_stat (oo, xt, N_("Somers' d"), true); + struct pivot_category *ni = pivot_category_create_group ( + statistics->root, N_("Nominal by Interval")); + create_direct_stat (ni, xt, N_("Eta"), false); + + for (size_t i = 2; i < xt->n_vars; i++) + add_var_dimension (direct, &xt->vars[i], PIVOT_AXIS_ROW, false); return direct; } - /* Delete missing rows and columns for statistical analysis when /MISSING=REPORT. */ static void @@ -1446,34 +1460,6 @@ delete_missing (struct crosstabulation *xt) } } -/* Prepare table T for submission, and submit it. */ -static void -submit (struct crosstabulation *xt, struct tab_table *t) -{ - int i; - - if (t == NULL) - return; - - tab_resize (t, -1, 0); - if (tab_nr (t) == tab_t (t)) - { - table_unref (&t->table); - return; - } - tab_offset (t, 0, 0); - if (xt != NULL) - for (i = 2; i < xt->n_vars; i++) - tab_text (t, xt->n_vars - i - 1, 0, TAB_RIGHT | TAT_TITLE, - var_to_string (xt->vars[i].var)); - tab_box (t, TAL_2, TAL_2, -1, -1, 0, 0, tab_nc (t) - 1, tab_nr (t) - 1); - tab_box (t, -1, -1, -1, TAL_1, tab_l (t), tab_t (t) - 1, tab_nc (t) - 1, - tab_nr (t) - 1); - tab_vline (t, TAL_2, tab_l (t), 0, tab_nr (t) - 1); - - tab_submit (t); -} - static bool find_crosstab (struct crosstabulation *xt, size_t *row0p, size_t *row1p) { @@ -1578,269 +1564,131 @@ static void free_var_values (const struct crosstabulation *xt, int var_idx) { struct xtab_var *xv = &xt->vars[var_idx]; - free (xv->values); + //free (xv->values); xv->values = NULL; xv->n_values = 0; } -/* Sets cell (C,R) in TABLE, with options OPT, to have a value taken - from V, displayed with print format spec from variable VAR. When - in REPORT missing-value mode, missing values have an M appended. */ -static void -table_value_missing (struct crosstabs_proc *proc, - struct tab_table *table, int c, int r, unsigned char opt, - const union value *v, const struct variable *var) -{ - const char *label = var_lookup_value_label (var, v); - if (label != NULL) - tab_text (table, c, r, TAB_LEFT, label); - else - { - const struct fmt_spec *print = var_get_print_format (var); - if (proc->exclude == MV_NEVER && var_is_value_missing (var, v, MV_USER)) - { - char *s = data_out (v, dict_get_encoding (proc->dict), print); - tab_text_format (table, c, r, opt, "%sM", s + strspn (s, " ")); - free (s); - } - else - tab_value (table, c, r, opt, v, var, print); - } -} - -/* Draws a line across TABLE at the current row to indicate the most - major dimension variable with index FIRST_DIFFERENCE out of N_VARS - that changed, and puts the values that changed into the table. TB - and XT must be the corresponding table_entry and crosstab, - respectively. */ -static void -display_dimensions (struct crosstabs_proc *proc, struct crosstabulation *xt, - struct tab_table *table, int first_difference) -{ - tab_hline (table, TAL_1, xt->n_consts + xt->n_vars - first_difference - 1, tab_nc (table) - 1, 0); - - for (; first_difference >= 2; first_difference--) - table_value_missing (proc, table, xt->n_consts + xt->n_vars - first_difference - 1, 0, - TAB_RIGHT, &xt->entries[0]->values[first_difference], - xt->vars[first_difference].var); -} - -/* Put VALUE into cell (C,R) of TABLE, suffixed with character - SUFFIX if nonzero. If MARK_MISSING is true the entry is - additionally suffixed with a letter `M'. */ -static void -format_cell_entry (struct tab_table *table, int c, int r, double value, - char suffix, bool mark_missing, const struct dictionary *dict) -{ - union value v; - char suffixes[3]; - int suffix_len; - char *s; - - v.f = value; - s = data_out (&v, dict_get_encoding (dict), settings_get_format ()); - - suffix_len = 0; - if (suffix != 0) - suffixes[suffix_len++] = suffix; - if (mark_missing) - suffixes[suffix_len++] = 'M'; - suffixes[suffix_len] = '\0'; - - tab_text_format (table, c, r, TAB_RIGHT, "%s%s", - s + strspn (s, " "), suffixes); - - free (s); -} - /* Displays the crosstabulation table. */ static void display_crosstabulation (struct crosstabs_proc *proc, - struct crosstabulation *xt, struct tab_table *table) + struct crosstabulation *xt, struct pivot_table *table, + size_t crs_leaves[CRS_CL_count]) { size_t n_rows = xt->vars[ROW_VAR].n_values; size_t n_cols = xt->vars[COL_VAR].n_values; - int last_row; - int r, c, i; - double *mp; - for (r = 0; r < n_rows; r++) - table_value_missing (proc, table, xt->n_consts + xt->n_vars - 2, - r * proc->n_cells, TAB_RIGHT, - &xt->vars[ROW_VAR].values[r], - xt->vars[ROW_VAR].var); - - tab_text (table, xt->n_vars - 2, n_rows * proc->n_cells, - TAB_LEFT, _("Total")); + size_t *indexes = xnmalloc (table->n_dimensions, sizeof *indexes); + assert (xt->n_vars == 2); + for (size_t i = 0; i < xt->n_consts; i++) + indexes[i + 3] = xt->const_indexes[i]; /* Put in the actual cells. */ - mp = xt->mat; - tab_offset (table, xt->n_consts + xt->n_vars - 1, -1); - for (r = 0; r < n_rows; r++) + double *mp = xt->mat; + for (size_t r = 0; r < n_rows; r++) { - if (proc->n_cells > 1) - tab_hline (table, TAL_1, -1, n_cols, 0); - for (c = 0; c < n_cols; c++) + if (!xt->row_tot[r] && proc->mode != INTEGER) + continue; + + indexes[ROW_VAR + 1] = r; + for (size_t c = 0; c < n_cols; c++) { - bool mark_missing = false; + if (!xt->col_tot[c] && proc->mode != INTEGER) + continue; + + indexes[COL_VAR + 1] = c; + double expected_value = xt->row_tot[r] * xt->col_tot[c] / xt->total; - if (proc->exclude == MV_NEVER - && (var_is_num_missing (xt->vars[COL_VAR].var, - xt->vars[COL_VAR].values[c].f, MV_USER) - || var_is_num_missing (xt->vars[ROW_VAR].var, - xt->vars[ROW_VAR].values[r].f, - MV_USER))) - mark_missing = true; - for (i = 0; i < proc->n_cells; i++) - { - double v; - int suffix = 0; - - switch (proc->a_cells[i]) - { - case CRS_CL_COUNT: - v = *mp; - break; - case CRS_CL_ROW: - v = *mp / xt->row_tot[r] * 100.; - suffix = '%'; - break; - case CRS_CL_COLUMN: - v = *mp / xt->col_tot[c] * 100.; - suffix = '%'; - break; - case CRS_CL_TOTAL: - v = *mp / xt->total * 100.; - suffix = '%'; - break; - case CRS_CL_EXPECTED: - v = expected_value; - break; - case CRS_CL_RESIDUAL: - v = *mp - expected_value; - break; - case CRS_CL_SRESIDUAL: - v = (*mp - expected_value) / sqrt (expected_value); - break; - case CRS_CL_ASRESIDUAL: - v = ((*mp - expected_value) - / sqrt (expected_value + double residual = *mp - expected_value; + double sresidual = residual / sqrt (expected_value); + double asresidual = (sresidual * (1. - xt->row_tot[r] / xt->total) - * (1. - xt->col_tot[c] / xt->total))); - break; - default: - NOT_REACHED (); - } - format_cell_entry (table, c, i, v, suffix, mark_missing, proc->dict); + * (1. - xt->col_tot[c] / xt->total)); + double entries[] = { + [CRS_CL_COUNT] = *mp, + [CRS_CL_ROW] = *mp / xt->row_tot[r] * 100., + [CRS_CL_COLUMN] = *mp / xt->col_tot[c] * 100., + [CRS_CL_TOTAL] = *mp / xt->total * 100., + [CRS_CL_EXPECTED] = expected_value, + [CRS_CL_RESIDUAL] = residual, + [CRS_CL_SRESIDUAL] = sresidual, + [CRS_CL_ASRESIDUAL] = asresidual, + }; + for (size_t i = 0; i < proc->n_cells; i++) + { + int cell = proc->a_cells[i]; + indexes[0] = crs_leaves[cell]; + pivot_table_put (table, indexes, table->n_dimensions, + pivot_value_new_number (entries[cell])); } mp++; } - - tab_offset (table, -1, tab_row (table) + proc->n_cells); } /* Row totals. */ - tab_offset (table, -1, tab_row (table) - proc->n_cells * n_rows); - for (r = 0; r < n_rows; r++) - { - bool mark_missing = false; - - if (proc->exclude == MV_NEVER - && var_is_num_missing (xt->vars[ROW_VAR].var, - xt->vars[ROW_VAR].values[r].f, MV_USER)) - mark_missing = true; - - for (i = 0; i < proc->n_cells; i++) + for (size_t r = 0; r < n_rows; r++) + { + if (!xt->row_tot[r] && proc->mode != INTEGER) + continue; + + double expected_value = xt->row_tot[r] / xt->total; + double entries[] = { + [CRS_CL_COUNT] = xt->row_tot[r], + [CRS_CL_ROW] = 100.0, + [CRS_CL_COLUMN] = expected_value * 100., + [CRS_CL_TOTAL] = expected_value * 100., + [CRS_CL_EXPECTED] = expected_value, + [CRS_CL_RESIDUAL] = SYSMIS, + [CRS_CL_SRESIDUAL] = SYSMIS, + [CRS_CL_ASRESIDUAL] = SYSMIS, + }; + for (size_t i = 0; i < proc->n_cells; i++) { - char suffix = 0; - double v; - - switch (proc->a_cells[i]) + int cell = proc->a_cells[i]; + double entry = entries[cell]; + if (entry != SYSMIS) { - case CRS_CL_COUNT: - v = xt->row_tot[r]; - break; - case CRS_CL_ROW: - v = 100.0; - suffix = '%'; - break; - case CRS_CL_COLUMN: - v = xt->row_tot[r] / xt->total * 100.; - suffix = '%'; - break; - case CRS_CL_TOTAL: - v = xt->row_tot[r] / xt->total * 100.; - suffix = '%'; - break; - case CRS_CL_EXPECTED: - case CRS_CL_RESIDUAL: - case CRS_CL_SRESIDUAL: - case CRS_CL_ASRESIDUAL: - v = 0.; - break; - default: - NOT_REACHED (); + indexes[ROW_VAR + 1] = r; + indexes[COL_VAR + 1] = n_cols; + indexes[0] = crs_leaves[cell]; + pivot_table_put (table, indexes, table->n_dimensions, + pivot_value_new_number (entry)); } - - format_cell_entry (table, n_cols, 0, v, suffix, mark_missing, proc->dict); - tab_next_row (table); } } - /* Column totals, grand total. */ - last_row = 0; - if (proc->n_cells > 1) - tab_hline (table, TAL_1, -1, n_cols, 0); - for (c = 0; c <= n_cols; c++) + for (size_t c = 0; c <= n_cols; c++) { - double ct = c < n_cols ? xt->col_tot[c] : xt->total; - bool mark_missing = false; - int i; + if (c < n_cols && !xt->col_tot[c] && proc->mode != INTEGER) + continue; - if (proc->exclude == MV_NEVER && c < n_cols - && var_is_num_missing (xt->vars[COL_VAR].var, - xt->vars[COL_VAR].values[c].f, MV_USER)) - mark_missing = true; - - for (i = 0; i < proc->n_cells; i++) + double ct = c < n_cols ? xt->col_tot[c] : xt->total; + double expected_value = ct / xt->total; + double entries[] = { + [CRS_CL_COUNT] = ct, + [CRS_CL_ROW] = expected_value * 100.0, + [CRS_CL_COLUMN] = 100.0, + [CRS_CL_TOTAL] = expected_value * 100., + [CRS_CL_EXPECTED] = expected_value, + [CRS_CL_RESIDUAL] = SYSMIS, + [CRS_CL_SRESIDUAL] = SYSMIS, + [CRS_CL_ASRESIDUAL] = SYSMIS, + }; + for (size_t i = 0; i < proc->n_cells; i++) { - char suffix = 0; - double v; - - switch (proc->a_cells[i]) + int cell = proc->a_cells[i]; + double entry = entries[cell]; + if (entry != SYSMIS) { - case CRS_CL_COUNT: - v = ct; - break; - case CRS_CL_ROW: - v = ct / xt->total * 100.; - suffix = '%'; - break; - case CRS_CL_COLUMN: - v = 100.; - suffix = '%'; - break; - case CRS_CL_TOTAL: - v = ct / xt->total * 100.; - suffix = '%'; - break; - case CRS_CL_EXPECTED: - case CRS_CL_RESIDUAL: - case CRS_CL_SRESIDUAL: - case CRS_CL_ASRESIDUAL: - continue; - default: - NOT_REACHED (); + indexes[ROW_VAR + 1] = n_rows; + indexes[COL_VAR + 1] = c; + indexes[0] = crs_leaves[cell]; + pivot_table_put (table, indexes, table->n_dimensions, + pivot_value_new_number (entry)); } - - format_cell_entry (table, c, i, v, suffix, mark_missing, proc->dict); } - last_row = i; } - - tab_offset (table, -1, tab_row (table) + last_row); - tab_offset (table, 0, -1); } static void calc_r (struct crosstabulation *, @@ -1850,55 +1698,49 @@ static void calc_chisq (struct crosstabulation *, /* Display chi-square statistics. */ static void -display_chisq (struct crosstabulation *xt, struct tab_table *chisq, - bool *showed_fisher) +display_chisq (struct crosstabulation *xt, struct pivot_table *chisq) { - static const char *chisq_stats[N_CHISQ] = - { - N_("Pearson Chi-Square"), - N_("Likelihood Ratio"), - N_("Fisher's Exact Test"), - N_("Continuity Correction"), - N_("Linear-by-Linear Association"), - }; double chisq_v[N_CHISQ]; double fisher1, fisher2; int df[N_CHISQ]; - - int i; - calc_chisq (xt, chisq_v, df, &fisher1, &fisher2); - tab_offset (chisq, xt->n_consts + xt->n_vars - 2, -1); - - for (i = 0; i < N_CHISQ; i++) + size_t *indexes = xnmalloc (chisq->n_dimensions, sizeof *indexes); + assert (xt->n_vars == 2); + for (size_t i = 0; i < xt->n_consts; i++) + indexes[i + 2] = xt->const_indexes[i]; + for (int i = 0; i < N_CHISQ; i++) { - if ((i != 2 && chisq_v[i] == SYSMIS) - || (i == 2 && fisher1 == SYSMIS)) - continue; + indexes[0] = i; - tab_text (chisq, 0, 0, TAB_LEFT, gettext (chisq_stats[i])); - if (i != 2) - { - tab_double (chisq, 1, 0, TAB_RIGHT, chisq_v[i], NULL, RC_OTHER); - tab_double (chisq, 2, 0, TAB_RIGHT, df[i], NULL, RC_WEIGHT); - tab_double (chisq, 3, 0, TAB_RIGHT, - gsl_cdf_chisq_Q (chisq_v[i], df[i]), NULL, RC_PVALUE); - } - else - { - *showed_fisher = true; - tab_double (chisq, 4, 0, TAB_RIGHT, fisher2, NULL, RC_PVALUE); - tab_double (chisq, 5, 0, TAB_RIGHT, fisher1, NULL, RC_PVALUE); - } - tab_next_row (chisq); + double entries[5] = { SYSMIS, SYSMIS, SYSMIS, SYSMIS, SYSMIS }; + if (i == 2) + { + entries[3] = fisher2; + entries[4] = fisher1; + } + else if (chisq_v[i] != SYSMIS) + { + entries[0] = chisq_v[i]; + entries[1] = df[i]; + entries[2] = gsl_cdf_chisq_Q (chisq_v[i], df[i]); + } + + for (size_t j = 0; j < sizeof entries / sizeof *entries; j++) + if (entries[j] != SYSMIS) + { + indexes[1] = j; + pivot_table_put (chisq, indexes, chisq->n_dimensions, + pivot_value_new_number (entries[j])); + } } - tab_text (chisq, 0, 0, TAB_LEFT, _("N of Valid Cases")); - tab_double (chisq, 1, 0, TAB_RIGHT, xt->total, NULL, RC_WEIGHT); - tab_next_row (chisq); + indexes[0] = 5; + indexes[1] = 0; + pivot_table_put (chisq, indexes, chisq->n_dimensions, + pivot_value_new_number (xt->total)); - tab_offset (chisq, 0, -1); + free (indexes); } static int calc_symmetric (struct crosstabs_proc *, struct crosstabulation *, @@ -1909,137 +1751,108 @@ static int calc_symmetric (struct crosstabs_proc *, struct crosstabulation *, /* Display symmetric measures. */ static void display_symmetric (struct crosstabs_proc *proc, struct crosstabulation *xt, - struct tab_table *sym) + struct pivot_table *sym) { - static const char *categories[] = - { - N_("Nominal by Nominal"), - N_("Ordinal by Ordinal"), - N_("Interval by Interval"), - N_("Measure of Agreement"), - }; - - static const char *stats[N_SYMMETRIC] = - { - N_("Phi"), - N_("Cramer's V"), - N_("Contingency Coefficient"), - N_("Kendall's tau-b"), - N_("Kendall's tau-c"), - N_("Gamma"), - N_("Spearman Correlation"), - N_("Pearson's R"), - N_("Kappa"), - }; - - static const int stats_categories[N_SYMMETRIC] = - { - 0, 0, 0, 1, 1, 1, 1, 2, 3, - }; - - int last_cat = -1; double sym_v[N_SYMMETRIC], sym_ase[N_SYMMETRIC], sym_t[N_SYMMETRIC]; double somers_d_v[3], somers_d_ase[3], somers_d_t[3]; - int i; if (!calc_symmetric (proc, xt, sym_v, sym_ase, sym_t, somers_d_v, somers_d_ase, somers_d_t)) return; - tab_offset (sym, xt->n_consts + xt->n_vars - 2, -1); + size_t *indexes = xnmalloc (sym->n_dimensions, sizeof *indexes); + assert (xt->n_vars == 2); + for (size_t i = 0; i < xt->n_consts; i++) + indexes[i + 2] = xt->const_indexes[i]; - for (i = 0; i < N_SYMMETRIC; i++) + for (int i = 0; i < N_SYMMETRIC; i++) { if (sym_v[i] == SYSMIS) continue; - if (stats_categories[i] != last_cat) - { - last_cat = stats_categories[i]; - tab_text (sym, 0, 0, TAB_LEFT, gettext (categories[last_cat])); - } + indexes[1] = i; - tab_text (sym, 1, 0, TAB_LEFT, gettext (stats[i])); - tab_double (sym, 2, 0, TAB_RIGHT, sym_v[i], NULL, RC_OTHER); - if (sym_ase[i] != SYSMIS) - tab_double (sym, 3, 0, TAB_RIGHT, sym_ase[i], NULL, RC_OTHER); - if (sym_t[i] != SYSMIS) - tab_double (sym, 4, 0, TAB_RIGHT, sym_t[i], NULL, RC_OTHER); - /*tab_double (sym, 5, 0, TAB_RIGHT, normal_sig (sym_v[i]), NULL, RC_PVALUE);*/ - tab_next_row (sym); + double entries[] = { sym_v[i], sym_ase[i], sym_t[i] }; + for (size_t j = 0; j < sizeof entries / sizeof *entries; j++) + if (entries[j] != SYSMIS) + { + indexes[0] = j; + pivot_table_put (sym, indexes, sym->n_dimensions, + pivot_value_new_number (entries[j])); + } } - tab_text (sym, 0, 0, TAB_LEFT, _("N of Valid Cases")); - tab_double (sym, 2, 0, TAB_RIGHT, xt->total, NULL, RC_WEIGHT); - tab_next_row (sym); - - tab_offset (sym, 0, -1); + indexes[1] = N_SYMMETRIC; + indexes[0] = 0; + struct pivot_value *total = pivot_value_new_number (xt->total); + pivot_value_set_rc (sym, total, PIVOT_RC_COUNT); + pivot_table_put (sym, indexes, sym->n_dimensions, total); } -static int calc_risk (struct crosstabulation *, - double[], double[], double[], union value *); +static bool calc_risk (struct crosstabulation *, + double[], double[], double[], union value *, + double *); /* Display risk estimate. */ static void -display_risk (struct crosstabulation *xt, struct tab_table *risk) +display_risk (struct crosstabulation *xt, struct pivot_table *risk, + struct pivot_dimension *risk_statistics) { - char buf[256]; - double risk_v[3], lower[3], upper[3]; + double risk_v[3], lower[3], upper[3], n_valid; union value c[2]; - int i; - - if (!calc_risk (xt, risk_v, upper, lower, c)) + if (!calc_risk (xt, risk_v, upper, lower, c, &n_valid)) return; - tab_offset (risk, xt->n_consts + xt->n_vars - 2, -1); + size_t *indexes = xnmalloc (risk->n_dimensions, sizeof *indexes); + assert (xt->n_vars == 2); + for (size_t i = 0; i < xt->n_consts; i++) + indexes[i + 2] = xt->const_indexes[i]; - for (i = 0; i < 3; i++) + for (int i = 0; i < 3; i++) { const struct variable *cv = xt->vars[COL_VAR].var; const struct variable *rv = xt->vars[ROW_VAR].var; - int cvw = var_get_width (cv); - int rvw = var_get_width (rv); if (risk_v[i] == SYSMIS) continue; + struct string label = DS_EMPTY_INITIALIZER; switch (i) { case 0: - if (var_is_numeric (cv)) - sprintf (buf, _("Odds Ratio for %s (%g / %g)"), - var_to_string (cv), c[0].f, c[1].f); - else - sprintf (buf, _("Odds Ratio for %s (%.*s / %.*s)"), - var_to_string (cv), - cvw, value_str (&c[0], cvw), - cvw, value_str (&c[1], cvw)); + ds_put_format (&label, _("Odds Ratio for %s"), var_to_string (rv)); + ds_put_cstr (&label, " ("); + var_append_value_name (rv, &c[0], &label); + ds_put_cstr (&label, " / "); + var_append_value_name (rv, &c[1], &label); + ds_put_cstr (&label, ")"); break; case 1: case 2: - if (var_is_numeric (rv)) - sprintf (buf, _("For cohort %s = %.*g"), - var_to_string (rv), DBL_DIG + 1, - xt->vars[ROW_VAR].values[i - 1].f); - else - sprintf (buf, _("For cohort %s = %.*s"), - var_to_string (rv), - rvw, value_str (&xt->vars[ROW_VAR].values[i - 1], rvw)); + ds_put_format (&label, _("For cohort %s = "), var_to_string (cv)); + var_append_value_name (cv, &xt->vars[ROW_VAR].values[i - 1], &label); break; } - tab_text (risk, 0, 0, TAB_LEFT, buf); - tab_double (risk, 1, 0, TAB_RIGHT, risk_v[i], NULL, RC_OTHER); - tab_double (risk, 2, 0, TAB_RIGHT, lower[i], NULL, RC_OTHER); - tab_double (risk, 3, 0, TAB_RIGHT, upper[i], NULL, RC_OTHER); - tab_next_row (risk); - } - - tab_text (risk, 0, 0, TAB_LEFT, _("N of Valid Cases")); - tab_double (risk, 1, 0, TAB_RIGHT, xt->total, NULL, RC_WEIGHT); - tab_next_row (risk); + indexes[1] = pivot_category_create_leaf ( + risk_statistics->root, + pivot_value_new_user_text_nocopy (ds_steal_cstr (&label))); - tab_offset (risk, 0, -1); + double entries[] = { risk_v[i], lower[i], upper[i] }; + for (size_t j = 0; j < sizeof entries / sizeof *entries; j++) + { + indexes[0] = j; + pivot_table_put (risk, indexes, risk->n_dimensions, + pivot_value_new_number (entries[i])); + } + } + indexes[1] = pivot_category_create_leaf ( + risk_statistics->root, + pivot_value_new_text (N_("N of Valid Cases"))); + indexes[0] = 0; + pivot_table_put (risk, indexes, risk->n_dimensions, + pivot_value_new_number (n_valid)); + free (indexes); } static int calc_directional (struct crosstabs_proc *, struct crosstabulation *, @@ -2048,120 +1861,39 @@ static int calc_directional (struct crosstabs_proc *, struct crosstabulation *, /* Display directional measures. */ static void -display_directional (struct crosstabs_proc *proc, struct crosstabulation *xt, - struct tab_table *direct) +display_directional (struct crosstabs_proc *proc, + struct crosstabulation *xt, struct pivot_table *direct) { - static const char *categories[] = - { - N_("Nominal by Nominal"), - N_("Ordinal by Ordinal"), - N_("Nominal by Interval"), - }; - - static const char *stats[] = - { - N_("Lambda"), - N_("Goodman and Kruskal tau"), - N_("Uncertainty Coefficient"), - N_("Somers' d"), - N_("Eta"), - }; - - static const char *types[] = - { - N_("Symmetric"), - N_("%s Dependent"), - N_("%s Dependent"), - }; - - static const int stats_categories[N_DIRECTIONAL] = - { - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, - }; - - static const int stats_stats[N_DIRECTIONAL] = - { - 0, 0, 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, - }; - - static const int stats_types[N_DIRECTIONAL] = - { - 0, 1, 2, 1, 2, 0, 1, 2, 0, 1, 2, 1, 2, - }; - - static const int *stats_lookup[] = - { - stats_categories, - stats_stats, - stats_types, - }; - - static const char **stats_names[] = - { - categories, - stats, - types, - }; - - int last[3] = - { - -1, -1, -1, - }; - double direct_v[N_DIRECTIONAL]; double direct_ase[N_DIRECTIONAL]; double direct_t[N_DIRECTIONAL]; double sig[N_DIRECTIONAL]; - - int i; - if (!calc_directional (proc, xt, direct_v, direct_ase, direct_t, sig)) return; - tab_offset (direct, xt->n_consts + xt->n_vars - 2, -1); + size_t *indexes = xnmalloc (direct->n_dimensions, sizeof *indexes); + assert (xt->n_vars == 2); + for (size_t i = 0; i < xt->n_consts; i++) + indexes[i + 2] = xt->const_indexes[i]; - for (i = 0; i < N_DIRECTIONAL; i++) + for (int i = 0; i < N_DIRECTIONAL; i++) { if (direct_v[i] == SYSMIS) continue; - { - int j; - - for (j = 0; j < 3; j++) - if (last[j] != stats_lookup[j][i]) - { - if (j < 2) - tab_hline (direct, TAL_1, j, 6, 0); - - for (; j < 3; j++) - { - const char *string; - int k = last[j] = stats_lookup[j][i]; - - if (k == 0) - string = NULL; - else if (k == 1) - string = var_to_string (xt->vars[0].var); - else - string = var_to_string (xt->vars[1].var); - - tab_text_format (direct, j, 0, TAB_LEFT, - gettext (stats_names[j][k]), string); - } - } - } + indexes[1] = i; - tab_double (direct, 3, 0, TAB_RIGHT, direct_v[i], NULL, RC_OTHER); - if (direct_ase[i] != SYSMIS) - tab_double (direct, 4, 0, TAB_RIGHT, direct_ase[i], NULL, RC_OTHER); - if (direct_t[i] != SYSMIS) - tab_double (direct, 5, 0, TAB_RIGHT, direct_t[i], NULL, RC_OTHER); - tab_double (direct, 6, 0, TAB_RIGHT, sig[i], NULL, RC_PVALUE); - tab_next_row (direct); + double entries[] = { + direct_v[i], direct_ase[i], direct_t[i], sig[i], + }; + for (size_t j = 0; j < sizeof entries / sizeof *entries; j++) + if (entries[j] != SYSMIS) + { + indexes[0] = j; + pivot_table_put (direct, indexes, direct->n_dimensions, + pivot_value_new_number (entries[j])); + } } - - tab_offset (direct, 0, -1); } /* Statistical calculations. */ @@ -2246,8 +1978,6 @@ calc_chisq (struct crosstabulation *xt, double chisq[N_CHISQ], int df[N_CHISQ], double *fisher1, double *fisher2) { - int r, c; - chisq[0] = chisq[1] = 0.; chisq[2] = chisq[3] = chisq[4] = SYSMIS; *fisher1 = *fisher2 = SYSMIS; @@ -2260,18 +1990,17 @@ calc_chisq (struct crosstabulation *xt, return; } - size_t n_rows = xt->vars[ROW_VAR].n_values; size_t n_cols = xt->vars[COL_VAR].n_values; - for (r = 0; r < n_rows; r++) - for (c = 0; c < n_cols; c++) + FOR_EACH_POPULATED_ROW (r, xt) + FOR_EACH_POPULATED_COLUMN (c, xt) { - const double expected = xt->row_tot[r] * xt->col_tot[c] / xt->total; - const double freq = xt->mat[n_cols * r + c]; - const double residual = freq - expected; + const double expected = xt->row_tot[r] * xt->col_tot[c] / xt->total; + const double freq = xt->mat[n_cols * r + c]; + const double residual = freq - expected; chisq[0] += residual * residual / expected; - if (freq) - chisq[1] += freq * log (expected / freq); + if (freq) + chisq[1] += freq * log (expected / freq); } if (chisq[0] == 0.) @@ -2289,16 +2018,14 @@ calc_chisq (struct crosstabulation *xt, { int nz_cols[2]; - int i, j; - - for (i = j = 0; i < n_cols; i++) - if (xt->col_tot[i] != 0.) - { - nz_cols[j++] = i; - if (j == 2) - break; - } + int j = 0; + FOR_EACH_POPULATED_COLUMN (c, xt) + { + nz_cols[j++] = c; + if (j == 2) + break; + } assert (j == 2); f11 = xt->mat[nz_cols[0]]; @@ -2433,14 +2160,13 @@ calc_symmetric (struct crosstabs_proc *proc, struct crosstabulation *xt, if (proc->statistics & ((1u << CRS_ST_PHI) | (1u << CRS_ST_CC))) { double Xp = 0.; /* Pearson chi-square. */ - int r, c; - for (r = 0; r < n_rows; r++) - for (c = 0; c < n_cols; c++) + FOR_EACH_POPULATED_ROW (r, xt) + FOR_EACH_POPULATED_COLUMN (c, xt) { - const double expected = xt->row_tot[r] * xt->col_tot[c] / xt->total; - const double freq = xt->mat[n_cols * r + c]; - const double residual = freq - expected; + double expected = xt->row_tot[r] * xt->col_tot[c] / xt->total; + double freq = xt->mat[n_cols * r + c]; + double residual = freq - expected; Xp += residual * residual / expected; } @@ -2738,42 +2464,41 @@ calc_symmetric (struct crosstabs_proc *proc, struct crosstabulation *xt, } /* Calculate risk estimate. */ -static int +static bool calc_risk (struct crosstabulation *xt, - double *value, double *upper, double *lower, union value *c) + double *value, double *upper, double *lower, union value *c, + double *n_valid) { size_t n_cols = xt->vars[COL_VAR].n_values; double f11, f12, f21, f22; double v; - { - int i; - - for (i = 0; i < 3; i++) - value[i] = upper[i] = lower[i] = SYSMIS; - } + for (int i = 0; i < 3; i++) + value[i] = upper[i] = lower[i] = SYSMIS; if (xt->ns_rows != 2 || xt->ns_cols != 2) - return 0; + return false; { + /* Find populated columns. */ int nz_cols[2]; - int i, j; - - for (i = j = 0; i < n_cols; i++) - if (xt->col_tot[i] != 0.) - { - nz_cols[j++] = i; - if (j == 2) - break; - } - - assert (j == 2); - - f11 = xt->mat[nz_cols[0]]; - f12 = xt->mat[nz_cols[1]]; - f21 = xt->mat[nz_cols[0] + n_cols]; - f22 = xt->mat[nz_cols[1] + n_cols]; + int n = 0; + FOR_EACH_POPULATED_COLUMN (c, xt) + nz_cols[n++] = c; + assert (n == 2); + + /* Find populated rows. */ + int nz_rows[2]; + n = 0; + FOR_EACH_POPULATED_ROW (r, xt) + nz_rows[n++] = r; + assert (n == 2); + + f11 = xt->mat[nz_cols[0] + n_cols * nz_rows[0]]; + f12 = xt->mat[nz_cols[1] + n_cols * nz_rows[0]]; + f21 = xt->mat[nz_cols[0] + n_cols * nz_rows[1]]; + f22 = xt->mat[nz_cols[1] + n_cols * nz_rows[1]]; + *n_valid = f11 + f12 + f21 + f22; c[0] = xt->vars[COL_VAR].values[nz_cols[0]]; c[1] = xt->vars[COL_VAR].values[nz_cols[1]]; @@ -2796,7 +2521,7 @@ calc_risk (struct crosstabulation *xt, lower[2] = value[2] * exp (-1.960 * v); upper[2] = value[2] * exp (1.960 * v); - return 1; + return true; } /* Calculate directional measures. */ @@ -2807,63 +2532,58 @@ calc_directional (struct crosstabs_proc *proc, struct crosstabulation *xt, { size_t n_rows = xt->vars[ROW_VAR].n_values; size_t n_cols = xt->vars[COL_VAR].n_values; - { - int i; - - for (i = 0; i < N_DIRECTIONAL; i++) - v[i] = ase[i] = t[i] = sig[i] = SYSMIS; - } + for (int i = 0; i < N_DIRECTIONAL; i++) + v[i] = ase[i] = t[i] = sig[i] = SYSMIS; /* Lambda. */ if (proc->statistics & (1u << CRS_ST_LAMBDA)) { + /* Find maximum for each row and their sum. */ double *fim = xnmalloc (n_rows, sizeof *fim); int *fim_index = xnmalloc (n_rows, sizeof *fim_index); - double *fmj = xnmalloc (n_cols, sizeof *fmj); - int *fmj_index = xnmalloc (n_cols, sizeof *fmj_index); - double sum_fim, sum_fmj; - double rm, cm; - int rm_index, cm_index; - int i, j; - - /* Find maximum for each row and their sum. */ - for (sum_fim = 0., i = 0; i < n_rows; i++) + double sum_fim = 0.0; + for (int i = 0; i < n_rows; i++) { double max = xt->mat[i * n_cols]; int index = 0; - for (j = 1; j < n_cols; j++) + for (int j = 1; j < n_cols; j++) if (xt->mat[j + i * n_cols] > max) { max = xt->mat[j + i * n_cols]; index = j; } - sum_fim += fim[i] = max; + fim[i] = max; + sum_fim += max; fim_index[i] = index; } /* Find maximum for each column. */ - for (sum_fmj = 0., j = 0; j < n_cols; j++) + double *fmj = xnmalloc (n_cols, sizeof *fmj); + int *fmj_index = xnmalloc (n_cols, sizeof *fmj_index); + double sum_fmj = 0.0; + for (int j = 0; j < n_cols; j++) { double max = xt->mat[j]; int index = 0; - for (i = 1; i < n_rows; i++) + for (int i = 1; i < n_rows; i++) if (xt->mat[j + i * n_cols] > max) { max = xt->mat[j + i * n_cols]; index = i; } - sum_fmj += fmj[j] = max; + fmj[j] = max; + sum_fmj += max; fmj_index[j] = index; } /* Find maximum row total. */ - rm = xt->row_tot[0]; - rm_index = 0; - for (i = 1; i < n_rows; i++) + double rm = xt->row_tot[0]; + int rm_index = 0; + for (int i = 1; i < n_rows; i++) if (xt->row_tot[i] > rm) { rm = xt->row_tot[i]; @@ -2871,9 +2591,9 @@ calc_directional (struct crosstabs_proc *proc, struct crosstabulation *xt, } /* Find maximum column total. */ - cm = xt->col_tot[0]; - cm_index = 0; - for (j = 1; j < n_cols; j++) + double cm = xt->col_tot[0]; + int cm_index = 0; + for (int j = 1; j < n_cols; j++) if (xt->col_tot[j] > cm) { cm = xt->col_tot[j]; @@ -2886,10 +2606,8 @@ calc_directional (struct crosstabs_proc *proc, struct crosstabulation *xt, /* ASE1 for Y given XT. */ { - double accum; - - accum = 0.; - for (i = 0; i < n_rows; i++) + double accum = 0.0; + for (int i = 0; i < n_rows; i++) if (cm_index == fim_index[i]) accum += fim[i]; ase[2] = sqrt ((xt->total - sum_fim) * (sum_fim + cm - 2. * accum) @@ -2898,9 +2616,8 @@ calc_directional (struct crosstabs_proc *proc, struct crosstabulation *xt, /* ASE0 for Y given XT. */ { - double accum; - - for (accum = 0., i = 0; i < n_rows; i++) + double accum = 0.0; + for (int i = 0; i < n_rows; i++) if (cm_index != fim_index[i]) accum += (xt->mat[i * n_cols + fim_index[i]] + xt->mat[i * n_cols + cm_index]); @@ -2909,10 +2626,8 @@ calc_directional (struct crosstabs_proc *proc, struct crosstabulation *xt, /* ASE1 for XT given Y. */ { - double accum; - - accum = 0.; - for (j = 0; j < n_cols; j++) + double accum = 0.0; + for (int j = 0; j < n_cols; j++) if (rm_index == fmj_index[j]) accum += fmj[j]; ase[1] = sqrt ((xt->total - sum_fmj) * (sum_fmj + rm - 2. * accum) @@ -2921,9 +2636,8 @@ calc_directional (struct crosstabs_proc *proc, struct crosstabulation *xt, /* ASE0 for XT given Y. */ { - double accum; - - for (accum = 0., j = 0; j < n_cols; j++) + double accum = 0.0; + for (int j = 0; j < n_cols; j++) if (rm_index != fmj_index[j]) accum += (xt->mat[j + n_cols * fmj_index[j]] + xt->mat[j + n_cols * rm_index]); @@ -2932,11 +2646,10 @@ calc_directional (struct crosstabs_proc *proc, struct crosstabulation *xt, /* Symmetric ASE0 and ASE1. */ { - double accum0; - double accum1; - - for (accum0 = accum1 = 0., i = 0; i < n_rows; i++) - for (j = 0; j < n_cols; j++) + double accum0 = 0.0; + double accum1 = 0.0; + for (int i = 0; i < n_rows; i++) + for (int j = 0; j < n_cols; j++) { int temp0 = (fmj_index[j] == i) + (fim_index[i] == j); int temp1 = (i == rm_index) + (j == cm_index); @@ -2949,7 +2662,7 @@ calc_directional (struct crosstabs_proc *proc, struct crosstabulation *xt, / (2. * xt->total - rm - cm)); } - for (i = 0; i < 3; i++) + for (int i = 0; i < 3; i++) sig[i] = 2 * gsl_cdf_ugaussian_Q (t[i]); free (fim); @@ -2959,21 +2672,22 @@ calc_directional (struct crosstabs_proc *proc, struct crosstabulation *xt, /* Tau. */ { - double sum_fij2_ri, sum_fij2_ci; - double sum_ri2, sum_cj2; - - for (sum_fij2_ri = sum_fij2_ci = 0., i = 0; i < n_rows; i++) - for (j = 0; j < n_cols; j++) + double sum_fij2_ri = 0.0; + double sum_fij2_ci = 0.0; + FOR_EACH_POPULATED_ROW (i, xt) + FOR_EACH_POPULATED_COLUMN (j, xt) { double temp = pow2 (xt->mat[j + i * n_cols]); sum_fij2_ri += temp / xt->row_tot[i]; sum_fij2_ci += temp / xt->col_tot[j]; } - for (sum_ri2 = 0., i = 0; i < n_rows; i++) + double sum_ri2 = 0.0; + for (int i = 0; i < n_rows; i++) sum_ri2 += pow2 (xt->row_tot[i]); - for (sum_cj2 = 0., j = 0; j < n_cols; j++) + double sum_cj2 = 0.0; + for (int j = 0; j < n_cols; j++) sum_cj2 += pow2 (xt->col_tot[j]); v[3] = (xt->total * sum_fij2_ci - sum_ri2) / (pow2 (xt->total) - sum_ri2); @@ -2983,20 +2697,18 @@ calc_directional (struct crosstabs_proc *proc, struct crosstabulation *xt, if (proc->statistics & (1u << CRS_ST_UC)) { - double UX, UY, UXY, P; - double ase1_yx, ase1_xy, ase1_sym; - int i, j; + double UX = 0.0; + FOR_EACH_POPULATED_ROW (i, xt) + UX -= xt->row_tot[i] / xt->total * log (xt->row_tot[i] / xt->total); - for (UX = 0., i = 0; i < n_rows; i++) - if (xt->row_tot[i] > 0.) - UX -= xt->row_tot[i] / xt->total * log (xt->row_tot[i] / xt->total); + double UY = 0.0; + FOR_EACH_POPULATED_COLUMN (j, xt) + UY -= xt->col_tot[j] / xt->total * log (xt->col_tot[j] / xt->total); - for (UY = 0., j = 0; j < n_cols; j++) - if (xt->col_tot[j] > 0.) - UY -= xt->col_tot[j] / xt->total * log (xt->col_tot[j] / xt->total); - - for (UXY = P = 0., i = 0; i < n_rows; i++) - for (j = 0; j < n_cols; j++) + double UXY = 0.0; + double P = 0.0; + for (int i = 0; i < n_rows; i++) + for (int j = 0; j < n_cols; j++) { double entry = xt->mat[j + i * n_cols]; @@ -3007,8 +2719,11 @@ calc_directional (struct crosstabs_proc *proc, struct crosstabulation *xt, UXY -= entry / xt->total * log (entry / xt->total); } - for (ase1_yx = ase1_xy = ase1_sym = 0., i = 0; i < n_rows; i++) - for (j = 0; j < n_cols; j++) + double ase1_yx = 0.0; + double ase1_xy = 0.0; + double ase1_sym = 0.0; + for (int i = 0; i < n_rows; i++) + for (int j = 0; j < n_cols; j++) { double entry = xt->mat[j + i * n_cols]; @@ -3050,8 +2765,7 @@ calc_directional (struct crosstabs_proc *proc, struct crosstabulation *xt, if (calc_symmetric (proc, xt, v_dummy, ase_dummy, t_dummy, somers_d_v, somers_d_ase, somers_d_t)) { - int i; - for (i = 0; i < 3; i++) + for (int i = 0; i < 3; i++) { v[8 + i] = somers_d_v[i]; ase[8 + i] = somers_d_ase[i]; @@ -3064,63 +2778,58 @@ calc_directional (struct crosstabs_proc *proc, struct crosstabulation *xt, /* Eta. */ if (proc->statistics & (1u << CRS_ST_ETA)) { - { - double sum_Xr, sum_X2r; - double SX, SXW; - int i, j; - - for (sum_Xr = sum_X2r = 0., i = 0; i < n_rows; i++) - { - sum_Xr += xt->vars[ROW_VAR].values[i].f * xt->row_tot[i]; - sum_X2r += pow2 (xt->vars[ROW_VAR].values[i].f) * xt->row_tot[i]; - } - SX = sum_X2r - pow2 (sum_Xr) / xt->total; - - for (SXW = 0., j = 0; j < n_cols; j++) - { - double cum; - - for (cum = 0., i = 0; i < n_rows; i++) - { - SXW += (pow2 (xt->vars[ROW_VAR].values[i].f) - * xt->mat[j + i * n_cols]); - cum += (xt->vars[ROW_VAR].values[i].f - * xt->mat[j + i * n_cols]); - } + /* X dependent. */ + double sum_Xr = 0.0; + double sum_X2r = 0.0; + for (int i = 0; i < n_rows; i++) + { + sum_Xr += xt->vars[ROW_VAR].values[i].f * xt->row_tot[i]; + sum_X2r += pow2 (xt->vars[ROW_VAR].values[i].f) * xt->row_tot[i]; + } + double SX = sum_X2r - pow2 (sum_Xr) / xt->total; - SXW -= cum * cum / xt->col_tot[j]; - } - v[11] = sqrt (1. - SXW / SX); - } + double SXW = 0.0; + FOR_EACH_POPULATED_COLUMN (j, xt) + { + double cum = 0.0; - { - double sum_Yc, sum_Y2c; - double SY, SYW; - int i, j; + for (int i = 0; i < n_rows; i++) + { + SXW += (pow2 (xt->vars[ROW_VAR].values[i].f) + * xt->mat[j + i * n_cols]); + cum += (xt->vars[ROW_VAR].values[i].f + * xt->mat[j + i * n_cols]); + } - for (sum_Yc = sum_Y2c = 0., i = 0; i < n_cols; i++) - { - sum_Yc += xt->vars[COL_VAR].values[i].f * xt->col_tot[i]; - sum_Y2c += pow2 (xt->vars[COL_VAR].values[i].f) * xt->col_tot[i]; - } - SY = sum_Y2c - sum_Yc * sum_Yc / xt->total; + SXW -= cum * cum / xt->col_tot[j]; + } + v[11] = sqrt (1. - SXW / SX); - for (SYW = 0., i = 0; i < n_rows; i++) - { - double cum; + /* Y dependent. */ + double sum_Yc = 0.0; + double sum_Y2c = 0.0; + for (int i = 0; i < n_cols; i++) + { + sum_Yc += xt->vars[COL_VAR].values[i].f * xt->col_tot[i]; + sum_Y2c += pow2 (xt->vars[COL_VAR].values[i].f) * xt->col_tot[i]; + } + double SY = sum_Y2c - pow2 (sum_Yc) / xt->total; - for (cum = 0., j = 0; j < n_cols; j++) - { - SYW += (pow2 (xt->vars[COL_VAR].values[j].f) - * xt->mat[j + i * n_cols]); - cum += (xt->vars[COL_VAR].values[j].f - * xt->mat[j + i * n_cols]); - } + double SYW = 0.0; + FOR_EACH_POPULATED_ROW (i, xt) + { + double cum = 0.0; + for (int j = 0; j < n_cols; j++) + { + SYW += (pow2 (xt->vars[COL_VAR].values[j].f) + * xt->mat[j + i * n_cols]); + cum += (xt->vars[COL_VAR].values[j].f + * xt->mat[j + i * n_cols]); + } - SYW -= cum * cum / xt->row_tot[i]; - } - v[12] = sqrt (1. - SYW / SY); - } + SYW -= cum * cum / xt->row_tot[i]; + } + v[12] = sqrt (1. - SYW / SY); } return 1; diff --git a/src/language/stats/descriptives.c b/src/language/stats/descriptives.c index 11a9f7f31e..2738fb137e 100644 --- a/src/language/stats/descriptives.c +++ b/src/language/stats/descriptives.c @@ -38,7 +38,7 @@ #include "libpspp/i18n.h" #include "libpspp/message.h" #include "math/moments.h" -#include "output/tab.h" +#include "output/pivot-table.h" #include "gl/xalloc.h" @@ -136,26 +136,17 @@ struct dsc_var double stats[DSC_N_STATS]; /* All the stats' values. */ }; -/* Output format. */ -enum dsc_format - { - DSC_LINE, /* Abbreviated format. */ - DSC_SERIAL /* Long format. */ - }; - /* A DESCRIPTIVES procedure. */ struct dsc_proc { /* Per-variable info. */ + struct dictionary *dict; /* Dictionary. */ struct dsc_var *vars; /* Variables. */ size_t var_cnt; /* Number of variables. */ /* User options. */ enum dsc_missing_type missing_type; /* Treatment of missing values. */ enum mv_class exclude; /* Classes of missing values to exclude. */ - int show_var_labels; /* Nonzero to show variable labels. */ - int show_index; /* Nonzero to show variable index. */ - enum dsc_format format; /* Output format. */ /* Accumulated results. */ double missing_listwise; /* Sum of weights of cases missing listwise. */ @@ -209,13 +200,11 @@ cmd_descriptives (struct lexer *lexer, struct dataset *ds) /* Create and initialize dsc. */ dsc = xmalloc (sizeof *dsc); + dsc->dict = dict; dsc->vars = NULL; dsc->var_cnt = 0; dsc->missing_type = DSC_VARIABLE; dsc->exclude = MV_ANY; - dsc->show_var_labels = 1; - dsc->show_index = 0; - dsc->format = DSC_LINE; dsc->missing_listwise = 0.; dsc->valid = 0.; dsc->bad_warn = 1; @@ -253,18 +242,15 @@ cmd_descriptives (struct lexer *lexer, struct dataset *ds) lex_match (lexer, T_EQUALS); while (lex_token (lexer) != T_ENDCMD && lex_token (lexer) != T_SLASH) { - if (lex_match_id (lexer, "LABELS")) - dsc->show_var_labels = 1; - else if (lex_match_id (lexer, "NOLABELS")) - dsc->show_var_labels = 0; - else if (lex_match_id (lexer, "INDEX")) - dsc->show_index = 1; - else if (lex_match_id (lexer, "NOINDEX")) - dsc->show_index = 0; - else if (lex_match_id (lexer, "LINE")) - dsc->format = DSC_LINE; - else if (lex_match_id (lexer, "SERIAL")) - dsc->format = DSC_SERIAL; + if (lex_match_id (lexer, "LABELS") + || lex_match_id (lexer, "NOLABELS") + || lex_match_id (lexer, "INDEX") + || lex_match_id (lexer, "NOINDEX") + || lex_match_id (lexer, "LINE") + || lex_match_id (lexer, "SERIAL")) + { + /* Ignore. */ + } else { lex_error (lexer, NULL); @@ -589,37 +575,29 @@ generate_z_varname (const struct dictionary *dict, struct dsc_proc *dsc, static void dump_z_table (struct dsc_proc *dsc) { - size_t cnt = 0; - struct tab_table *t; + struct pivot_table *table = pivot_table_create ( + N_("Mapping of Variables to Z-scores")); - { - size_t i; + pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Names"), + N_("Source"), N_("Target")); - for (i = 0; i < dsc->var_cnt; i++) - if (dsc->vars[i].z_name != NULL) - cnt++; - } - - t = tab_create (2, cnt + 1); - tab_title (t, _("Mapping of variables to corresponding Z-scores.")); - tab_headers (t, 0, 0, 1, 0); - tab_box (t, TAL_1, TAL_1, TAL_0, TAL_1, 0, 0, 1, cnt); - tab_hline (t, TAL_2, 0, 1, 1); - tab_text (t, 0, 0, TAB_CENTER | TAT_TITLE, _("Source")); - tab_text (t, 1, 0, TAB_CENTER | TAT_TITLE, _("Target")); + struct pivot_dimension *names = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Variables")); + names->hide_all_labels = true; - { - size_t i, y; + for (size_t i = 0; i < dsc->var_cnt; i++) + if (dsc->vars[i].z_name != NULL) + { + int row = pivot_category_create_leaf (names->root, + pivot_value_new_number (i)); - for (i = 0, y = 1; i < dsc->var_cnt; i++) - if (dsc->vars[i].z_name != NULL) - { - tab_text (t, 0, y, TAB_LEFT, var_to_string (dsc->vars[i].v)); - tab_text (t, 1, y++, TAB_LEFT, dsc->vars[i].z_name); - } - } + pivot_table_put2 (table, 0, row, + pivot_value_new_variable (dsc->vars[i].v)); + pivot_table_put2 (table, 1, row, + pivot_value_new_user_text (dsc->vars[i].z_name, -1)); + } - tab_submit (t); + pivot_table_submit (table); } static void @@ -1003,64 +981,53 @@ static algo_compare_func descriptives_compare_dsc_vars; static void display (struct dsc_proc *dsc) { - size_t i; - int nc; - struct tab_table *t; - - nc = 1 + (dsc->format == DSC_SERIAL ? 2 : 1); - for (i = 0; i < DSC_N_STATS; i++) + struct pivot_table *table = pivot_table_create ( + N_("Descriptive Statistics")); + pivot_table_set_weight_var (table, dict_get_weight (dsc->dict)); + + struct pivot_dimension *statistics = pivot_dimension_create ( + table, PIVOT_AXIS_COLUMN, N_("Statistics")); + pivot_category_create_leaf_rc ( + statistics->root, pivot_value_new_text (N_("N")), PIVOT_RC_COUNT); + for (int i = 0; i < DSC_N_STATS; i++) if (dsc->show_stats & (1ul << i)) - nc++; + pivot_category_create_leaf (statistics->root, + pivot_value_new_text (dsc_info[i].name)); if (dsc->sort_by_stat != DSC_NONE) sort (dsc->vars, dsc->var_cnt, sizeof *dsc->vars, descriptives_compare_dsc_vars, dsc); - t = tab_create (nc, dsc->var_cnt + 1); - tab_headers (t, 1, 0, 1, 0); - tab_box (t, TAL_1, TAL_1, -1, -1, 0, 0, nc - 1, dsc->var_cnt); - tab_box (t, -1, -1, -1, TAL_1, 1, 0, nc - 1, dsc->var_cnt); - tab_hline (t, TAL_2, 0, nc - 1, 1); - tab_vline (t, TAL_2, 1, 0, dsc->var_cnt); - - nc = 0; - tab_text (t, nc++, 0, TAB_LEFT | TAT_TITLE, _("Variable")); - if (dsc->format == DSC_SERIAL) - { - tab_text (t, nc++, 0, TAB_CENTER | TAT_TITLE, _("Valid N")); - tab_text (t, nc++, 0, TAB_CENTER | TAT_TITLE, _("Missing N")); - } - else - tab_text (t, nc++, 0, TAB_CENTER | TAT_TITLE, "N"); - - for (i = 0; i < DSC_N_STATS; i++) - if (dsc->show_stats & (1ul << i)) - { - const char *title = gettext (dsc_info[i].name); - tab_text (t, nc++, 0, TAB_CENTER | TAT_TITLE, title); - } - - for (i = 0; i < dsc->var_cnt; i++) + struct pivot_dimension *variables = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Variable")); + for (size_t i = 0; i < dsc->var_cnt; i++) { struct dsc_var *dv = &dsc->vars[i]; - size_t j; - nc = 0; - tab_text (t, nc++, i + 1, TAB_LEFT, var_to_string (dv->v)); - tab_text_format (t, nc++, i + 1, 0, "%.*g", DBL_DIG + 1, dv->valid); - if (dsc->format == DSC_SERIAL) - tab_text_format (t, nc++, i + 1, 0, "%.*g", DBL_DIG + 1, dv->missing); + int row = pivot_category_create_leaf (variables->root, + pivot_value_new_variable (dv->v)); - for (j = 0; j < DSC_N_STATS; j++) + int column = 0; + pivot_table_put2 (table, column++, row, + pivot_value_new_number (dv->valid)); + + for (int j = 0; j < DSC_N_STATS; j++) if (dsc->show_stats & (1ul << j)) - tab_double (t, nc++, i + 1, TAB_NONE, dv->stats[j], NULL, RC_OTHER); + { + union value v = { .f = dv->stats[j] }; + struct pivot_value *pv = (j == DSC_MIN || j == DSC_MAX + ? pivot_value_new_var_value (dv->v, &v) + : pivot_value_new_number (dv->stats[j])); + pivot_table_put2 (table, column++, row, pv); + } } - tab_title (t, _("Valid cases = %.*g; cases with missing value(s) = %.*g."), - DBL_DIG + 1, dsc->valid, - DBL_DIG + 1, dsc->missing_listwise); - - tab_submit (t); + int row = pivot_category_create_leaves ( + variables->root, N_("Valid N (listwise)"), N_("Missing N (listwise)")); + pivot_table_put2 (table, 0, row, pivot_value_new_number (dsc->valid)); + pivot_table_put2 (table, 0, row + 1, + pivot_value_new_number (dsc->missing_listwise)); + pivot_table_submit (table); } /* Compares `struct dsc_var's A and B according to the ordering diff --git a/src/language/stats/examine.c b/src/language/stats/examine.c index 861f81f2d2..4f47a6c95a 100644 --- a/src/language/stats/examine.c +++ b/src/language/stats/examine.c @@ -60,7 +60,7 @@ #include "language/lexer/value-parser.h" #include "language/lexer/variable-parser.h" -#include "output/tab.h" +#include "output/pivot-table.h" #include "gettext.h" #define _(msgid) gettext (msgid) @@ -196,54 +196,6 @@ struct exploratory_stats double cmin; }; - -/* Returns an array of (iact->n_vars) pointers to union value initialised to NULL. - The caller must free this array when no longer required. */ -static const union value ** -previous_value_alloc (const struct interaction *iact) -{ - int ivar_idx; - - const union value **prev_val = xcalloc (iact->n_vars, sizeof (*prev_val)); - - for (ivar_idx = 0; ivar_idx < iact->n_vars; ++ivar_idx) - prev_val[ivar_idx] = NULL; - - return prev_val; -} - -/* Set the contents of PREV_VAL to the values of C indexed by the variables of IACT */ -static int -previous_value_record (const struct interaction *iact, const struct ccase *c, const union value **prev_val) -{ - int ivar_idx; - int diff_idx = -1; - - for (ivar_idx = 0; ivar_idx < iact->n_vars; ++ivar_idx) - { - const struct variable *ivar = iact->vars[ivar_idx]; - const int width = var_get_width (ivar); - const union value *val = case_data (c, ivar); - - if (prev_val[ivar_idx]) - if (! value_equal (prev_val[ivar_idx], val, width)) - { - diff_idx = ivar_idx; - break; - } - } - - for (ivar_idx = 0; ivar_idx < iact->n_vars; ++ivar_idx) - { - const struct variable *ivar = iact->vars[ivar_idx]; - const union value *val = case_data (c, ivar); - - prev_val[ivar_idx] = val; - } - return diff_idx; -} - - static void show_boxplot_grouped (const struct examine *cmd, int iact_idx) { @@ -589,888 +541,380 @@ show_histogram (const struct examine *cmd, int iact_idx) } } -static void -percentiles_report (const struct examine *cmd, int iact_idx) +static struct pivot_value * +new_value_with_missing_footnote (const struct variable *var, + const union value *value, + struct pivot_footnote *missing_footnote) { - const struct interaction *iact = cmd->iacts[iact_idx]; - int i, v; - const int heading_columns = 1 + iact->n_vars + 1; - const int heading_rows = 2; - struct tab_table *t; - - const size_t n_cats = categoricals_n_count (cmd->cats, iact_idx); - - const int rows_per_cat = 2; - const int rows_per_var = n_cats * rows_per_cat; - - const int nr = heading_rows + cmd->n_dep_vars * rows_per_var; - const int nc = heading_columns + cmd->n_percentiles; - - t = tab_create (nc, nr); - - tab_title (t, _("Percentiles")); - - tab_headers (t, heading_columns, 0, heading_rows, 0); - - /* Internal Vertical lines */ - tab_box (t, -1, -1, -1, TAL_1, - heading_columns, 0, nc - 1, nr - 1); - - /* External Frame */ - tab_box (t, TAL_2, TAL_2, -1, -1, - 0, 0, nc - 1, nr - 1); - - tab_hline (t, TAL_2, 0, nc - 1, heading_rows); - tab_vline (t, TAL_2, heading_columns, 0, nr - 1); - - tab_joint_text (t, heading_columns, 0, - nc - 1, 0, - TAT_TITLE | TAB_CENTER, - _("Percentiles") - ); - - tab_hline (t, TAL_1, heading_columns, nc - 1, 1); - - - for (i = 0; i < cmd->n_percentiles; ++i) - { - tab_text_format (t, heading_columns + i, 1, - TAT_TITLE | TAB_CENTER, - _("%g"), cmd->ptiles[i]); - } + struct pivot_value *pv = pivot_value_new_var_value (var, value); + if (var_is_value_missing (var, value, MV_USER)) + pivot_value_add_footnote (pv, missing_footnote); + return pv; +} - for (i = 0; i < iact->n_vars; ++i) +static void +create_interaction_dimensions (struct pivot_table *table, + const struct categoricals *cats, + const struct interaction *iact, + struct pivot_footnote *missing_footnote) +{ + for (size_t i = iact->n_vars; i-- > 0; ) { - tab_text (t, - 1 + i, 1, - TAT_TITLE, - var_to_string (iact->vars[i]) - ); + const struct variable *var = iact->vars[i]; + struct pivot_dimension *d = pivot_dimension_create__ ( + table, PIVOT_AXIS_ROW, pivot_value_new_variable (var)); + d->root->show_label = true; + + size_t n; + union value *values = categoricals_get_var_values (cats, var, &n); + for (size_t j = 0; j < n; j++) + pivot_category_create_leaf ( + d->root, new_value_with_missing_footnote (var, &values[j], + missing_footnote)); } +} +static struct pivot_footnote * +create_missing_footnote (struct pivot_table *table) +{ + return pivot_table_create_footnote ( + table, pivot_value_new_text (N_("User-missing value."))); +} +static void +percentiles_report (const struct examine *cmd, int iact_idx) +{ + struct pivot_table *table = pivot_table_create (N_("Percentiles")); + table->omit_empty = true; - if (n_cats > 0) - { - tab_vline (t, TAL_1, heading_columns - 1, heading_rows, nr - 1); - - for (v = 0; v < cmd->n_dep_vars; ++v) - { - const union value **prev_vals = previous_value_alloc (iact); - - int ivar_idx; - if ( v > 0 ) - tab_hline (t, TAL_1, 0, nc - 1, heading_rows + v * rows_per_var); - - tab_text (t, - 0, heading_rows + v * rows_per_var, - TAT_TITLE | TAB_LEFT, - var_to_string (cmd->dep_vars[v]) - ); - - for (i = 0; i < n_cats; ++i) - { - const struct ccase *c = - categoricals_get_case_by_category_real (cmd->cats, - iact_idx, i); - - const struct exploratory_stats *ess = - categoricals_get_user_data_by_category_real (cmd->cats, iact_idx, i); - - const struct exploratory_stats *es = ess + v; - - int diff_idx = previous_value_record (iact, c, prev_vals); - - double hinges[3]; - int p; - - for (ivar_idx = 0; ivar_idx < iact->n_vars; ++ivar_idx) - { - const struct variable *ivar = iact->vars[ivar_idx]; - const union value *val = case_data (c, ivar); + struct pivot_dimension *percentiles = pivot_dimension_create ( + table, PIVOT_AXIS_COLUMN, N_("Percentiles")); + percentiles->root->show_label = true; + for (int i = 0; i < cmd->n_percentiles; ++i) + pivot_category_create_leaf ( + percentiles->root, + pivot_value_new_user_text_nocopy (xasprintf ("%g", cmd->ptiles[i]))); - if (( diff_idx != -1 && diff_idx <= ivar_idx) - || i == 0) - { - struct string str; - ds_init_empty (&str); - append_value_name (ivar, val, &str); - - tab_text (t, - 1 + ivar_idx, - heading_rows + v * rows_per_var + i * rows_per_cat, - TAT_TITLE | TAB_LEFT, - ds_cstr (&str) - ); - - ds_destroy (&str); - } - } + pivot_dimension_create (table, PIVOT_AXIS_ROW, N_("Statistics"), + N_("Weighted Average"), N_("Tukey's Hinges")); - if ( diff_idx != -1 && diff_idx < iact->n_vars) - { - tab_hline (t, TAL_1, 1 + diff_idx, nc - 1, - heading_rows + v * rows_per_var + i * rows_per_cat - ); - } + const struct interaction *iact = cmd->iacts[iact_idx]; + struct pivot_footnote *missing_footnote = create_missing_footnote (table); + create_interaction_dimensions (table, cmd->cats, iact, missing_footnote); - tab_text (t, heading_columns - 1, - heading_rows + v * rows_per_var + i * rows_per_cat, - TAT_TITLE | TAB_LEFT, - gettext (ptile_alg_desc [cmd->pc_alg])); + struct pivot_dimension *dep_dim = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Dependent Variables")); - tukey_hinges_calculate (es->hinges, hinges); + size_t *indexes = xnmalloc (table->n_dimensions, sizeof *indexes); - for (p = 0; p < cmd->n_percentiles; ++p) - { - tab_double (t, heading_columns + p, - heading_rows + v * rows_per_var + i * rows_per_cat, - 0, - percentile_calculate (es->percentiles[p], cmd->pc_alg), - NULL, RC_OTHER); + size_t n_cats = categoricals_n_count (cmd->cats, iact_idx); + for (size_t v = 0; v < cmd->n_dep_vars; ++v) + { + indexes[table->n_dimensions - 1] = pivot_category_create_leaf ( + dep_dim->root, pivot_value_new_variable (cmd->dep_vars[v])); - if (cmd->ptiles[p] == 25.0) - { - tab_double (t, heading_columns + p, - heading_rows + v * rows_per_var + i * rows_per_cat + 1, - 0, - hinges[0], - NULL, RC_OTHER); - } - else if (cmd->ptiles[p] == 50.0) - { - tab_double (t, heading_columns + p, - heading_rows + v * rows_per_var + i * rows_per_cat + 1, - 0, - hinges[1], - NULL, RC_OTHER); - } - else if (cmd->ptiles[p] == 75.0) - { - tab_double (t, heading_columns + p, - heading_rows + v * rows_per_var + i * rows_per_cat + 1, - 0, - hinges[2], - NULL, RC_OTHER); - } - } + for (size_t i = 0; i < n_cats; ++i) + { + for (size_t j = 0; j < iact->n_vars; j++) + { + int idx = categoricals_get_value_index_by_category_real ( + cmd->cats, iact_idx, i, j); + indexes[table->n_dimensions - 2 - j] = idx; + } + const struct exploratory_stats *ess + = categoricals_get_user_data_by_category_real ( + cmd->cats, iact_idx, i); + const struct exploratory_stats *es = ess + v; - tab_text (t, heading_columns - 1, - heading_rows + v * rows_per_var + i * rows_per_cat + 1, - TAT_TITLE | TAB_LEFT, - _("Tukey's Hinges")); + double hinges[3]; + tukey_hinges_calculate (es->hinges, hinges); - } + for (size_t pc_idx = 0; pc_idx < cmd->n_percentiles; ++pc_idx) + { + indexes[0] = pc_idx; + + indexes[1] = 0; + double value = percentile_calculate (es->percentiles[pc_idx], + cmd->pc_alg); + pivot_table_put (table, indexes, table->n_dimensions, + pivot_value_new_number (value)); + + double hinge = (cmd->ptiles[pc_idx] == 25.0 ? hinges[0] + : cmd->ptiles[pc_idx] == 50.0 ? hinges[1] + : cmd->ptiles[pc_idx] == 75.0 ? hinges[2] + : SYSMIS); + if (hinge != SYSMIS) + { + indexes[1] = 1; + pivot_table_put (table, indexes, table->n_dimensions, + pivot_value_new_number (hinge)); + } + } + } - free (prev_vals); - } } - tab_submit (t); + free (indexes); + + pivot_table_submit (table); } static void descriptives_report (const struct examine *cmd, int iact_idx) { - const struct interaction *iact = cmd->iacts[iact_idx]; - int i, v; - const int heading_columns = 1 + iact->n_vars + 2; - const int heading_rows = 1; - struct tab_table *t; - - size_t n_cats = categoricals_n_count (cmd->cats, iact_idx); - - const int rows_per_cat = 13; - const int rows_per_var = n_cats * rows_per_cat; - - const int nr = heading_rows + cmd->n_dep_vars * rows_per_var; - const int nc = 2 + heading_columns; - - t = tab_create (nc, nr); - - tab_title (t, _("Descriptives")); - - tab_headers (t, heading_columns, 0, heading_rows, 0); + struct pivot_table *table = pivot_table_create (N_("Descriptives")); + table->omit_empty = true; + + pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Aspect"), + N_("Statistic"), N_("Std. Error")); + + struct pivot_dimension *statistics = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Statistics"), N_("Mean")); + struct pivot_category *interval = pivot_category_create_group__ ( + statistics->root, + pivot_value_new_text_format (N_("%g%% Confidence Interval for Mean"), + cmd->conf * 100.0)); + pivot_category_create_leaves (interval, N_("Lower Bound"), + N_("Upper Bound")); + pivot_category_create_leaves ( + statistics->root, N_("5% Trimmed Mean"), N_("Median"), N_("Variance"), + N_("Std. Deviation"), N_("Minimum"), N_("Maximum"), N_("Range"), + N_("Interquartile Range"), N_("Skewness"), N_("Kurtosis")); - /* Internal Vertical lines */ - tab_box (t, -1, -1, -1, TAL_1, - heading_columns, 0, nc - 1, nr - 1); - - /* External Frame */ - tab_box (t, TAL_2, TAL_2, -1, -1, - 0, 0, nc - 1, nr - 1); - - tab_hline (t, TAL_2, 0, nc - 1, heading_rows); - tab_vline (t, TAL_2, heading_columns, 0, nr - 1); - - - tab_text (t, heading_columns, 0, TAB_CENTER | TAT_TITLE, - _("Statistic")); + const struct interaction *iact = cmd->iacts[iact_idx]; + struct pivot_footnote *missing_footnote = create_missing_footnote (table); + create_interaction_dimensions (table, cmd->cats, iact, missing_footnote); - tab_text (t, heading_columns + 1, 0, TAB_CENTER | TAT_TITLE, - _("Std. Error")); + struct pivot_dimension *dep_dim = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Dependent Variables")); - for (i = 0; i < iact->n_vars; ++i) - { - tab_text (t, - 1 + i, 0, - TAT_TITLE, - var_to_string (iact->vars[i]) - ); - } + size_t *indexes = xnmalloc (table->n_dimensions, sizeof *indexes); - for (v = 0; v < cmd->n_dep_vars; ++v) + size_t n_cats = categoricals_n_count (cmd->cats, iact_idx); + for (size_t v = 0; v < cmd->n_dep_vars; ++v) { - const union value **prev_val = previous_value_alloc (iact); - - int ivar_idx; - if ( v > 0 ) - tab_hline (t, TAL_1, 0, nc - 1, heading_rows + v * rows_per_var); + indexes[table->n_dimensions - 1] = pivot_category_create_leaf ( + dep_dim->root, pivot_value_new_variable (cmd->dep_vars[v])); - tab_text (t, - 0, heading_rows + v * rows_per_var, - TAT_TITLE | TAB_LEFT, - var_to_string (cmd->dep_vars[v]) - ); - - for (i = 0; i < n_cats; ++i) + for (size_t i = 0; i < n_cats; ++i) { - const struct ccase *c = - categoricals_get_case_by_category_real (cmd->cats, - iact_idx, i); - - const struct exploratory_stats *ess = - categoricals_get_user_data_by_category_real (cmd->cats, iact_idx, i); + for (size_t j = 0; j < iact->n_vars; j++) + { + int idx = categoricals_get_value_index_by_category_real ( + cmd->cats, iact_idx, i, j); + indexes[table->n_dimensions - 2 - j] = idx; + } + const struct exploratory_stats *ess + = categoricals_get_user_data_by_category_real (cmd->cats, + iact_idx, i); const struct exploratory_stats *es = ess + v; - const int diff_idx = previous_value_record (iact, c, prev_val); - double m0, m1, m2, m3, m4; - double tval; - moments_calculate (es->mom, &m0, &m1, &m2, &m3, &m4); + double tval = gsl_cdf_tdist_Qinv ((1.0 - cmd->conf) / 2.0, m0 - 1.0); - tval = gsl_cdf_tdist_Qinv ((1.0 - cmd->conf) / 2.0, m0 - 1.0); - - for (ivar_idx = 0; ivar_idx < iact->n_vars; ++ivar_idx) + struct entry { - const struct variable *ivar = iact->vars[ivar_idx]; - const union value *val = case_data (c, ivar); - - if (( diff_idx != -1 && diff_idx <= ivar_idx) - || i == 0) - { - struct string str; - ds_init_empty (&str); - append_value_name (ivar, val, &str); - - tab_text (t, - 1 + ivar_idx, - heading_rows + v * rows_per_var + i * rows_per_cat, - TAT_TITLE | TAB_LEFT, - ds_cstr (&str) - ); - - ds_destroy (&str); - } + int stat_idx; + int aspect_idx; + double x; } - - if ( diff_idx != -1 && diff_idx < iact->n_vars) + entries[] = { + { 0, 0, m1 }, + { 0, 1, calc_semean (m2, m0) }, + { 1, 0, m1 - tval * calc_semean (m2, m0) }, + { 2, 0, m1 + tval * calc_semean (m2, m0) }, + { 3, 0, trimmed_mean_calculate (es->trimmed_mean) }, + { 4, 0, percentile_calculate (es->quartiles[1], cmd->pc_alg) }, + { 5, 0, m2 }, + { 6, 0, sqrt (m2) }, + { 7, 0, es->minima[0].val }, + { 8, 0, es->maxima[0].val }, + { 9, 0, es->maxima[0].val - es->minima[0].val }, + { 10, 0, (percentile_calculate (es->quartiles[2], cmd->pc_alg) - + percentile_calculate (es->quartiles[0], cmd->pc_alg)) }, + { 11, 0, m3 }, + { 11, 1, calc_seskew (m0) }, + { 12, 0, m4 }, + { 12, 1, calc_sekurt (m0) }, + }; + for (size_t j = 0; j < sizeof entries / sizeof *entries; j++) { - tab_hline (t, TAL_1, 1 + diff_idx, nc - 1, - heading_rows + v * rows_per_var + i * rows_per_cat - ); + const struct entry *e = &entries[j]; + indexes[0] = e->aspect_idx; + indexes[1] = e->stat_idx; + pivot_table_put (table, indexes, table->n_dimensions, + pivot_value_new_number (e->x)); } - - tab_text (t, - 1 + iact->n_vars, - heading_rows + v * rows_per_var + i * rows_per_cat, - TAB_LEFT, - _("Mean") - ); - - tab_double (t, - 1 + iact->n_vars + 2, - heading_rows + v * rows_per_var + i * rows_per_cat, - 0, m1, NULL, RC_OTHER); - - tab_double (t, - 1 + iact->n_vars + 3, - heading_rows + v * rows_per_var + i * rows_per_cat, - 0, calc_semean (m2, m0), NULL, RC_OTHER); - - tab_text_format (t, - 1 + iact->n_vars, - heading_rows + v * rows_per_var + i * rows_per_cat + 1, - TAB_LEFT, - _("%g%% Confidence Interval for Mean"), - cmd->conf * 100.0 - ); - - tab_text (t, - 1 + iact->n_vars + 1, - heading_rows + v * rows_per_var + i * rows_per_cat + 1, - TAB_LEFT, - _("Lower Bound") - ); - - tab_double (t, - 1 + iact->n_vars + 2, - heading_rows + v * rows_per_var + i * rows_per_cat + 1, - 0, m1 - tval * calc_semean (m2, m0), NULL, RC_OTHER); - - - tab_text (t, - 1 + iact->n_vars + 1, - heading_rows + v * rows_per_var + i * rows_per_cat + 2, - TAB_LEFT, - _("Upper Bound") - ); - - tab_double (t, - 1 + iact->n_vars + 2, - heading_rows + v * rows_per_var + i * rows_per_cat + 2, - 0, m1 + tval * calc_semean (m2, m0), NULL, RC_OTHER); - - - tab_text (t, - 1 + iact->n_vars, - heading_rows + v * rows_per_var + i * rows_per_cat + 3, - TAB_LEFT, - _("5% Trimmed Mean") - ); - - tab_double (t, - 1 + iact->n_vars + 2, - heading_rows + v * rows_per_var + i * rows_per_cat + 3, - 0, - trimmed_mean_calculate (es->trimmed_mean), - NULL, RC_OTHER); - - tab_text (t, - 1 + iact->n_vars, - heading_rows + v * rows_per_var + i * rows_per_cat + 4, - TAB_LEFT, - _("Median") - ); - - tab_double (t, - 1 + iact->n_vars + 2, - heading_rows + v * rows_per_var + i * rows_per_cat + 4, - 0, - percentile_calculate (es->quartiles[1], cmd->pc_alg), - NULL, RC_OTHER); - - - tab_text (t, - 1 + iact->n_vars, - heading_rows + v * rows_per_var + i * rows_per_cat + 5, - TAB_LEFT, - _("Variance") - ); - - tab_double (t, - 1 + iact->n_vars + 2, - heading_rows + v * rows_per_var + i * rows_per_cat + 5, - 0, m2, NULL, RC_OTHER); - - tab_text (t, - 1 + iact->n_vars, - heading_rows + v * rows_per_var + i * rows_per_cat + 6, - TAB_LEFT, - _("Std. Deviation") - ); - - tab_double (t, - 1 + iact->n_vars + 2, - heading_rows + v * rows_per_var + i * rows_per_cat + 6, - 0, sqrt (m2), NULL, RC_OTHER); - - tab_text (t, - 1 + iact->n_vars, - heading_rows + v * rows_per_var + i * rows_per_cat + 7, - TAB_LEFT, - _("Minimum") - ); - - tab_double (t, - 1 + iact->n_vars + 2, - heading_rows + v * rows_per_var + i * rows_per_cat + 7, - 0, - es->minima[0].val, - NULL, RC_OTHER); - - tab_text (t, - 1 + iact->n_vars, - heading_rows + v * rows_per_var + i * rows_per_cat + 8, - TAB_LEFT, - _("Maximum") - ); - - tab_double (t, - 1 + iact->n_vars + 2, - heading_rows + v * rows_per_var + i * rows_per_cat + 8, - 0, - es->maxima[0].val, - NULL, RC_OTHER); - - tab_text (t, - 1 + iact->n_vars, - heading_rows + v * rows_per_var + i * rows_per_cat + 9, - TAB_LEFT, - _("Range") - ); - - tab_double (t, - 1 + iact->n_vars + 2, - heading_rows + v * rows_per_var + i * rows_per_cat + 9, - 0, - es->maxima[0].val - es->minima[0].val, - NULL, RC_OTHER); - - tab_text (t, - 1 + iact->n_vars, - heading_rows + v * rows_per_var + i * rows_per_cat + 10, - TAB_LEFT, - _("Interquartile Range") - ); - - - tab_double (t, - 1 + iact->n_vars + 2, - heading_rows + v * rows_per_var + i * rows_per_cat + 10, - 0, - percentile_calculate (es->quartiles[2], cmd->pc_alg) - - percentile_calculate (es->quartiles[0], cmd->pc_alg), - NULL, RC_OTHER); - - - - - tab_text (t, - 1 + iact->n_vars, - heading_rows + v * rows_per_var + i * rows_per_cat + 11, - TAB_LEFT, - _("Skewness") - ); - - tab_double (t, - 1 + iact->n_vars + 2, - heading_rows + v * rows_per_var + i * rows_per_cat + 11, - 0, m3, NULL, RC_OTHER); - - tab_double (t, - 1 + iact->n_vars + 3, - heading_rows + v * rows_per_var + i * rows_per_cat + 11, - 0, calc_seskew (m0), NULL, RC_OTHER); - - tab_text (t, - 1 + iact->n_vars, - heading_rows + v * rows_per_var + i * rows_per_cat + 12, - TAB_LEFT, - _("Kurtosis") - ); - - tab_double (t, - 1 + iact->n_vars + 2, - heading_rows + v * rows_per_var + i * rows_per_cat + 12, - 0, m4, NULL, RC_OTHER); - - tab_double (t, - 1 + iact->n_vars + 3, - heading_rows + v * rows_per_var + i * rows_per_cat + 12, - 0, calc_sekurt (m0), NULL, RC_OTHER); } - - free (prev_val); } - tab_submit (t); + + free (indexes); + + pivot_table_submit (table); } static void extremes_report (const struct examine *cmd, int iact_idx) { - const struct interaction *iact = cmd->iacts[iact_idx]; - int i, v; - const int heading_columns = 1 + iact->n_vars + 2; - const int heading_rows = 1; - struct tab_table *t; - - size_t n_cats = categoricals_n_count (cmd->cats, iact_idx); - - const int rows_per_cat = 2 * cmd->disp_extremes; - const int rows_per_var = n_cats * rows_per_cat; - - const int nr = heading_rows + cmd->n_dep_vars * rows_per_var; - const int nc = 2 + heading_columns; - - t = tab_create (nc, nr); - - tab_title (t, _("Extreme Values")); - - tab_headers (t, heading_columns, 0, heading_rows, 0); + struct pivot_table *table = pivot_table_create (N_("Extreme Values")); + table->omit_empty = true; - /* Internal Vertical lines */ - tab_box (t, -1, -1, -1, TAL_1, - heading_columns, 0, nc - 1, nr - 1); + struct pivot_dimension *statistics = pivot_dimension_create ( + table, PIVOT_AXIS_COLUMN, N_("Statistics")); + pivot_category_create_leaf (statistics->root, + (cmd->id_var + ? pivot_value_new_variable (cmd->id_var) + : pivot_value_new_text (N_("Case Number")))); + pivot_category_create_leaves (statistics->root, N_("Value")); - /* External Frame */ - tab_box (t, TAL_2, TAL_2, -1, -1, - 0, 0, nc - 1, nr - 1); + struct pivot_dimension *order = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Order")); + for (size_t i = 0; i < cmd->disp_extremes; i++) + pivot_category_create_leaf (order->root, pivot_value_new_integer (i + 1)); - tab_hline (t, TAL_2, 0, nc - 1, heading_rows); - tab_vline (t, TAL_2, heading_columns, 0, nr - 1); + pivot_dimension_create (table, PIVOT_AXIS_ROW, N_("Extreme"), + N_("Highest"), N_("Lowest")); + const struct interaction *iact = cmd->iacts[iact_idx]; + struct pivot_footnote *missing_footnote = create_missing_footnote (table); + create_interaction_dimensions (table, cmd->cats, iact, missing_footnote); - if ( cmd->id_var ) - tab_text (t, heading_columns, 0, TAB_CENTER | TAT_TITLE, - var_to_string (cmd->id_var)); - else - tab_text (t, heading_columns, 0, TAB_CENTER | TAT_TITLE, - _("Case Number")); - - tab_text (t, heading_columns + 1, 0, TAB_CENTER | TAT_TITLE, - _("Value")); + struct pivot_dimension *dep_dim = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Dependent Variables")); - for (i = 0; i < iact->n_vars; ++i) - { - tab_text (t, - 1 + i, 0, - TAT_TITLE, - var_to_string (iact->vars[i]) - ); - } + size_t *indexes = xnmalloc (table->n_dimensions, sizeof *indexes); - for (v = 0; v < cmd->n_dep_vars; ++v) + size_t n_cats = categoricals_n_count (cmd->cats, iact_idx); + for (size_t v = 0; v < cmd->n_dep_vars; ++v) { - const union value **prev_val = previous_value_alloc (iact); + indexes[table->n_dimensions - 1] = pivot_category_create_leaf ( + dep_dim->root, pivot_value_new_variable (cmd->dep_vars[v])); - int ivar_idx; - if ( v > 0 ) - tab_hline (t, TAL_1, 0, nc - 1, heading_rows + v * rows_per_var); - - tab_text (t, - 0, heading_rows + v * rows_per_var, - TAT_TITLE, - var_to_string (cmd->dep_vars[v]) - ); - - for (i = 0; i < n_cats; ++i) + for (size_t i = 0; i < n_cats; ++i) { - int e; - const struct ccase *c = - categoricals_get_case_by_category_real (cmd->cats, iact_idx, i); - - const struct exploratory_stats *ess = - categoricals_get_user_data_by_category_real (cmd->cats, iact_idx, i); + for (size_t j = 0; j < iact->n_vars; j++) + { + int idx = categoricals_get_value_index_by_category_real ( + cmd->cats, iact_idx, i, j); + indexes[table->n_dimensions - 2 - j] = idx; + } + const struct exploratory_stats *ess + = categoricals_get_user_data_by_category_real (cmd->cats, + iact_idx, i); const struct exploratory_stats *es = ess + v; - int diff_idx = previous_value_record (iact, c, prev_val); - - for (ivar_idx = 0; ivar_idx < iact->n_vars; ++ivar_idx) + for (int e = 0 ; e < cmd->disp_extremes; ++e) { - const struct variable *ivar = iact->vars[ivar_idx]; - const union value *val = case_data (c, ivar); + indexes[1] = e; - if (( diff_idx != -1 && diff_idx <= ivar_idx) - || i == 0) + for (size_t j = 0; j < 2; j++) { - struct string str; - ds_init_empty (&str); - append_value_name (ivar, val, &str); - - tab_text (t, - 1 + ivar_idx, - heading_rows + v * rows_per_var + i * rows_per_cat, - TAT_TITLE | TAB_LEFT, - ds_cstr (&str) - ); - - ds_destroy (&str); + const struct extremity *extremity + = j ? &es->minima[e] : &es->maxima[e]; + indexes[2] = j; + + indexes[0] = 0; + pivot_table_put ( + table, indexes, table->n_dimensions, + (cmd->id_var + ? new_value_with_missing_footnote (cmd->id_var, + &extremity->identity, + missing_footnote) + : pivot_value_new_integer (extremity->identity.f))); + + indexes[0] = 1; + union value val = { .f = extremity->val }; + pivot_table_put ( + table, indexes, table->n_dimensions, + new_value_with_missing_footnote (cmd->dep_vars[v], &val, + missing_footnote)); } } - - if ( diff_idx != -1 && diff_idx < iact->n_vars) - { - tab_hline (t, TAL_1, 1 + diff_idx, nc - 1, - heading_rows + v * rows_per_var + i * rows_per_cat - ); - } - - tab_text (t, - heading_columns - 2, - heading_rows + v * rows_per_var + i * rows_per_cat, - TAB_RIGHT, - _("Highest")); - - - tab_hline (t, TAL_1, heading_columns - 2, nc - 1, - heading_rows + v * rows_per_var + i * rows_per_cat + cmd->disp_extremes - ); - - tab_text (t, - heading_columns - 2, - heading_rows + v * rows_per_var + i * rows_per_cat + cmd->disp_extremes, - TAB_RIGHT, - _("Lowest")); - - for (e = 0 ; e < cmd->disp_extremes; ++e) - { - tab_double (t, - heading_columns - 1, - heading_rows + v * rows_per_var + i * rows_per_cat + e, - TAB_RIGHT, - e + 1, - NULL, RC_INTEGER); - - /* The casenumber */ - if (cmd->id_var) - tab_value (t, - heading_columns, - heading_rows + v * rows_per_var + i * rows_per_cat + e, - TAB_RIGHT, - &es->maxima[e].identity, - cmd->id_var, - NULL); - else - tab_double (t, - heading_columns, - heading_rows + v * rows_per_var + i * rows_per_cat + e, - TAB_RIGHT, - es->maxima[e].identity.f, - NULL, RC_INTEGER); - - tab_double (t, - heading_columns + 1, - heading_rows + v * rows_per_var + i * rows_per_cat + e, - 0, - es->maxima[e].val, - var_get_print_format (cmd->dep_vars[v]), RC_OTHER); - - - tab_double (t, - heading_columns - 1, - heading_rows + v * rows_per_var + i * rows_per_cat + cmd->disp_extremes + e, - TAB_RIGHT, - e + 1, - NULL, RC_INTEGER); - - /* The casenumber */ - if (cmd->id_var) - tab_value (t, - heading_columns, - heading_rows + v * rows_per_var + i * rows_per_cat + cmd->disp_extremes + e, - TAB_RIGHT, - &es->minima[e].identity, - cmd->id_var, - NULL); - else - tab_double (t, - heading_columns, - heading_rows + v * rows_per_var + i * rows_per_cat + cmd->disp_extremes + e, - TAB_RIGHT, - es->minima[e].identity.f, - NULL, RC_INTEGER); - - tab_double (t, - heading_columns + 1, - heading_rows + v * rows_per_var + i * rows_per_cat + cmd->disp_extremes + e, - 0, - es->minima[e].val, - var_get_print_format (cmd->dep_vars[v]), RC_OTHER); - } } - free (prev_val); } + free (indexes); - tab_submit (t); + pivot_table_submit (table); } static void summary_report (const struct examine *cmd, int iact_idx) { - const struct interaction *iact = cmd->iacts[iact_idx]; - int i, v; - const int heading_columns = 1 + iact->n_vars; - const int heading_rows = 3; - struct tab_table *t; - - const struct fmt_spec *wfmt = cmd->wv ? var_get_print_format (cmd->wv) : &F_8_0; - - size_t n_cats = categoricals_n_count (cmd->cats, iact_idx); - - const int nr = heading_rows + n_cats * cmd->n_dep_vars; - const int nc = 6 + heading_columns; - - t = tab_create (nc, nr); - tab_set_format (t, RC_WEIGHT, wfmt); - tab_title (t, _("Case Processing Summary")); - - tab_headers (t, heading_columns, 0, heading_rows, 0); + struct pivot_table *table = pivot_table_create ( + N_("Case Processing Summary")); + table->omit_empty = true; + pivot_table_set_weight_var (table, dict_get_weight (cmd->dict)); + + pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Statistics"), + N_("N"), PIVOT_RC_COUNT, + N_("Percent"), PIVOT_RC_PERCENT); + struct pivot_dimension *cases = pivot_dimension_create ( + table, PIVOT_AXIS_COLUMN, N_("Cases"), N_("Valid"), N_("Missing"), + N_("Total")); + cases->root->show_label = true; - /* Internal Vertical lines */ - tab_box (t, -1, -1, -1, TAL_1, - heading_columns, 0, nc - 1, nr - 1); - - /* External Frame */ - tab_box (t, TAL_2, TAL_2, -1, -1, - 0, 0, nc - 1, nr - 1); - - tab_hline (t, TAL_2, 0, nc - 1, heading_rows); - tab_vline (t, TAL_2, heading_columns, 0, nr - 1); - - tab_joint_text (t, heading_columns, 0, - nc - 1, 0, TAB_CENTER | TAT_TITLE, _("Cases")); - tab_joint_text (t, - heading_columns, 1, - heading_columns + 1, 1, - TAB_CENTER | TAT_TITLE, _("Valid")); - - tab_joint_text (t, - heading_columns + 2, 1, - heading_columns + 3, 1, - TAB_CENTER | TAT_TITLE, _("Missing")); + const struct interaction *iact = cmd->iacts[iact_idx]; + struct pivot_footnote *missing_footnote = create_missing_footnote (table); + create_interaction_dimensions (table, cmd->cats, iact, missing_footnote); - tab_joint_text (t, - heading_columns + 4, 1, - heading_columns + 5, 1, - TAB_CENTER | TAT_TITLE, _("Total")); + struct pivot_dimension *dep_dim = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Dependent Variables")); - for (i = 0; i < 3; ++i) - { - tab_text (t, heading_columns + i * 2, 2, TAB_CENTER | TAT_TITLE, - _("N")); - tab_text (t, heading_columns + i * 2 + 1, 2, TAB_CENTER | TAT_TITLE, - _("Percent")); - } + size_t *indexes = xnmalloc (table->n_dimensions, sizeof *indexes); - for (i = 0; i < iact->n_vars; ++i) + size_t n_cats = categoricals_n_count (cmd->cats, iact_idx); + for (size_t v = 0; v < cmd->n_dep_vars; ++v) { - tab_text (t, - 1 + i, 2, - TAT_TITLE, - var_to_string (iact->vars[i]) - ); - } - - if (n_cats > 0) - for (v = 0; v < cmd->n_dep_vars; ++v) - { - int ivar_idx; - const union value **prev_values = previous_value_alloc (iact); - - if ( v > 0 ) - tab_hline (t, TAL_1, 0, nc - 1, heading_rows + v * n_cats); + indexes[table->n_dimensions - 1] = pivot_category_create_leaf ( + dep_dim->root, pivot_value_new_variable (cmd->dep_vars[v])); - tab_text (t, - 0, heading_rows + n_cats * v, - TAT_TITLE, - var_to_string (cmd->dep_vars[v]) - ); + for (size_t i = 0; i < n_cats; ++i) + { + for (size_t j = 0; j < iact->n_vars; j++) + { + int idx = categoricals_get_value_index_by_category_real ( + cmd->cats, iact_idx, i, j); + indexes[table->n_dimensions - 2 - j] = idx; + } + const struct exploratory_stats *es + = categoricals_get_user_data_by_category_real ( + cmd->cats, iact_idx, i); - for (i = 0; i < n_cats; ++i) - { - double total; - const struct exploratory_stats *es; - - const struct ccase *c = - categoricals_get_case_by_category_real (cmd->cats, - iact_idx, i); - if (c) - { - int diff_idx = previous_value_record (iact, c, prev_values); - - if ( diff_idx != -1 && diff_idx < iact->n_vars - 1) - tab_hline (t, TAL_1, 1 + diff_idx, nc - 1, - heading_rows + n_cats * v + i ); - - for (ivar_idx = 0; ivar_idx < iact->n_vars; ++ivar_idx) - { - const struct variable *ivar = iact->vars[ivar_idx]; - const union value *val = case_data (c, ivar); - - if (( diff_idx != -1 && diff_idx <= ivar_idx) - || i == 0) - { - struct string str; - ds_init_empty (&str); - append_value_name (ivar, val, &str); - - tab_text (t, - 1 + ivar_idx, heading_rows + n_cats * v + i, - TAT_TITLE | TAB_LEFT, - ds_cstr (&str) - ); - - ds_destroy (&str); - } - } - } - - - es = categoricals_get_user_data_by_category_real (cmd->cats, iact_idx, i); - - - total = es[v].missing + es[v].non_missing; - tab_double (t, - heading_columns + 0, - heading_rows + n_cats * v + i, - 0, - es[v].non_missing, - NULL, RC_WEIGHT); - - - tab_text_format (t, - heading_columns + 1, - heading_rows + n_cats * v + i, - 0, - "%g%%", - 100.0 * es[v].non_missing / total - ); - - - tab_double (t, - heading_columns + 2, - heading_rows + n_cats * v + i, - 0, - es[v].missing, - NULL, RC_WEIGHT); - - tab_text_format (t, - heading_columns + 3, - heading_rows + n_cats * v + i, - 0, - "%g%%", - 100.0 * es[v].missing / total - ); - tab_double (t, - heading_columns + 4, - heading_rows + n_cats * v + i, - 0, - total, - NULL, RC_WEIGHT); - - /* This can only be 100% can't it? */ - tab_text_format (t, - heading_columns + 5, - heading_rows + n_cats * v + i, - 0, - "%g%%", - 100.0 * (es[v].missing + es[v].non_missing)/ total - ); - } - free (prev_values); - } + double total = es[v].missing + es[v].non_missing; + struct entry + { + int stat_idx; + int case_idx; + double x; + } + entries[] = { + { 0, 0, es[v].non_missing }, + { 1, 0, 100.0 * es[v].non_missing / total }, + { 0, 1, es[v].missing }, + { 1, 1, 100.0 * es[v].missing / total }, + { 0, 2, total }, + { 1, 2, 100.0 }, + }; + for (size_t j = 0; j < sizeof entries / sizeof *entries; j++) + { + const struct entry *e = &entries[j]; + indexes[0] = e->stat_idx; + indexes[1] = e->case_idx; + pivot_table_put (table, indexes, table->n_dimensions, + pivot_value_new_number (e->x)); + } + } + } - tab_hline (t, TAL_1, heading_columns, nc - 1, 1); - tab_hline (t, TAL_1, heading_columns, nc - 1, 2); + free (indexes); - tab_submit (t); + pivot_table_submit (table); } /* Attempt to parse an interaction from LEXER */ diff --git a/src/language/stats/factor.c b/src/language/stats/factor.c index 095d98ff35..797c5a6725 100644 --- a/src/language/stats/factor.c +++ b/src/language/stats/factor.c @@ -47,7 +47,7 @@ #include "math/moments.h" #include "output/chart-item.h" #include "output/charts/scree.h" -#include "output/tab.h" +#include "output/pivot-table.h" #include "gettext.h" @@ -1638,162 +1638,101 @@ static void show_communalities (const struct cmd_factor * factor, const gsl_vector *initial, const gsl_vector *extracted) { - int i; - int c = 0; - const int heading_columns = 1; - int nc = heading_columns; - const int heading_rows = 1; - const int nr = heading_rows + factor->n_vars; - struct tab_table *t; - - if (factor->print & PRINT_EXTRACTION) - nc++; - - if (factor->print & PRINT_INITIAL) - nc++; - - /* No point having a table with only headings */ - if (nc <= 1) + if (!(factor->print & (PRINT_INITIAL | PRINT_EXTRACTION))) return; - t = tab_create (nc, nr); - - tab_title (t, _("Communalities")); - - tab_headers (t, heading_columns, 0, heading_rows, 0); + struct pivot_table *table = pivot_table_create (N_("Communalities")); - c = 1; + struct pivot_dimension *communalities = pivot_dimension_create ( + table, PIVOT_AXIS_COLUMN, N_("Communalities")); if (factor->print & PRINT_INITIAL) - tab_text (t, c++, 0, TAB_CENTER | TAT_TITLE, _("Initial")); - + pivot_category_create_leaves (communalities->root, N_("Initial")); if (factor->print & PRINT_EXTRACTION) - tab_text (t, c++, 0, TAB_CENTER | TAT_TITLE, _("Extraction")); - - /* Outline the box */ - tab_box (t, - TAL_2, TAL_2, - -1, -1, - 0, 0, - nc - 1, nr - 1); - - /* Vertical lines */ - tab_box (t, - -1, -1, - -1, TAL_1, - heading_columns, 0, - nc - 1, nr - 1); - - tab_hline (t, TAL_1, 0, nc - 1, heading_rows); - tab_vline (t, TAL_2, heading_columns, 0, nr - 1); - - for (i = 0 ; i < factor->n_vars; ++i) + pivot_category_create_leaves (communalities->root, N_("Extraction")); + + struct pivot_dimension *variables = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Variables")); + + for (size_t i = 0 ; i < factor->n_vars; ++i) { - c = 0; - tab_text (t, c++, i + heading_rows, TAT_TITLE, var_to_string (factor->vars[i])); + int row = pivot_category_create_leaf ( + variables->root, pivot_value_new_variable (factor->vars[i])); + int col = 0; if (factor->print & PRINT_INITIAL) - tab_double (t, c++, i + heading_rows, 0, gsl_vector_get (initial, i), NULL, RC_OTHER); - + pivot_table_put2 (table, col++, row, pivot_value_new_number ( + gsl_vector_get (initial, i))); if (factor->print & PRINT_EXTRACTION) - tab_double (t, c++, i + heading_rows, 0, gsl_vector_get (extracted, i), NULL, RC_OTHER); + pivot_table_put2 (table, col++, row, pivot_value_new_number ( + gsl_vector_get (extracted, i))); } - tab_submit (t); + pivot_table_submit (table); } +static struct pivot_dimension * +create_numeric_dimension (struct pivot_table *table, + enum pivot_axis_type axis_type, const char *name, + size_t n, bool show_label) +{ + struct pivot_dimension *d = pivot_dimension_create (table, axis_type, name); + d->root->show_label = show_label; + for (int i = 0 ; i < n; ++i) + pivot_category_create_leaf (d->root, pivot_value_new_integer (i + 1)); + return d; +} static void show_factor_matrix (const struct cmd_factor *factor, const struct idata *idata, const char *title, const gsl_matrix *fm) { - int i; + struct pivot_table *table = pivot_table_create (title); const int n_factors = idata->n_extractions; + create_numeric_dimension ( + table, PIVOT_AXIS_COLUMN, + factor->extraction == EXTRACTION_PC ? N_("Component") : N_("Factor"), + n_factors, true); - const int heading_columns = 1; - const int heading_rows = 2; - const int nr = heading_rows + factor->n_vars; - const int nc = heading_columns + n_factors; - gsl_permutation *perm; - - struct tab_table *t = tab_create (nc, nr); - - /* - if ( factor->extraction == EXTRACTION_PC ) - tab_title (t, _("Component Matrix")); - else - tab_title (t, _("Factor Matrix")); - */ - - tab_title (t, "%s", title); - - tab_headers (t, heading_columns, 0, heading_rows, 0); - - if ( factor->extraction == EXTRACTION_PC ) - tab_joint_text (t, - 1, 0, - nc - 1, 0, - TAB_CENTER | TAT_TITLE, _("Component")); - else - tab_joint_text (t, - 1, 0, - nc - 1, 0, - TAB_CENTER | TAT_TITLE, _("Factor")); - - - tab_hline (t, TAL_1, heading_columns, nc - 1, 1); - - - /* Outline the box */ - tab_box (t, - TAL_2, TAL_2, - -1, -1, - 0, 0, - nc - 1, nr - 1); - - /* Vertical lines */ - tab_box (t, - -1, -1, - -1, TAL_1, - heading_columns, 1, - nc - 1, nr - 1); - - tab_hline (t, TAL_1, 0, nc - 1, heading_rows); - tab_vline (t, TAL_2, heading_columns, 0, nr - 1); - + struct pivot_dimension *variables = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Variables")); /* Initialise to the identity permutation */ - perm = gsl_permutation_calloc (factor->n_vars); + gsl_permutation *perm = gsl_permutation_calloc (factor->n_vars); if ( factor->sort) sort_matrix_indirect (fm, perm); - for (i = 0 ; i < n_factors; ++i) - { - tab_text_format (t, heading_columns + i, 1, TAB_CENTER | TAT_TITLE, _("%d"), i + 1); - } - - for (i = 0 ; i < factor->n_vars; ++i) + for (size_t i = 0 ; i < factor->n_vars; ++i) { - int j; const int matrix_row = perm->data[i]; - tab_text (t, 0, i + heading_rows, TAT_TITLE, var_to_string (factor->vars[matrix_row])); - for (j = 0 ; j < n_factors; ++j) + int var_idx = pivot_category_create_leaf ( + variables->root, pivot_value_new_variable (factor->vars[matrix_row])); + + for (size_t j = 0 ; j < n_factors; ++j) { double x = gsl_matrix_get (fm, matrix_row, j); - if ( fabs (x) < factor->blank) continue; - tab_double (t, heading_columns + j, heading_rows + i, 0, x, NULL, RC_OTHER); + pivot_table_put2 (table, j, var_idx, pivot_value_new_number (x)); } } gsl_permutation_free (perm); - tab_submit (t); + pivot_table_submit (table); } +static void +put_variance (struct pivot_table *table, int row, int phase_idx, + double lambda, double percent, double cum) +{ + double entries[] = { lambda, percent, cum }; + for (size_t i = 0; i < sizeof entries / sizeof *entries; i++) + pivot_table_put3 (table, i, phase_idx, row, + pivot_value_new_number (entries[i])); +} static void show_explained_variance (const struct cmd_factor * factor, @@ -1802,517 +1741,226 @@ show_explained_variance (const struct cmd_factor * factor, const gsl_vector *extracted_eigenvalues, const gsl_vector *rotated_loadings) { - size_t i; - int c = 0; - const int heading_columns = 1; - const int heading_rows = 2; - const int nr = heading_rows + factor->n_vars; - - struct tab_table *t ; - - double i_total = 0.0; - double i_cum = 0.0; - - double e_total = 0.0; - double e_cum = 0.0; - - double r_cum = 0.0; - - int nc = heading_columns; - - if (factor->print & PRINT_EXTRACTION) - nc += 3; - - if (factor->print & PRINT_INITIAL) - nc += 3; - - if (factor->print & PRINT_ROTATION) - { - nc += factor->rotation == ROT_PROMAX ? 1 : 3; - } - - /* No point having a table with only headings */ - if ( nc <= heading_columns) + if (!(factor->print & (PRINT_INITIAL | PRINT_EXTRACTION | PRINT_ROTATION))) return; - t = tab_create (nc, nr); - - tab_title (t, _("Total Variance Explained")); - - tab_headers (t, heading_columns, 0, heading_rows, 0); - - /* Outline the box */ - tab_box (t, - TAL_2, TAL_2, - -1, -1, - 0, 0, - nc - 1, nr - 1); - - /* Vertical lines */ - tab_box (t, - -1, -1, - -1, TAL_1, - heading_columns, 0, - nc - 1, nr - 1); - - tab_hline (t, TAL_1, 0, nc - 1, heading_rows); - tab_hline (t, TAL_1, 1, nc - 1, 1); + struct pivot_table *table = pivot_table_create ( + N_("Total Variance Explained")); + table->omit_empty = true; - tab_vline (t, TAL_2, heading_columns, 0, nr - 1); + /* xgettext:no-c-format */ + pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Statistics"), + N_("Total"), PIVOT_RC_OTHER, + N_("% of Variance"), PIVOT_RC_PERCENT, + N_("Cumulative %"), PIVOT_RC_PERCENT); - - if ( factor->extraction == EXTRACTION_PC) - tab_text (t, 0, 1, TAB_LEFT | TAT_TITLE, _("Component")); - else - tab_text (t, 0, 1, TAB_LEFT | TAT_TITLE, _("Factor")); - - c = 1; + struct pivot_dimension *phase = pivot_dimension_create ( + table, PIVOT_AXIS_COLUMN, N_("Phase")); if (factor->print & PRINT_INITIAL) - { - tab_joint_text (t, c, 0, c + 2, 0, TAB_CENTER | TAT_TITLE, _("Initial Eigenvalues")); - c += 3; - } + pivot_category_create_leaves (phase->root, N_("Initial Eigenvalues")); if (factor->print & PRINT_EXTRACTION) - { - tab_joint_text (t, c, 0, c + 2, 0, TAB_CENTER | TAT_TITLE, _("Extraction Sums of Squared Loadings")); - c += 3; - } + pivot_category_create_leaves (phase->root, + N_("Extraction Sums of Squared Loadings")); if (factor->print & PRINT_ROTATION) - { - const int width = factor->rotation == ROT_PROMAX ? 0 : 2; - tab_joint_text (t, c, 0, c + width, 0, TAB_CENTER | TAT_TITLE, _("Rotation Sums of Squared Loadings")); - c += width + 1; - } - - for (i = 0; i < (nc - heading_columns + 2) / 3 ; ++i) - { - tab_text (t, i * 3 + 1, 1, TAB_CENTER | TAT_TITLE, _("Total")); - - tab_vline (t, TAL_2, heading_columns + i * 3, 0, nr - 1); + pivot_category_create_leaves (phase->root, + N_("Rotation Sums of Squared Loadings")); - if (i == 2 && factor->rotation == ROT_PROMAX) - continue; + struct pivot_dimension *components = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, + factor->extraction == EXTRACTION_PC ? N_("Component") : N_("Factor")); - /* xgettext:no-c-format */ - tab_text (t, i * 3 + 2, 1, TAB_CENTER | TAT_TITLE, _("% of Variance")); - tab_text (t, i * 3 + 3, 1, TAB_CENTER | TAT_TITLE, _("Cumulative %")); - } - - for (i = 0 ; i < initial_eigenvalues->size; ++i) + double i_total = 0.0; + for (size_t i = 0 ; i < initial_eigenvalues->size; ++i) i_total += gsl_vector_get (initial_eigenvalues, i); - if ( factor->extraction == EXTRACTION_PAF) - { - e_total = factor->n_vars; - } - else - { - e_total = i_total; - } + double e_total = (factor->extraction == EXTRACTION_PAF + ? factor->n_vars + : i_total); - for (i = 0 ; i < factor->n_vars; ++i) + double i_cum = 0.0; + double e_cum = 0.0; + double r_cum = 0.0; + for (size_t i = 0 ; i < factor->n_vars; ++i) { const double i_lambda = gsl_vector_get (initial_eigenvalues, i); double i_percent = 100.0 * i_lambda / i_total ; + i_cum += i_percent; const double e_lambda = gsl_vector_get (extracted_eigenvalues, i); double e_percent = 100.0 * e_lambda / e_total ; + e_cum += e_percent; - c = 0; - - tab_text_format (t, c++, i + heading_rows, TAB_LEFT | TAT_TITLE, _("%zu"), i + 1); + int row = pivot_category_create_leaf ( + components->root, pivot_value_new_integer (i + 1)); - i_cum += i_percent; - e_cum += e_percent; + int phase_idx = 0; /* Initial Eigenvalues */ if (factor->print & PRINT_INITIAL) - { - tab_double (t, c++, i + heading_rows, 0, i_lambda, NULL, RC_OTHER); - tab_double (t, c++, i + heading_rows, 0, i_percent, NULL, RC_OTHER); - tab_double (t, c++, i + heading_rows, 0, i_cum, NULL, RC_OTHER); - } - - - if (factor->print & PRINT_EXTRACTION) - { - if (i < idata->n_extractions) - { - /* Sums of squared loadings */ - tab_double (t, c++, i + heading_rows, 0, e_lambda, NULL, RC_OTHER); - tab_double (t, c++, i + heading_rows, 0, e_percent, NULL, RC_OTHER); - tab_double (t, c++, i + heading_rows, 0, e_cum, NULL, RC_OTHER); - } - } + put_variance (table, row, phase_idx++, i_lambda, i_percent, i_cum); - if (rotated_loadings != NULL) + if (i < idata->n_extractions) { - const double r_lambda = gsl_vector_get (rotated_loadings, i); - double r_percent = 100.0 * r_lambda / e_total ; + if (factor->print & PRINT_EXTRACTION) + put_variance (table, row, phase_idx++, e_lambda, e_percent, e_cum); - if (factor->print & PRINT_ROTATION) + if (rotated_loadings != NULL && factor->print & PRINT_ROTATION) { - if (i < idata->n_extractions) - { - r_cum += r_percent; - tab_double (t, c++, i + heading_rows, 0, r_lambda, NULL, RC_OTHER); - if (factor->rotation != ROT_PROMAX) - { - tab_double (t, c++, i + heading_rows, 0, r_percent, NULL, RC_OTHER); - tab_double (t, c++, i + heading_rows, 0, r_cum, NULL, RC_OTHER); - } - } + double r_lambda = gsl_vector_get (rotated_loadings, i); + double r_percent = 100.0 * r_lambda / e_total ; + if (factor->rotation == ROT_PROMAX) + r_lambda = r_percent = SYSMIS; + + r_cum += r_percent; + put_variance (table, row, phase_idx++, r_lambda, r_percent, + r_cum); } } } - tab_submit (t); + pivot_table_submit (table); } - static void show_factor_correlation (const struct cmd_factor * factor, const gsl_matrix *fcm) { - size_t i, j; - const int heading_columns = 1; - const int heading_rows = 1; - const int nr = heading_rows + fcm->size2; - const int nc = heading_columns + fcm->size1; - struct tab_table *t = tab_create (nc, nr); - - tab_title (t, _("Factor Correlation Matrix")); - - tab_headers (t, heading_columns, 0, heading_rows, 0); - - /* Outline the box */ - tab_box (t, - TAL_2, TAL_2, - -1, -1, - 0, 0, - nc - 1, nr - 1); - - /* Vertical lines */ - tab_box (t, - -1, -1, - -1, TAL_1, - heading_columns, 0, - nc - 1, nr - 1); - - tab_hline (t, TAL_1, 0, nc - 1, heading_rows); - tab_hline (t, TAL_1, 1, nc - 1, 1); + struct pivot_table *table = pivot_table_create ( + N_("Factor Correlation Matrix")); - tab_vline (t, TAL_2, heading_columns, 0, nr - 1); + create_numeric_dimension ( + table, PIVOT_AXIS_ROW, + factor->extraction == EXTRACTION_PC ? N_("Component") : N_("Factor"), + fcm->size2, true); + create_numeric_dimension (table, PIVOT_AXIS_COLUMN, N_("Factor 2"), + fcm->size1, false); - if ( factor->extraction == EXTRACTION_PC) - tab_text (t, 0, 0, TAB_LEFT | TAT_TITLE, _("Component")); - else - tab_text (t, 0, 0, TAB_LEFT | TAT_TITLE, _("Factor")); + for (size_t i = 0 ; i < fcm->size1; ++i) + for (size_t j = 0 ; j < fcm->size2; ++j) + pivot_table_put2 (table, j, i, + pivot_value_new_number (gsl_matrix_get (fcm, i, j))); - for (i = 0 ; i < fcm->size1; ++i) - { - tab_text_format (t, heading_columns + i, 0, TAB_CENTER | TAT_TITLE, _("%zu"), i + 1); - } + pivot_table_submit (table); +} - for (i = 0 ; i < fcm->size2; ++i) +static void +add_var_dims (struct pivot_table *table, const struct cmd_factor *factor) +{ + for (int i = 0; i < 2; i++) { - tab_text_format (t, 0, heading_rows + i, TAB_CENTER | TAT_TITLE, _("%zu"), i + 1); - } - + struct pivot_dimension *d = pivot_dimension_create ( + table, i ? PIVOT_AXIS_ROW : PIVOT_AXIS_COLUMN, + N_("Variables")); - for (i = 0 ; i < fcm->size1; ++i) - { - for (j = 0 ; j < fcm->size2; ++j) - tab_double (t, heading_columns + j, heading_rows + i, 0, - gsl_matrix_get (fcm, i, j), NULL, RC_OTHER); + for (size_t j = 0; j < factor->n_vars; j++) + pivot_category_create_leaf ( + d->root, pivot_value_new_variable (factor->vars[j])); } - - tab_submit (t); } static void show_aic (const struct cmd_factor *factor, const struct idata *idata) { - struct tab_table *t ; - size_t i; - - const int heading_rows = 1; - const int heading_columns = 2; - - const int nc = heading_columns + factor->n_vars; - const int nr = heading_rows + 2 * factor->n_vars; - if ((factor->print & PRINT_AIC) == 0) return; - t = tab_create (nc, nr); - - tab_title (t, _("Anti-Image Matrices")); - - tab_hline (t, TAL_1, 0, nc - 1, heading_rows); + struct pivot_table *table = pivot_table_create (N_("Anti-Image Matrices")); - tab_headers (t, heading_columns, 0, heading_rows, 0); + add_var_dims (table, factor); - tab_vline (t, TAL_2, 2, 0, nr - 1); - - /* Outline the box */ - tab_box (t, - TAL_2, TAL_2, - -1, -1, - 0, 0, - nc - 1, nr - 1); - - /* Vertical lines */ - tab_box (t, - -1, -1, - -1, TAL_1, - heading_columns, 0, - nc - 1, nr - 1); - - - for (i = 0; i < factor->n_vars; ++i) - tab_text (t, heading_columns + i, 0, TAT_TITLE, var_to_string (factor->vars[i])); - - tab_text (t, 0, heading_rows, TAT_TITLE, _("Anti-image Covariance")); - tab_hline (t, TAL_1, 0, nc - 1, heading_rows + factor->n_vars); - tab_text (t, 0, heading_rows + factor->n_vars, TAT_TITLE, _("Anti-image Correlation")); - - for (i = 0; i < factor->n_vars; ++i) - { - tab_text (t, 1, i + heading_rows, TAT_TITLE, - var_to_string (factor->vars[i])); - - tab_text (t, 1, factor->n_vars + i + heading_rows, TAT_TITLE, - var_to_string (factor->vars[i])); - } - - for (i = 0; i < factor->n_vars; ++i) - { - int j; - for (j = 0; j < factor->n_vars; ++j) - { - tab_double (t, heading_columns + i, heading_rows + j, 0, - gsl_matrix_get (idata->ai_cov, i, j), NULL, RC_OTHER); - } + pivot_dimension_create (table, PIVOT_AXIS_ROW, N_("Statistics"), + N_("Anti-image Covariance"), + N_("Anti-image Correlation")); + for (size_t i = 0; i < factor->n_vars; ++i) + for (size_t j = 0; j < factor->n_vars; ++j) + { + double cov = gsl_matrix_get (idata->ai_cov, i, j); + pivot_table_put3 (table, i, j, 0, pivot_value_new_number (cov)); - for (j = 0; j < factor->n_vars; ++j) - { - tab_double (t, heading_columns + i, factor->n_vars + heading_rows + j, 0, - gsl_matrix_get (idata->ai_cor, i, j), NULL, RC_OTHER); - } - } + double corr = gsl_matrix_get (idata->ai_cor, i, j); + pivot_table_put3 (table, i, j, 1, pivot_value_new_number (corr)); + } - tab_submit (t); + pivot_table_submit (table); } static void show_correlation_matrix (const struct cmd_factor *factor, const struct idata *idata) { - struct tab_table *t ; - size_t i, j; - int y_pos_corr = -1; - int y_pos_sig = -1; - int suffix_rows = 0; - - const int heading_rows = 1; - const int heading_columns = 2; - - int nc = heading_columns ; - int nr = heading_rows ; - int n_data_sets = 0; - - if (factor->print & PRINT_CORRELATION) - { - y_pos_corr = n_data_sets; - n_data_sets++; - nc = heading_columns + factor->n_vars; - } - - if (factor->print & PRINT_SIG) - { - y_pos_sig = n_data_sets; - n_data_sets++; - nc = heading_columns + factor->n_vars; - } - - nr += n_data_sets * factor->n_vars; - - if (factor->print & PRINT_DETERMINANT) - suffix_rows = 1; - - /* If the table would contain only headings, don't bother rendering it */ - if (nr <= heading_rows && suffix_rows == 0) + if (!(factor->print & (PRINT_CORRELATION | PRINT_SIG | PRINT_DETERMINANT))) return; - t = tab_create (nc, nr + suffix_rows); - - tab_title (t, _("Correlation Matrix")); + struct pivot_table *table = pivot_table_create (N_("Correlation Matrix")); - tab_hline (t, TAL_1, 0, nc - 1, heading_rows); - - if (nr > heading_rows) + if (factor->print & (PRINT_CORRELATION | PRINT_SIG)) { - tab_headers (t, heading_columns, 0, heading_rows, 0); - - tab_vline (t, TAL_2, 2, 0, nr - 1); - - /* Outline the box */ - tab_box (t, - TAL_2, TAL_2, - -1, -1, - 0, 0, - nc - 1, nr - 1); - - /* Vertical lines */ - tab_box (t, - -1, -1, - -1, TAL_1, - heading_columns, 0, - nc - 1, nr - 1); - - - for (i = 0; i < factor->n_vars; ++i) - tab_text (t, heading_columns + i, 0, TAT_TITLE, var_to_string (factor->vars[i])); - - - for (i = 0 ; i < n_data_sets; ++i) - { - int y = heading_rows + i * factor->n_vars; - size_t v; - for (v = 0; v < factor->n_vars; ++v) - tab_text (t, 1, y + v, TAT_TITLE, var_to_string (factor->vars[v])); - - tab_hline (t, TAL_1, 0, nc - 1, y); - } + add_var_dims (table, factor); + struct pivot_dimension *statistics = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Statistics")); if (factor->print & PRINT_CORRELATION) - { - const double y = heading_rows + y_pos_corr; - tab_text (t, 0, y, TAT_TITLE, _("Correlations")); - - for (i = 0; i < factor->n_vars; ++i) - { - for (j = 0; j < factor->n_vars; ++j) - tab_double (t, heading_columns + j, y + i, 0, gsl_matrix_get (idata->mm.corr, i, j), NULL, RC_OTHER); - } - } - + pivot_category_create_leaves (statistics->root, N_("Correlation"), + PIVOT_RC_CORRELATION); if (factor->print & PRINT_SIG) - { - const double y = heading_rows + y_pos_sig * factor->n_vars; - tab_text (t, 0, y, TAT_TITLE, _("Sig. (1-tailed)")); - - for (i = 0; i < factor->n_vars; ++i) - { - for (j = 0; j < factor->n_vars; ++j) - { - double rho = gsl_matrix_get (idata->mm.corr, i, j); - double w = gsl_matrix_get (idata->mm.n, i, j); + pivot_category_create_leaves (statistics->root, N_("Sig. (1-tailed)"), + PIVOT_RC_SIGNIFICANCE); - if (i == j) - continue; + int stat_idx = 0; + if (factor->print & PRINT_CORRELATION) + { + for (int i = 0; i < factor->n_vars; ++i) + for (int j = 0; j < factor->n_vars; ++j) + { + double corr = gsl_matrix_get (idata->mm.corr, i, j); + pivot_table_put3 (table, j, i, stat_idx, + pivot_value_new_number (corr)); + } + stat_idx++; + } - tab_double (t, heading_columns + j, y + i, 0, significance_of_correlation (rho, w), NULL, RC_PVALUE); - } - } - } + if (factor->print & PRINT_SIG) + { + for (int i = 0; i < factor->n_vars; ++i) + for (int j = 0; j < factor->n_vars; ++j) + if (i != j) + { + double rho = gsl_matrix_get (idata->mm.corr, i, j); + double w = gsl_matrix_get (idata->mm.n, i, j); + double sig = significance_of_correlation (rho, w); + pivot_table_put3 (table, j, i, stat_idx, + pivot_value_new_number (sig)); + } + stat_idx++; + } } if (factor->print & PRINT_DETERMINANT) - { - tab_text (t, 0, nr, TAB_LEFT | TAT_TITLE, _("Determinant")); - - tab_double (t, 1, nr, 0, idata->detR, NULL, RC_OTHER); - } + table->caption = pivot_value_new_user_text_nocopy ( + xasprintf ("%s: %.2f", _("Determinant"), idata->detR)); - tab_submit (t); + pivot_table_submit (table); } static void show_covariance_matrix (const struct cmd_factor *factor, const struct idata *idata) { - struct tab_table *t ; - size_t i, j; - int y_pos_corr = -1; - int suffix_rows = 0; - - const int heading_rows = 1; - const int heading_columns = 1; - - int nc = heading_columns ; - int nr = heading_rows ; - int n_data_sets = 0; - - if (factor->print & PRINT_COVARIANCE) - { - y_pos_corr = n_data_sets; - n_data_sets++; - nc = heading_columns + factor->n_vars; - } - - nr += n_data_sets * factor->n_vars; - - /* If the table would contain only headings, don't bother rendering it */ - if (nr <= heading_rows && suffix_rows == 0) + if (!(factor->print & PRINT_COVARIANCE)) return; - t = tab_create (nc, nr + suffix_rows); - - tab_title (t, _("Covariance Matrix")); - - tab_hline (t, TAL_1, 0, nc - 1, heading_rows); - - if (nr > heading_rows) - { - tab_headers (t, heading_columns, 0, heading_rows, 0); - - tab_vline (t, TAL_2, heading_columns, 0, nr - 1); + struct pivot_table *table = pivot_table_create (N_("Covariance Matrix")); + add_var_dims (table, factor); - /* Outline the box */ - tab_box (t, - TAL_2, TAL_2, - -1, -1, - 0, 0, - nc - 1, nr - 1); - - /* Vertical lines */ - tab_box (t, - -1, -1, - -1, TAL_1, - heading_columns, 0, - nc - 1, nr - 1); - - - for (i = 0; i < factor->n_vars; ++i) - tab_text (t, heading_columns + i, 0, TAT_TITLE, var_to_string (factor->vars[i])); - - - for (i = 0 ; i < n_data_sets; ++i) - { - int y = heading_rows + i * factor->n_vars; - size_t v; - for (v = 0; v < factor->n_vars; ++v) - tab_text (t, heading_columns -1, y + v, TAT_TITLE, var_to_string (factor->vars[v])); - - tab_hline (t, TAL_1, 0, nc - 1, y); - } - - if (factor->print & PRINT_COVARIANCE) - { - const double y = heading_rows + y_pos_corr; - - for (i = 0; i < factor->n_vars; ++i) - { - for (j = 0; j < factor->n_vars; ++j) - tab_double (t, heading_columns + j, y + i, 0, gsl_matrix_get (idata->mm.cov, i, j), NULL, RC_OTHER); - } - } - } + for (int i = 0; i < factor->n_vars; ++i) + for (int j = 0; j < factor->n_vars; ++j) + { + double cov = gsl_matrix_get (idata->mm.cov, i, j); + pivot_table_put2 (table, j, i, pivot_value_new_number (cov)); + } - tab_submit (t); + pivot_table_submit (table); } @@ -2408,116 +2056,73 @@ do_factor_by_matrix (const struct cmd_factor *factor, struct idata *idata) if ( factor->print & PRINT_UNIVARIATE) { - const struct fmt_spec *wfmt = factor->wv ? var_get_print_format (factor->wv) : & F_8_0; - const int nc = 4; - int i; - - const int heading_columns = 1; - const int heading_rows = 1; - - const int nr = heading_rows + factor->n_vars; - - struct tab_table *t = tab_create (nc, nr); - tab_set_format (t, RC_WEIGHT, wfmt); - tab_title (t, _("Descriptive Statistics")); + struct pivot_table *table = pivot_table_create ( + N_("Descriptive Statistics")); + pivot_table_set_weight_var (table, factor->wv); - tab_headers (t, heading_columns, 0, heading_rows, 0); + pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Statistics"), + N_("Mean"), PIVOT_RC_OTHER, + N_("Std. Deviation"), PIVOT_RC_OTHER, + N_("Analysis N"), PIVOT_RC_COUNT); - /* Outline the box */ - tab_box (t, - TAL_2, TAL_2, - -1, -1, - 0, 0, - nc - 1, nr - 1); - - /* Vertical lines */ - tab_box (t, - -1, -1, - -1, TAL_1, - heading_columns, 0, - nc - 1, nr - 1); - - tab_hline (t, TAL_1, 0, nc - 1, heading_rows); - tab_vline (t, TAL_2, heading_columns, 0, nr - 1); - - tab_text (t, 1, 0, TAB_CENTER | TAT_TITLE, _("Mean")); - tab_text (t, 2, 0, TAB_CENTER | TAT_TITLE, _("Std. Deviation")); - tab_text (t, 3, 0, TAB_CENTER | TAT_TITLE, _("Analysis N")); + struct pivot_dimension *variables = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Variables")); for (i = 0 ; i < factor->n_vars; ++i) { const struct variable *v = factor->vars[i]; - tab_text (t, 0, i + heading_rows, TAB_LEFT | TAT_TITLE, var_to_string (v)); - tab_double (t, 1, i + heading_rows, 0, gsl_matrix_get (idata->mm.mean_matrix, i, i), NULL, RC_OTHER); - tab_double (t, 2, i + heading_rows, 0, sqrt (gsl_matrix_get (idata->mm.var_matrix, i, i)), NULL, RC_OTHER); - tab_double (t, 3, i + heading_rows, 0, gsl_matrix_get (idata->mm.n, i, i), NULL, RC_WEIGHT); + int row = pivot_category_create_leaf ( + variables->root, pivot_value_new_variable (v)); + + double entries[] = { + gsl_matrix_get (idata->mm.mean_matrix, i, i), + sqrt (gsl_matrix_get (idata->mm.var_matrix, i, i)), + gsl_matrix_get (idata->mm.n, i, i), + }; + for (size_t j = 0; j < sizeof entries / sizeof *entries; j++) + pivot_table_put2 (table, j, row, + pivot_value_new_number (entries[j])); } - tab_submit (t); + pivot_table_submit (table); } if (factor->print & PRINT_KMO) { - int i; - double df = factor->n_vars * (factor->n_vars - 1) / 2; - - double w = 0; - - - double xsq; - - const int heading_columns = 2; - const int heading_rows = 0; - - const int nr = heading_rows + 4; - const int nc = heading_columns + 1; - - - - struct tab_table *t = tab_create (nc, nr); - tab_title (t, _("KMO and Bartlett's Test")); - - - tab_headers (t, heading_columns, 0, heading_rows, 0); - - /* Outline the box */ - tab_box (t, - TAL_2, TAL_2, - -1, -1, - 0, 0, - nc - 1, nr - 1); - - tab_vline (t, TAL_2, heading_columns, 0, nr - 1); - - tab_text (t, 0, 0, TAT_TITLE | TAB_LEFT, _("Kaiser-Meyer-Olkin Measure of Sampling Adequacy")); - - tab_double (t, 2, 0, 0, sum_ssq_r / (sum_ssq_r + sum_ssq_a), NULL, RC_OTHER); - - tab_text (t, 0, 1, TAT_TITLE | TAB_LEFT, _("Bartlett's Test of Sphericity")); - - tab_text (t, 1, 1, TAT_TITLE, _("Approx. Chi-Square")); - tab_text (t, 1, 2, TAT_TITLE, _("df")); - tab_text (t, 1, 3, TAT_TITLE, _("Sig.")); - + struct pivot_table *table = pivot_table_create ( + N_("KMO and Bartlett's Test")); + + struct pivot_dimension *statistics = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Statistics"), + N_("Kaiser-Meyer-Olkin Measure of Sampling Adequacy"), PIVOT_RC_OTHER); + pivot_category_create_group ( + statistics->root, N_("Bartlett's Test of Sphericity"), + N_("Approx. Chi-Square"), PIVOT_RC_OTHER, + N_("df"), PIVOT_RC_INTEGER, + N_("Sig."), PIVOT_RC_SIGNIFICANCE); /* The literature doesn't say what to do for the value of W when missing values are involved. The best thing I can think of is to take the mean average. */ - w = 0; + double w = 0; for (i = 0; i < idata->mm.n->size1; ++i) w += gsl_matrix_get (idata->mm.n, i, i); w /= idata->mm.n->size1; - xsq = w - 1 - (2 * factor->n_vars + 5) / 6.0; - xsq *= -log (idata->detR); - - tab_double (t, 2, 1, 0, xsq, NULL, RC_OTHER); - tab_double (t, 2, 2, 0, df, NULL, RC_INTEGER); - tab_double (t, 2, 3, 0, gsl_cdf_chisq_Q (xsq, df), NULL, RC_PVALUE); - - - tab_submit (t); + double xsq = ((w - 1 - (2 * factor->n_vars + 5) / 6.0) + * -log (idata->detR)); + double df = factor->n_vars * (factor->n_vars - 1) / 2; + double entries[] = { + sum_ssq_r / (sum_ssq_r + sum_ssq_a), + xsq, + df, + gsl_cdf_chisq_Q (xsq, df) + }; + for (size_t i = 0; i < sizeof entries / sizeof *entries; i++) + pivot_table_put1 (table, i, pivot_value_new_number (entries[i])); + + pivot_table_submit (table); } show_correlation_matrix (factor, idata); @@ -2640,21 +2245,25 @@ do_factor_by_matrix (const struct cmd_factor *factor, struct idata *idata) show_scree (factor, idata); show_factor_matrix (factor, idata, - factor->extraction == EXTRACTION_PC ? _("Component Matrix") : _("Factor Matrix"), + (factor->extraction == EXTRACTION_PC + ? N_("Component Matrix") : N_("Factor Matrix")), factor_matrix); if ( factor->rotation == ROT_PROMAX) { - show_factor_matrix (factor, idata, _("Pattern Matrix"), pattern_matrix); + show_factor_matrix (factor, idata, N_("Pattern Matrix"), + pattern_matrix); gsl_matrix_free (pattern_matrix); } if ( factor->rotation != ROT_NONE) { show_factor_matrix (factor, idata, - (factor->rotation == ROT_PROMAX) ? _("Structure Matrix") : - (factor->extraction == EXTRACTION_PC ? _("Rotated Component Matrix") : - _("Rotated Factor Matrix")), + (factor->rotation == ROT_PROMAX + ? N_("Structure Matrix") + : factor->extraction == EXTRACTION_PC + ? N_("Rotated Component Matrix") + : N_("Rotated Factor Matrix")), rotated_factors); gsl_matrix_free (rotated_factors); diff --git a/src/language/stats/frequencies.c b/src/language/stats/frequencies.c index ff29b6600a..8bd6c60020 100644 --- a/src/language/stats/frequencies.c +++ b/src/language/stats/frequencies.c @@ -56,7 +56,7 @@ #include "output/charts/barchart.h" #include "output/charts/piechart.h" #include "output/charts/plot-hist.h" -#include "output/tab.h" +#include "output/pivot-table.h" #include "gl/minmax.h" #include "gl/xalloc.h" @@ -211,7 +211,8 @@ struct frq_proc /* Percentiles to calculate and possibly display. */ struct percentile *percentiles; - int n_percentiles, n_show_percentiles; + const struct percentile *median; + int n_percentiles; /* Frequency table display. */ long int max_categories; /* Maximum categories to show. */ @@ -236,7 +237,8 @@ struct freq_compare_aux bool ascending_value; }; -static void calc_stats (const struct var_freqs *vf, double d[FRQ_ST_count]); +static void calc_stats (const struct frq_proc *, + const struct var_freqs *, double d[FRQ_ST_count]); static void do_piechart(const struct frq_chart *pie, const struct variable *var, @@ -247,7 +249,6 @@ static void do_barchart(const struct frq_chart *bar, const struct freq_tab *frq_tab); static void dump_statistics (const struct frq_proc *frq, - const struct var_freqs *vf, const struct variable *wv); static int @@ -274,89 +275,74 @@ static struct histogram * freq_tab_to_hist (const struct frq_proc *frq, const struct freq_tab *ft, const struct variable *var); +static void +put_freq_row (struct pivot_table *table, int var_idx, + double frequency, double percent, + double valid_percent, double cum_percent) +{ + double entries[] = { frequency, percent, valid_percent, cum_percent }; + for (size_t i = 0; i < sizeof entries / sizeof *entries; i++) + if (entries[i] != SYSMIS) + pivot_table_put2 (table, i, var_idx, + pivot_value_new_number (entries[i])); +} /* Displays a full frequency table for variable V. */ static void dump_freq_table (const struct var_freqs *vf, const struct variable *wv) { - const struct fmt_spec *wfmt = wv ? var_get_print_format (wv) : &F_8_0; const struct freq_tab *ft = &vf->tab; - int n_categories; - struct freq *f; - struct tab_table *t; - int r, x; - double cum_total = 0.0; - double cum_freq = 0.0; - static const char *headings[] = { - N_("Value Label"), - N_("Value"), - N_("Frequency"), - N_("Percent"), - N_("Valid Percent"), - N_("Cum Percent") - }; + struct pivot_table *table = pivot_table_create__ (pivot_value_new_variable ( + vf->var)); + pivot_table_set_weight_var (table, wv); - n_categories = ft->n_valid + ft->n_missing; - t = tab_create (6, n_categories + 2); - tab_set_format (t, RC_WEIGHT, wfmt); - tab_headers (t, 0, 0, 1, 0); + pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Statistics"), + N_("Frequency"), PIVOT_RC_COUNT, + N_("Percent"), PIVOT_RC_PERCENT, + N_("Valid Percent"), PIVOT_RC_PERCENT, + N_("Cumulative Percent"), PIVOT_RC_PERCENT); - for (x = 0; x < 6; x++) - tab_text (t, x, 0, TAB_CENTER | TAT_TITLE, gettext (headings[x])); + struct pivot_dimension *variable = pivot_dimension_create__ ( + table, PIVOT_AXIS_ROW, pivot_value_new_variable (vf->var)); - r = 1; - for (f = ft->valid; f < ft->missing; f++) + double cum_freq = 0.0; + double cum_percent = 0.0; + struct pivot_category *valid = NULL; + for (const struct freq *f = ft->valid; f < ft->missing; f++) { - const char *label; - double percent, valid_percent; - cum_freq += f->count; - - percent = f->count / ft->total_cases * 100.0; - valid_percent = f->count / ft->valid_cases * 100.0; - cum_total += valid_percent; - - label = var_lookup_value_label (vf->var, f->values); - if (label != NULL) - tab_text (t, 0, r, TAB_LEFT, label); - - tab_value (t, 1, r, TAB_NONE, f->values, vf->var, NULL); - tab_double (t, 2, r, TAB_NONE, f->count, NULL, RC_WEIGHT); - tab_double (t, 3, r, TAB_NONE, percent, NULL, RC_OTHER); - tab_double (t, 4, r, TAB_NONE, valid_percent, NULL, RC_OTHER); - tab_double (t, 5, r, TAB_NONE, cum_total, NULL, RC_OTHER); - r++; + double valid_percent = f->count / ft->valid_cases * 100.0; + cum_percent += valid_percent; + + if (!valid) + valid = pivot_category_create_group (variable->root, N_("Valid")); + int var_idx = pivot_category_create_leaf ( + valid, pivot_value_new_var_value (vf->var, &f->values[0])); + put_freq_row (table, var_idx, f->count, + f->count / ft->total_cases * 100.0, + valid_percent, cum_percent); } - for (; f < &ft->valid[n_categories]; f++) - { - const char *label; + struct pivot_category *missing = NULL; + size_t n_categories = ft->n_valid + ft->n_missing; + for (const struct freq *f = ft->missing; f < &ft->valid[n_categories]; f++) + { cum_freq += f->count; - label = var_lookup_value_label (vf->var, f->values); - if (label != NULL) - tab_text (t, 0, r, TAB_LEFT, label); - - tab_value (t, 1, r, TAB_NONE, f->values, vf->var, NULL); - tab_double (t, 2, r, TAB_NONE, f->count, NULL, RC_WEIGHT); - tab_double (t, 3, r, TAB_NONE, - f->count / ft->total_cases * 100.0, NULL, RC_OTHER); - tab_text (t, 4, r, TAB_NONE, _("Missing")); - r++; + if (!missing) + missing = pivot_category_create_group (variable->root, N_("Missing")); + int var_idx = pivot_category_create_leaf ( + missing, pivot_value_new_var_value (vf->var, &f->values[0])); + put_freq_row (table, var_idx, f->count, + f->count / ft->total_cases * 100.0, SYSMIS, SYSMIS); } - tab_box (t, TAL_1, TAL_1, -1, TAL_1, 0, 0, 5, r); - tab_hline (t, TAL_2, 0, 5, 1); - tab_hline (t, TAL_2, 0, 5, r); - tab_joint_text (t, 0, r, 1, r, TAB_RIGHT | TAT_TITLE, _("Total")); - tab_vline (t, TAL_0, 1, r, r); - tab_double (t, 2, r, TAB_NONE, cum_freq, NULL, RC_WEIGHT); - tab_double (t, 3, r, TAB_NONE, 100.0, &F_5_1, RC_OTHER); - tab_double (t, 4, r, TAB_NONE, 100.0, &F_5_1, RC_OTHER); - - tab_title (t, "%s", var_to_string (vf->var)); - tab_submit (t); + int var_idx = pivot_category_create_leaf ( + variable->root, pivot_value_new_text (N_("Total"))); + put_freq_row (table, var_idx, cum_freq, cum_percent, SYSMIS, SYSMIS); + + pivot_table_submit (table); } /* Statistical display. */ @@ -532,25 +518,28 @@ postcalc (struct frq_proc *frq, const struct dataset *ds) for (i = 0; i < frq->n_vars; i++) { struct var_freqs *vf = &frq->vars[i]; - postprocess_freq_tab (frq, vf); + calc_percentiles (frq, vf); + } + + if (frq->n_stats) + dump_statistics (frq, wv); + + for (i = 0; i < frq->n_vars; i++) + { + struct var_freqs *vf = &frq->vars[i]; /* Frequencies tables. */ if (vf->tab.n_valid + vf->tab.n_missing <= frq->max_categories) dump_freq_table (vf, wv); - calc_percentiles (frq, vf); - - /* Statistics. */ - if (frq->n_stats) - dump_statistics (frq, vf, wv); if (frq->hist && var_is_numeric (vf->var) && vf->tab.n_valid > 0) { double d[FRQ_ST_count]; struct histogram *histogram; - calc_stats (vf, d); + calc_stats (frq, vf, d); histogram = freq_tab_to_hist (frq, &vf->tab, vf->var); @@ -620,7 +609,6 @@ cmd_frequencies (struct lexer *lexer, struct dataset *ds) frq.percentiles = NULL; frq.n_percentiles = 0; - frq.n_show_percentiles = 0; frq.hist = NULL; frq.pie = NULL; @@ -782,7 +770,6 @@ cmd_frequencies (struct lexer *lexer, struct dataset *ds) frq.percentiles[frq.n_percentiles].show = true; lex_get (lexer); frq.n_percentiles++; - frq.n_show_percentiles++; } else { @@ -860,7 +847,6 @@ cmd_frequencies (struct lexer *lexer, struct dataset *ds) frq.percentiles[frq.n_percentiles].show = true; frq.n_percentiles++; - frq.n_show_percentiles++; } } else @@ -1123,10 +1109,9 @@ cmd_frequencies (struct lexer *lexer, struct dataset *ds) * sizeof (*frq.percentiles)); frq.percentiles[frq.n_percentiles].p = 0.50; - frq.percentiles[frq.n_percentiles].show = true; + frq.percentiles[frq.n_percentiles].show = false; frq.n_percentiles++; - frq.n_show_percentiles++; } @@ -1212,27 +1197,31 @@ cmd_frequencies (struct lexer *lexer, struct dataset *ds) sizeof (*frq.percentiles), ptile_3way); - frq.n_show_percentiles = 0; for (i = o = 0; i < frq.n_percentiles; ++i) { if (frq.percentiles[i].p != previous_p) { frq.percentiles[o].p = frq.percentiles[i].p; frq.percentiles[o].show = frq.percentiles[i].show; - if (frq.percentiles[i].show) - frq.n_show_percentiles++; o++; } else if (frq.percentiles[i].show && !frq.percentiles[o].show) { frq.percentiles[o].show = true; - frq.n_show_percentiles++; } previous_p = frq.percentiles[i].p; } frq.n_percentiles = o; + + frq.median = NULL; + for (i = 0; i < frq.n_percentiles; i++) + if (frq.percentiles[i].p == 0.5) + { + frq.median = &frq.percentiles[i]; + break; + } } { @@ -1509,7 +1498,8 @@ do_barchart(const struct frq_chart *bar, const struct variable **var, /* Calculates all the pertinent statistics for VF, putting them in array D[]. */ static void -calc_stats (const struct var_freqs *vf, double d[FRQ_ST_count]) +calc_stats (const struct frq_proc *frq, const struct var_freqs *vf, + double d[FRQ_ST_count]) { const struct freq_tab *ft = &vf->tab; double W = ft->valid_cases; @@ -1563,88 +1553,102 @@ calc_stats (const struct var_freqs *vf, double d[FRQ_ST_count]) d[FRQ_ST_SEMEAN] = d[FRQ_ST_STDDEV] / sqrt (W); d[FRQ_ST_SESKEWNESS] = calc_seskew (W); d[FRQ_ST_SEKURTOSIS] = calc_sekurt (W); + d[FRQ_ST_MEDIAN] = frq->median ? frq->median->value : SYSMIS; } -/* Displays a table of all the statistics requested for variable V. */ -static void -dump_statistics (const struct frq_proc *frq, const struct var_freqs *vf, - const struct variable *wv) +static bool +all_string_variables (const struct frq_proc *frq) { - const struct fmt_spec *wfmt = wv ? var_get_print_format (wv) : &F_8_0; - const struct freq_tab *ft = &vf->tab; - double stat_value[FRQ_ST_count]; - struct tab_table *t; - int i, r = 2; /* N missing and N valid are always dumped */ - - if (var_is_alpha (vf->var)) - return; + for (size_t i = 0; i < frq->n_vars; i++) + if (var_is_numeric (frq->vars[i].var)) + return false; - calc_stats (vf, stat_value); - - t = tab_create (3, ((frq->stats & BIT_INDEX (FRQ_ST_MEDIAN)) ? frq->n_stats - 1 : frq->n_stats) - + frq->n_show_percentiles + 2); - - tab_set_format (t, RC_WEIGHT, wfmt); - tab_box (t, TAL_1, TAL_1, -1, -1 , 0 , 0 , 2, tab_nr(t) - 1) ; + return true; +} - tab_vline (t, TAL_1 , 2, 0, tab_nr(t) - 1); +/* Displays a table of all the statistics requested. */ +static void +dump_statistics (const struct frq_proc *frq, const struct variable *wv) +{ + if (all_string_variables (frq)) + return; - for (i = 0; i < FRQ_ST_count; i++) + struct pivot_table *table = pivot_table_create (N_("Statistics")); + pivot_table_set_weight_var (table, wv); + + struct pivot_dimension *variables + = pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Variables")); + + struct pivot_dimension *statistics = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Statistics")); + struct pivot_category *n = pivot_category_create_group ( + statistics->root, N_("N")); + pivot_category_create_leaves (n, + N_("Valid"), PIVOT_RC_COUNT, + N_("Missing"), PIVOT_RC_COUNT); + for (int i = 0; i < FRQ_ST_count; i++) + if (frq->stats & BIT_INDEX (i)) + pivot_category_create_leaf (statistics->root, + pivot_value_new_text (st_name[i])); + struct pivot_category *percentiles = NULL; + for (size_t i = 0; i < frq->n_percentiles; i++) { - if (FRQ_ST_MEDIAN == i) - continue; - - if (frq->stats & BIT_INDEX (i)) - { - tab_text (t, 0, r, TAB_LEFT | TAT_TITLE, - gettext (st_name[i])); - - if (vf->tab.n_valid <= 0 && r >= 2) - tab_text (t, 2, r, 0, "."); - else - tab_double (t, 2, r, TAB_NONE, stat_value[i], NULL, RC_OTHER); - r++; - } - } + const struct percentile *pc = &frq->percentiles[i]; - tab_text (t, 0, 0, TAB_LEFT | TAT_TITLE, _("N")); - tab_text (t, 1, 0, TAB_LEFT | TAT_TITLE, _("Valid")); - tab_text (t, 1, 1, TAB_LEFT | TAT_TITLE, _("Missing")); + if (!pc->show) + continue; - tab_double (t, 2, 0, TAB_NONE, ft->valid_cases, NULL, RC_WEIGHT); - tab_double (t, 2, 1, TAB_NONE, ft->total_cases - ft->valid_cases, NULL, RC_WEIGHT); + if (!percentiles) + percentiles = pivot_category_create_group ( + statistics->root, N_("Percentiles")); + pivot_category_create_leaf (percentiles, pivot_value_new_integer ( + pc->p * 100.0)); + } - for (i = 0; i < frq->n_percentiles; i++) + for (size_t i = 0; i < frq->n_vars; i++) { - const struct percentile *pc = &frq->percentiles[i]; - - if (!pc->show) + struct var_freqs *vf = &frq->vars[i]; + if (var_is_alpha (vf->var)) continue; - if ( i == 0 ) - { - tab_text (t, 0, r, TAB_LEFT | TAT_TITLE, _("Percentiles")); - } + const struct freq_tab *ft = &vf->tab; - if (vf->tab.n_valid <= 0) - { - tab_text (t, 2, r, 0, "."); - ++r; - continue; - } + int var_idx = pivot_category_create_leaf ( + variables->root, pivot_value_new_variable (vf->var)); - if (pc->p == 0.5) - tab_text (t, 1, r, TAB_LEFT, _("50 (Median)")); - else - tab_double (t, 1, r, TAB_LEFT, pc->p * 100, NULL, RC_INTEGER); - tab_double (t, 2, r, TAB_NONE, pc->value, - var_get_print_format (vf->var), RC_OTHER); + int row = 0; + pivot_table_put2 (table, var_idx, row++, + pivot_value_new_number (ft->valid_cases)); + pivot_table_put2 (table, var_idx, row++, + pivot_value_new_number ( + ft->total_cases - ft->valid_cases)); - ++r; - } + double stat_values[FRQ_ST_count]; + calc_stats (frq, vf, stat_values); + for (int j = 0; j < FRQ_ST_count; j++) + { + if (!(frq->stats & BIT_INDEX (j))) + continue; + + union value v = { .f = vf->tab.n_valid ? stat_values[j] : SYSMIS }; + struct pivot_value *pv + = (j == FRQ_ST_MODE || j == FRQ_ST_MINIMUM || j == FRQ_ST_MAXIMUM + ? pivot_value_new_var_value (vf->var, &v) + : pivot_value_new_number (v.f)); + pivot_table_put2 (table, var_idx, row++, pv); + } + + for (size_t j = 0; j < frq->n_percentiles; j++) + { + const struct percentile *pc = &frq->percentiles[j]; + if (!pc->show) + continue; - tab_title (t, "%s", var_to_string (vf->var)); + union value v = { .f = vf->tab.n_valid ? pc->value : SYSMIS }; + pivot_table_put2 (table, var_idx, row++, + pivot_value_new_var_value (vf->var, &v)); + } + } - tab_submit (t); + pivot_table_submit (table); } - diff --git a/src/language/stats/friedman.c b/src/language/stats/friedman.c index cf03c83c12..9ea3cbc516 100644 --- a/src/language/stats/friedman.c +++ b/src/language/stats/friedman.c @@ -29,9 +29,10 @@ #include "data/variable.h" #include "libpspp/message.h" #include "libpspp/misc.h" -#include "output/tab.h" +#include "output/pivot-table.h" #include "gettext.h" +#define N_(msgid) msgid #define _(msgid) gettext (msgid) @@ -216,40 +217,24 @@ friedman_execute (const struct dataset *ds, static void show_ranks_box (const struct one_sample_test *ost, const struct friedman *fr) { - int i; - const int row_headers = 1; - const int column_headers = 1; - struct tab_table *table = - tab_create (row_headers + 1, column_headers + ost->n_vars); + struct pivot_table *table = pivot_table_create (N_("Ranks")); - tab_headers (table, row_headers, 0, column_headers, 0); + pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Mean Rank"), + N_("Mean Rank"), PIVOT_RC_OTHER); - tab_title (table, _("Ranks")); + struct pivot_dimension *variables = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Variable")); - /* Vertical lines inside the box */ - tab_box (table, 1, 0, -1, TAL_1, - row_headers, 0, tab_nc (table) - 1, tab_nr (table) - 1 ); - - /* Box around the table */ - tab_box (table, TAL_2, TAL_2, -1, -1, - 0, 0, tab_nc (table) - 1, tab_nr (table) - 1 ); - - - tab_text (table, 1, 0, 0, _("Mean Rank")); - - tab_hline (table, TAL_2, 0, tab_nc (table) - 1, column_headers); - tab_vline (table, TAL_2, row_headers, 0, tab_nr (table) - 1); - - for (i = 0 ; i < ost->n_vars ; ++i) + for (size_t i = 0 ; i < ost->n_vars ; ++i) { - tab_text (table, 0, row_headers + i, - TAB_LEFT, var_to_string (ost->vars[i])); + int row = pivot_category_create_leaf ( + variables->root, pivot_value_new_variable (ost->vars[i])); - tab_double (table, 1, row_headers + i, - 0, fr->rank_sum[i] / fr->cc, NULL, RC_OTHER); + pivot_table_put2 (table, 0, row, + pivot_value_new_number (fr->rank_sum[i] / fr->cc)); } - tab_submit (table); + pivot_table_submit (table); } @@ -258,60 +243,33 @@ show_sig_box (const struct one_sample_test *ost, const struct friedman *fr) { const struct friedman_test *ft = UP_CAST (ost, const struct friedman_test, parent); - int row = 0; - const struct fmt_spec *wfmt = dict_get_weight_format (fr->dict); - - const int row_headers = 1; - const int column_headers = 0; - struct tab_table *table = - tab_create (row_headers + 1, column_headers + (ft->kendalls_w ? 5 : 4)); - tab_set_format (table, RC_WEIGHT, wfmt); - - tab_headers (table, row_headers, 0, column_headers, 0); - - tab_title (table, _("Test Statistics")); - - tab_text (table, 0, column_headers + row++, - TAT_TITLE | TAB_LEFT , _("N")); - - if ( ft->kendalls_w) - tab_text (table, 0, column_headers + row++, - TAT_TITLE | TAB_LEFT , _("Kendall's W")); - - tab_text (table, 0, column_headers + row++, - TAT_TITLE | TAB_LEFT , _("Chi-Square")); - - tab_text (table, 0, column_headers + row++, - TAT_TITLE | TAB_LEFT, _("df")); - - tab_text (table, 0, column_headers + row++, - TAT_TITLE | TAB_LEFT, _("Asymp. Sig.")); - - /* Box around the table */ - tab_box (table, TAL_2, TAL_2, -1, -1, - 0, 0, tab_nc (table) - 1, tab_nr (table) - 1 ); - - - tab_hline (table, TAL_2, 0, tab_nc (table) -1, column_headers); - tab_vline (table, TAL_2, row_headers, 0, tab_nr (table) - 1); - - row = 0; - tab_double (table, 1, column_headers + row++, - 0, fr->cc, NULL, RC_WEIGHT); + struct pivot_table *table = pivot_table_create (N_("Test Statistics")); + pivot_table_set_weight_var (table, dict_get_weight (fr->dict)); + struct pivot_dimension *statistics = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Statistics"), + N_("N"), PIVOT_RC_COUNT); if (ft->kendalls_w) - tab_double (table, 1, column_headers + row++, - 0, fr->w, NULL, RC_OTHER); + pivot_category_create_leaves (statistics->root, N_("Kendall's W"), + PIVOT_RC_OTHER); + pivot_category_create_leaves (statistics->root, + N_("Chi-Square"), PIVOT_RC_OTHER, + N_("df"), PIVOT_RC_INTEGER, + N_("Asymp. Sig."), PIVOT_RC_SIGNIFICANCE); - tab_double (table, 1, column_headers + row++, - 0, fr->chi_sq, NULL, RC_OTHER); + double entries[5]; + int n = 0; - tab_double (table, 1, column_headers + row++, - 0, ost->n_vars - 1, NULL, RC_INTEGER); + entries[n++] = fr->cc; + if (ft->kendalls_w) + entries[n++] = fr->w; + entries[n++] = fr->chi_sq; + entries[n++] = ost->n_vars - 1; + entries[n++] = gsl_cdf_chisq_Q (fr->chi_sq, ost->n_vars - 1); + assert (n <= sizeof entries / sizeof *entries); - tab_double (table, 1, column_headers + row++, - 0, gsl_cdf_chisq_Q (fr->chi_sq, ost->n_vars - 1), - NULL, RC_PVALUE); + for (size_t i = 0; i < n; i++) + pivot_table_put1 (table, i, pivot_value_new_number (entries[i])); - tab_submit (table); + pivot_table_submit (table); } diff --git a/src/language/stats/glm.c b/src/language/stats/glm.c index 5c46b18437..c8a3dd36e1 100644 --- a/src/language/stats/glm.c +++ b/src/language/stats/glm.c @@ -43,9 +43,10 @@ #include "math/covariance.h" #include "math/interaction.h" #include "math/moments.h" -#include "output/tab.h" +#include "output/pivot-table.h" #include "gettext.h" +#define N_(msgid) msgid #define _(msgid) gettext (msgid) struct glm_spec @@ -651,16 +652,14 @@ run_glm (struct glm_spec *cmd, struct casereader *input, if (cmd->dump_coding) { - struct tab_table *t = - covariance_dump_enc_header (cov, - 1 + casereader_count_cases (input)); + struct pivot_table *t = covariance_dump_enc_header (cov); for (reader = input; (c = casereader_read (reader)) != NULL; case_unref (c)) { covariance_dump_enc (cov, c, t); } - casereader_destroy (reader); - tab_submit (t); + + pivot_table_submit (t); } { @@ -709,174 +708,120 @@ run_glm (struct glm_spec *cmd, struct casereader *input, taint_destroy (taint); } -static const char *roman[] = - { - "", /* The Romans had no concept of zero */ - "I", - "II", - "III", - "IV" - }; +static void +put_glm_row (struct pivot_table *table, int row, + double a, double b, double c, double d, double e) +{ + double entries[] = { a, b, c, d, e }; + + for (size_t col = 0; col < sizeof entries / sizeof *entries; col++) + if (entries[col] != SYSMIS) + pivot_table_put2 (table, col, row, + pivot_value_new_number (entries[col])); +} static void output_glm (const struct glm_spec *cmd, const struct glm_workspace *ws) { - const struct fmt_spec *wfmt = - cmd->wv ? var_get_print_format (cmd->wv) : &F_8_0; + struct pivot_table *table = pivot_table_create ( + N_("Tests of Between-Subjects Effects")); + + pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Statistics"), + (cmd->ss_type == 1 ? N_("Type I Sum Of Squares") + : cmd->ss_type == 2 ? N_("Type II Sum Of Squares") + : N_("Type III Sum Of Squares")), PIVOT_RC_OTHER, + N_("df"), PIVOT_RC_COUNT, + N_("Mean Square"), PIVOT_RC_OTHER, + N_("F"), PIVOT_RC_OTHER, + N_("Sig."), PIVOT_RC_SIGNIFICANCE); + + struct pivot_dimension *source = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Source"), + cmd->intercept ? N_("Corrected Model") : N_("Model")); - double intercept_ssq; - double ssq_effects; double n_total, mean; - double df_corr = 1.0; - double mse = 0; - - int f; - int r; - const int heading_columns = 1; - const int heading_rows = 1; - struct tab_table *t; - - const int nc = 6; - int nr = heading_rows + 3 + cmd->n_interactions; - if (cmd->intercept) - nr += 2; - - t = tab_create (nc, nr); - tab_set_format (t, RC_WEIGHT, wfmt); - tab_title (t, _("Tests of Between-Subjects Effects")); - - tab_headers (t, heading_columns, 0, heading_rows, 0); - - tab_box (t, TAL_2, TAL_2, -1, TAL_1, 0, 0, nc - 1, nr - 1); - - tab_hline (t, TAL_2, 0, nc - 1, heading_rows); - tab_vline (t, TAL_2, heading_columns, 0, nr - 1); - - tab_text (t, 0, 0, TAB_CENTER | TAT_TITLE, _("Source")); - - /* TRANSLATORS: The parameter is a roman numeral */ - tab_text_format (t, 1, 0, TAB_CENTER | TAT_TITLE, - _("Type %s Sum of Squares"), - roman[cmd->ss_type]); - tab_text (t, 2, 0, TAB_CENTER | TAT_TITLE, _("df")); - tab_text (t, 3, 0, TAB_CENTER | TAT_TITLE, _("Mean Square")); - tab_text (t, 4, 0, TAB_CENTER | TAT_TITLE, _("F")); - tab_text (t, 5, 0, TAB_CENTER | TAT_TITLE, _("Sig.")); - moments_calculate (ws->totals, &n_total, &mean, NULL, NULL, NULL); - df_corr += categoricals_df_total (ws->cats); + double df_corr = 1.0 + categoricals_df_total (ws->cats); - r = heading_rows; - if (cmd->intercept) - tab_text (t, 0, r, TAB_LEFT | TAT_TITLE, _("Corrected Model")); - else - tab_text (t, 0, r, TAB_LEFT | TAT_TITLE, _("Model")); - - r++; - - mse = gsl_vector_get (ws->ssq, 0) / (n_total - df_corr); - - intercept_ssq = pow2 (mean * n_total) / n_total; - - ssq_effects = 0.0; + double mse = gsl_vector_get (ws->ssq, 0) / (n_total - df_corr); + double intercept_ssq = pow2 (mean * n_total) / n_total; if (cmd->intercept) { - const double df = 1.0; - const double F = intercept_ssq / df / mse; - tab_text (t, 0, r, TAB_LEFT | TAT_TITLE, _("Intercept")); + int row = pivot_category_create_leaf ( + source->root, pivot_value_new_text (N_("Intercept"))); + /* The intercept for unbalanced models is of limited use and nobody knows how to calculate it properly */ if (categoricals_isbalanced (ws->cats)) - { - tab_double (t, 1, r, 0, intercept_ssq, NULL, RC_OTHER); - tab_double (t, 2, r, 0, 1.00, NULL, RC_WEIGHT); - tab_double (t, 3, r, 0, intercept_ssq / df, NULL, RC_OTHER); - tab_double (t, 4, r, 0, F, NULL, RC_OTHER); - tab_double (t, 5, r, 0, gsl_cdf_fdist_Q (F, df, n_total - df_corr), - NULL, RC_PVALUE); - } - r++; + { + const double df = 1.0; + const double F = intercept_ssq / df / mse; + put_glm_row (table, row, intercept_ssq, 1.0, intercept_ssq / df, + F, gsl_cdf_fdist_Q (F, df, n_total - df_corr)); + } } - for (f = 0; f < cmd->n_interactions; ++f) + double ssq_effects = 0.0; + for (int f = 0; f < cmd->n_interactions; ++f) { - struct string str = DS_EMPTY_INITIALIZER; double df = categoricals_df (ws->cats, f); - double ssq = gsl_vector_get (ws->ssq, f + 1); - double F; - ssq_effects += ssq; - - if (! cmd->intercept) + if (!cmd->intercept) { df++; ssq += intercept_ssq; } + double F = ssq / df / mse; - F = ssq / df / mse; + struct string str = DS_EMPTY_INITIALIZER; interaction_to_string (cmd->interactions[f], &str); - tab_text (t, 0, r, TAB_LEFT | TAT_TITLE, ds_cstr (&str)); - ds_destroy (&str); - - tab_double (t, 1, r, 0, ssq, NULL, RC_OTHER); - tab_double (t, 2, r, 0, df, NULL, RC_WEIGHT); - tab_double (t, 3, r, 0, ssq / df, NULL, RC_OTHER); - tab_double (t, 4, r, 0, F, NULL, RC_OTHER); + int row = pivot_category_create_leaf ( + source->root, pivot_value_new_user_text_nocopy (ds_steal_cstr (&str))); - tab_double (t, 5, r, 0, gsl_cdf_fdist_Q (F, df, n_total - df_corr), - NULL, RC_PVALUE); - r++; + put_glm_row (table, row, ssq, df, ssq / df, F, + gsl_cdf_fdist_Q (F, df, n_total - df_corr)); } { /* Model / Corrected Model */ double df = df_corr; double ssq = ws->total_ssq - gsl_vector_get (ws->ssq, 0); - double F; - - if ( cmd->intercept ) - df --; + if (cmd->intercept) + df--; else ssq += intercept_ssq; - - F = ssq / df / mse; - tab_double (t, 1, heading_rows, 0, ssq, NULL, RC_OTHER); - tab_double (t, 2, heading_rows, 0, df, NULL, RC_WEIGHT); - tab_double (t, 3, heading_rows, 0, ssq / df, NULL, RC_OTHER); - tab_double (t, 4, heading_rows, 0, F, NULL, RC_OTHER); - - tab_double (t, 5, heading_rows, 0, - gsl_cdf_fdist_Q (F, df, n_total - df_corr), NULL, RC_PVALUE); + double F = ssq / df / mse; + put_glm_row (table, 0, ssq, df, ssq / df, F, + gsl_cdf_fdist_Q (F, df, n_total - df_corr)); } { + int row = pivot_category_create_leaf (source->root, + pivot_value_new_text (N_("Error"))); const double df = n_total - df_corr; const double ssq = gsl_vector_get (ws->ssq, 0); const double mse = ssq / df; - tab_text (t, 0, r, TAB_LEFT | TAT_TITLE, _("Error")); - tab_double (t, 1, r, 0, ssq, NULL, RC_OTHER); - tab_double (t, 2, r, 0, df, NULL, RC_WEIGHT); - tab_double (t, 3, r++, 0, mse, NULL, RC_OTHER); + put_glm_row (table, row, ssq, df, mse, SYSMIS, SYSMIS); } { - tab_text (t, 0, r, TAB_LEFT | TAT_TITLE, _("Total")); - tab_double (t, 1, r, 0, ws->total_ssq + intercept_ssq, NULL, RC_OTHER); - tab_double (t, 2, r, 0, n_total, NULL, RC_WEIGHT); - - r++; + int row = pivot_category_create_leaf (source->root, + pivot_value_new_text (N_("Total"))); + put_glm_row (table, row, ws->total_ssq + intercept_ssq, n_total, + SYSMIS, SYSMIS, SYSMIS); } if (cmd->intercept) { - tab_text (t, 0, r, TAB_LEFT | TAT_TITLE, _("Corrected Total")); - tab_double (t, 1, r, 0, ws->total_ssq, NULL, RC_OTHER); - tab_double (t, 2, r, 0, n_total - 1.0, NULL, RC_WEIGHT); + int row = pivot_category_create_leaf ( + source->root, pivot_value_new_text (N_("Corrected Total"))); + put_glm_row (table, row, ws->total_ssq, n_total - 1.0, SYSMIS, + SYSMIS, SYSMIS); } - tab_submit (t); + pivot_table_submit (table); } #if 0 diff --git a/src/language/stats/graph.c b/src/language/stats/graph.c index 578efc1e75..cc927bd10c 100644 --- a/src/language/stats/graph.c +++ b/src/language/stats/graph.c @@ -58,8 +58,6 @@ #include "language/stats/freq.h" #include "language/stats/chart-category.h" -#include "output/tab.h" - #include "gettext.h" #define _(msgid) gettext (msgid) #define N_(msgid) msgid diff --git a/src/language/stats/jonckheere-terpstra.c b/src/language/stats/jonckheere-terpstra.c index d7af2b070e..7e8406f382 100644 --- a/src/language/stats/jonckheere-terpstra.c +++ b/src/language/stats/jonckheere-terpstra.c @@ -35,11 +35,16 @@ #include "libpspp/message.h" #include "libpspp/misc.h" #include "math/sort.h" -#include "output/tab.h" +#include "output/pivot-table.h" #include "gl/minmax.h" #include "gl/xalloc.h" +#include "gettext.h" +#define N_(msgid) msgid +#define _(msgid) gettext (msgid) + + /* Returns true iff the independent variable lies in the between val1 and val2. Regardless of which is the greater value. */ @@ -216,7 +221,8 @@ struct jt double stddev; }; -static void show_jt (const struct n_sample_test *nst, const struct jt *jt, const struct variable *wv); +static void show_jt (const struct n_sample_test *, const struct jt *, + const struct fmt_spec *wfmt); void @@ -336,85 +342,61 @@ jonckheere_terpstra_execute (const struct dataset *ds, jt.mean = (pow2 (jt.n) - ccsq_sum) / 4.0; - show_jt (nst, &jt, dict_get_weight (dict)); + show_jt (nst, &jt, dict_get_weight_format (dict)); } casereader_destroy (input); caseproto_unref (proto); } - - -#include "gettext.h" -#define _(msgid) gettext (msgid) - static void -show_jt (const struct n_sample_test *nst, const struct jt *jt, const struct variable *wv) +show_jt (const struct n_sample_test *nst, const struct jt *jt, + const struct fmt_spec *wfmt) { - int i; - const int row_headers = 1; - const int column_headers = 1; - const struct fmt_spec *wfmt = wv ? var_get_print_format (wv) : & F_8_0; - - struct tab_table *table = - tab_create (row_headers + 7, column_headers + nst->n_vars); - tab_set_format (table, RC_WEIGHT, wfmt); - - tab_headers (table, row_headers, 0, column_headers, 0); - - tab_title (table, _("Jonckheere-Terpstra Test")); - - /* Vertical lines inside the box */ - tab_box (table, 1, 0, -1, TAL_1, - row_headers, 0, tab_nc (table) - 1, tab_nr (table) - 1 ); - - /* Box around the table */ - tab_box (table, TAL_2, TAL_2, -1, -1, - 0, 0, tab_nc (table) - 1, tab_nr (table) - 1 ); - - tab_hline (table, TAL_2, 0, tab_nc (table) -1, column_headers); - tab_vline (table, TAL_2, row_headers, 0, tab_nr (table) - 1); - - tab_text_format (table, 1, 0, TAT_TITLE | TAB_CENTER, - _("Number of levels in %s"), - var_to_string (nst->indep_var)); - tab_text (table, 2, 0, TAT_TITLE | TAB_CENTER, _("N")); - tab_text (table, 3, 0, TAT_TITLE | TAB_CENTER, _("Observed J-T Statistic")); - tab_text (table, 4, 0, TAT_TITLE | TAB_CENTER, _("Mean J-T Statistic")); - tab_text (table, 5, 0, TAT_TITLE | TAB_CENTER, _("Std. Deviation of J-T Statistic")); - tab_text (table, 6, 0, TAT_TITLE | TAB_CENTER, _("Std. J-T Statistic")); - tab_text (table, 7, 0, TAT_TITLE | TAB_CENTER, _("Asymp. Sig. (2-tailed)")); - - - for (i = 0; i < nst->n_vars; ++i) + struct pivot_table *table = pivot_table_create ( + N_("Jonckheere-Terpstra Test")); + pivot_table_set_weight_format (table, wfmt); + + struct pivot_dimension *statistics = pivot_dimension_create ( + table, PIVOT_AXIS_COLUMN, N_("Statistics")); + pivot_category_create_leaf_rc ( + statistics->root, + pivot_value_new_text_format (N_("Number of levels in %s"), + var_to_string (nst->indep_var)), + PIVOT_RC_INTEGER); + pivot_category_create_leaves ( + statistics->root, + N_("N"), PIVOT_RC_COUNT, + N_("Observed J-T Statistic"), PIVOT_RC_OTHER, + N_("Mean J-T Statistic"), PIVOT_RC_OTHER, + N_("Std. Deviation of J-T Statistic"), PIVOT_RC_OTHER, + N_("Std. J-T Statistic"), PIVOT_RC_OTHER, + N_("Asymp. Sig. (2-tailed)"), PIVOT_RC_SIGNIFICANCE); + + struct pivot_dimension *variables = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Variable")); + + for (size_t i = 0; i < nst->n_vars; ++i) { - double std_jt; - - tab_text (table, 0, i + row_headers, TAT_TITLE, - var_to_string (nst->vars[i]) ); - - tab_double (table, 1, i + row_headers, TAT_TITLE, - jt[0].levels, NULL, RC_INTEGER); - - tab_double (table, 2, i + row_headers, TAT_TITLE, - jt[0].n, NULL, RC_WEIGHT); - - tab_double (table, 3, i + row_headers, TAT_TITLE, - jt[0].obs, NULL, RC_OTHER); - - tab_double (table, 4, i + row_headers, TAT_TITLE, - jt[0].mean, NULL, RC_OTHER); - - tab_double (table, 5, i + row_headers, TAT_TITLE, - jt[0].stddev, NULL, RC_OTHER); - - std_jt = (jt[0].obs - jt[0].mean) / jt[0].stddev; - tab_double (table, 6, i + row_headers, TAT_TITLE, - std_jt, NULL, RC_OTHER); - - tab_double (table, 7, i + row_headers, TAT_TITLE, - 2.0 * ((std_jt > 0) ? gsl_cdf_ugaussian_Q (std_jt) : gsl_cdf_ugaussian_P (std_jt)), NULL, RC_PVALUE); + int row = pivot_category_create_leaf ( + variables->root, pivot_value_new_variable (nst->vars[i])); + + double std_jt = (jt[0].obs - jt[0].mean) / jt[0].stddev; + double sig = (2.0 * (std_jt > 0 + ? gsl_cdf_ugaussian_Q (std_jt) + : gsl_cdf_ugaussian_P (std_jt))); + double entries[] = { + jt[0].levels, + jt[0].n, + jt[0].obs, + jt[0].mean, + jt[0].stddev, + std_jt, + sig, + }; + for (size_t j = 0; j < sizeof entries / sizeof *entries; j++) + pivot_table_put2 (table, j, row, pivot_value_new_number (entries[j])); } - tab_submit (table); + pivot_table_submit (table); } diff --git a/src/language/stats/kruskal-wallis.c b/src/language/stats/kruskal-wallis.c index 24c369a93b..ae6fffe205 100644 --- a/src/language/stats/kruskal-wallis.c +++ b/src/language/stats/kruskal-wallis.c @@ -35,11 +35,14 @@ #include "libpspp/message.h" #include "libpspp/misc.h" #include "math/sort.h" -#include "output/tab.h" +#include "output/pivot-table.h" #include "gl/minmax.h" #include "gl/xalloc.h" +#include "gettext.h" +#define N_(msgid) msgid +#define _(msgid) gettext (msgid) /* Returns true iff the independent variable lies in the range [nst->val1, nst->val2] */ static bool @@ -113,8 +116,8 @@ struct kw double h; }; -static void show_ranks_box (const struct n_sample_test *nst, const struct kw *kw, int n_groups); -static void show_sig_box (const struct n_sample_test *nst, const struct kw *kw); +static void show_ranks_box (const struct n_sample_test *, const struct kw *); +static void show_sig_box (const struct n_sample_test *, const struct kw *); void kruskal_wallis_execute (const struct dataset *ds, @@ -220,7 +223,7 @@ kruskal_wallis_execute (const struct dataset *ds, casereader_destroy (input); - show_ranks_box (nst, kw, total_n_groups); + show_ranks_box (nst, kw); show_sig_box (nst, kw); /* Cleanup allocated memory */ @@ -237,140 +240,79 @@ kruskal_wallis_execute (const struct dataset *ds, free (kw); } - -#include "gettext.h" -#define _(msgid) gettext (msgid) - - static void -show_ranks_box (const struct n_sample_test *nst, const struct kw *kw, int n_groups) +show_ranks_box (const struct n_sample_test *nst, const struct kw *kw) { - int row; - int i; - const int row_headers = 2; - const int column_headers = 1; - struct tab_table *table = - tab_create (row_headers + 2, column_headers + n_groups + nst->n_vars); - - tab_headers (table, row_headers, 0, column_headers, 0); + struct pivot_table *table = pivot_table_create (N_("Ranks")); - tab_title (table, _("Ranks")); + pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Statistics"), + N_("N"), PIVOT_RC_INTEGER, + N_("Mean Rank"), PIVOT_RC_OTHER); - /* Vertical lines inside the box */ - tab_box (table, 1, 0, -1, TAL_1, - row_headers, 0, tab_nc (table) - 1, tab_nr (table) - 1 ); + struct pivot_dimension *variables = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Variables")); - /* Box around the table */ - tab_box (table, TAL_2, TAL_2, -1, -1, - 0, 0, tab_nc (table) - 1, tab_nr (table) - 1 ); - - tab_text (table, 1, 0, TAT_TITLE, - var_to_string (nst->indep_var) - ); - - tab_text (table, 3, 0, 0, _("Mean Rank")); - tab_text (table, 2, 0, 0, _("N")); - - tab_hline (table, TAL_2, 0, tab_nc (table) -1, column_headers); - tab_vline (table, TAL_2, row_headers, 0, tab_nr (table) - 1); - - - row = column_headers; - for (i = 0 ; i < nst->n_vars ; ++i) + for (size_t i = 0 ; i < nst->n_vars ; ++i) { - int tot = 0; - struct rank_entry *re_x; - struct bt bt; - - if (i > 0) - tab_hline (table, TAL_1, 0, tab_nc (table) -1, row); - - tab_text (table, 0, row, - TAT_TITLE, var_to_string (nst->vars[i])); - /* Sort the rank entries, by iteratin the hash and putting the entries into a binary tree. */ - bt_init (&bt, compare_rank_entries_3way, nst->vars[i]); + struct bt bt = BT_INITIALIZER(compare_rank_entries_3way, nst->vars[i]); + struct rank_entry *re_x; HMAP_FOR_EACH (re_x, struct rank_entry, node, &kw[i].map) - { - bt_insert (&bt, &re_x->btn); - } + bt_insert (&bt, &re_x->btn); /* Report the rank entries in sorted order. */ + struct pivot_category *group = pivot_category_create_group__ ( + variables->root, pivot_value_new_variable (nst->vars[i])); + int tot = 0; const struct rank_entry *re; BT_FOR_EACH (re, struct rank_entry, btn, &bt) { - struct string str; - ds_init_empty (&str); - + struct string str = DS_EMPTY_INITIALIZER; var_append_value_name (nst->indep_var, &re->group, &str); + int row = pivot_category_create_leaf ( + group, pivot_value_new_user_text_nocopy (ds_steal_cstr (&str))); - tab_text (table, 1, row, TAB_LEFT, ds_cstr (&str)); - tab_double (table, 2, row, TAB_LEFT, re->n, NULL, RC_INTEGER); - tab_double (table, 3, row, TAB_LEFT, re->sum_of_ranks / re->n, NULL, RC_OTHER); + double entries[] = { re->n, re->sum_of_ranks / re->n }; + for (size_t j = 0; j < sizeof entries / sizeof *entries; j++) + pivot_table_put2 (table, j, row, + pivot_value_new_number (entries[j])); tot += re->n; - row++; - ds_destroy (&str); } - tab_double (table, 2, row, TAB_LEFT, - tot, NULL, RC_INTEGER); - tab_text (table, 1, row++, TAB_LEFT, _("Total")); + int row = pivot_category_create_leaves (group, N_("Total")); + pivot_table_put2 (table, 0, row, pivot_value_new_number (tot)); } - tab_submit (table); + pivot_table_submit (table); } - static void show_sig_box (const struct n_sample_test *nst, const struct kw *kw) { - int i; - const int row_headers = 1; - const int column_headers = 1; - struct tab_table *table = - tab_create (row_headers + nst->n_vars * 2, column_headers + 3); - - tab_headers (table, row_headers, 0, column_headers, 0); - - tab_title (table, _("Test Statistics")); + struct pivot_table *table = pivot_table_create (N_("Test Statistics")); - tab_text (table, 0, column_headers, - TAT_TITLE | TAB_LEFT , _("Chi-Square")); + pivot_dimension_create (table, PIVOT_AXIS_ROW, N_("Statistics"), + N_("Chi-Square"), PIVOT_RC_OTHER, + N_("df"), PIVOT_RC_INTEGER, + N_("Asymp. Sig."), PIVOT_RC_SIGNIFICANCE); - tab_text (table, 0, 1 + column_headers, - TAT_TITLE | TAB_LEFT, _("df")); + struct pivot_dimension *variables = pivot_dimension_create ( + table, PIVOT_AXIS_COLUMN, N_("Variables")); - tab_text (table, 0, 2 + column_headers, - TAT_TITLE | TAB_LEFT, _("Asymp. Sig.")); - - /* Box around the table */ - tab_box (table, TAL_2, TAL_2, -1, -1, - 0, 0, tab_nc (table) - 1, tab_nr (table) - 1 ); - - - tab_hline (table, TAL_2, 0, tab_nc (table) -1, column_headers); - tab_vline (table, TAL_2, row_headers, 0, tab_nr (table) - 1); - - for (i = 0 ; i < nst->n_vars; ++i) + for (size_t i = 0 ; i < nst->n_vars; ++i) { - const double df = hmap_count (&kw[i].map) - 1; - tab_text (table, column_headers + 1 + i, 0, TAT_TITLE, - var_to_string (nst->vars[i]) - ); - - tab_double (table, column_headers + 1 + i, 1, 0, - kw[i].h, NULL, RC_OTHER); - - tab_double (table, column_headers + 1 + i, 2, 0, - df, NULL, RC_INTEGER); - - tab_double (table, column_headers + 1 + i, 3, 0, - gsl_cdf_chisq_Q (kw[i].h, df), - NULL, RC_PVALUE); + int col = pivot_category_create_leaf ( + variables->root, pivot_value_new_variable (nst->vars[i])); + + double df = hmap_count (&kw[i].map) - 1; + double sig = gsl_cdf_chisq_Q (kw[i].h, df); + double entries[] = { kw[i].h, df, sig }; + for (size_t j = 0; j < sizeof entries / sizeof *entries; j++) + pivot_table_put2 (table, j, col, pivot_value_new_number (entries[j])); } - tab_submit (table); + pivot_table_submit (table); } diff --git a/src/language/stats/ks-one-sample.c b/src/language/stats/ks-one-sample.c index 7e2e5bb631..89559b798f 100644 --- a/src/language/stats/ks-one-sample.c +++ b/src/language/stats/ks-one-sample.c @@ -40,11 +40,12 @@ #include "libpspp/hash-functions.h" #include "libpspp/message.h" #include "libpspp/misc.h" -#include "output/tab.h" +#include "output/pivot-table.h" #include "gl/xalloc.h" #include "gettext.h" +#define N_(msgid) msgid #define _(msgid) gettext (msgid) @@ -269,133 +270,96 @@ show_results (const struct ks *ks, const struct ks_one_sample_test *kst, const struct fmt_spec *wfmt) { - int i; - const int row_headers = 1; - const int column_headers = 2; - const int nc = kst->parent.n_vars + column_headers; - const int nr = 8 + row_headers; - struct tab_table *table = tab_create (nc, nr); - tab_set_format (table, RC_WEIGHT, wfmt); - tab_headers (table, row_headers, 0, column_headers, 0); + struct pivot_table *table = pivot_table_create ( + N_("One-Sample Kolmogorov-Smirnov Test")); + pivot_table_set_weight_format (table, wfmt); - tab_title (table, _("One-Sample Kolmogorov-Smirnov Test")); - - /* Box around the table */ - tab_box (table, TAL_2, TAL_2, -1, -1, - 0, 0, nc - 1, nr - 1 ); - - tab_hline (table, TAL_2, 0, nc - 1, row_headers); - - tab_vline (table, TAL_1, column_headers, 0, nr - 1); - - tab_text (table, 0, 1, - TAT_TITLE | TAB_LEFT , _("N")); + struct pivot_dimension *statistics = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Statistics"), + N_("N"), PIVOT_RC_COUNT); switch (kst->dist) { - case KS_NORMAL: - tab_text (table, 0, 2, - TAT_TITLE | TAB_LEFT , _("Normal Parameters")); - - tab_text (table, 1, 2, - TAT_TITLE | TAB_LEFT , _("Mean")); - tab_text (table, 1, 3, - TAT_TITLE | TAB_LEFT , _("Std. Deviation")); - break; case KS_UNIFORM: - tab_text (table, 0, 2, - TAT_TITLE | TAB_LEFT , _("Uniform Parameters")); + pivot_category_create_group (statistics->root, N_("Uniform Parameters"), + N_("Minimum"), N_("Maximum")); + break; - tab_text (table, 1, 2, - TAT_TITLE | TAB_LEFT , _("Minimum")); - tab_text (table, 1, 3, - TAT_TITLE | TAB_LEFT , _("Maximum")); + case KS_NORMAL: + pivot_category_create_group (statistics->root, N_("Normal Parameters"), + N_("Mean"), N_("Std. Deviation")); break; - case KS_POISSON: - tab_text (table, 0, 2, - TAT_TITLE | TAB_LEFT , _("Poisson Parameters")); - tab_text (table, 1, 2, - TAT_TITLE | TAB_LEFT , _("Lambda")); + case KS_POISSON: + pivot_category_create_group (statistics->root, N_("Poisson Parameters"), + N_("Lambda")); break; - case KS_EXPONENTIAL: - tab_text (table, 0, 2, - TAT_TITLE | TAB_LEFT , _("Exponential Parameters")); - tab_text (table, 1, 2, - TAT_TITLE | TAB_LEFT , _("Scale")); + case KS_EXPONENTIAL: + pivot_category_create_group (statistics->root, + N_("Exponential Parameters"), N_("Scale")); break; default: NOT_REACHED (); } - /* The variable columns */ - for (i = 0; i < kst->parent.n_vars; ++i) + pivot_category_create_group ( + statistics->root, N_("Most Extreme Differences"), + N_("Absolute"), N_("Positive"), N_("Negative")); + + pivot_category_create_leaves ( + statistics->root, N_("Kolmogorov-Smirnov Z"), + _("Asymp. Sig. (2-tailed)"), PIVOT_RC_SIGNIFICANCE); + + struct pivot_dimension *variables = pivot_dimension_create ( + table, PIVOT_AXIS_COLUMN, N_("Variables")); + + for (size_t i = 0; i < kst->parent.n_vars; ++i) { - double abs = 0; - double z = 0; - const int col = 2 + i; - tab_text (table, col, 0, - TAT_TITLE | TAB_CENTER , - var_to_string (kst->parent.vars[i])); + int col = pivot_category_create_leaf ( + variables->root, pivot_value_new_variable (kst->parent.vars[i])); + + double values[10]; + size_t n = 0; + + values[n++] = ks[i].obs_cc; switch (kst->dist) { case KS_UNIFORM: - tab_double (table, col, 1, 0, ks[i].obs_cc, NULL, RC_WEIGHT); - tab_double (table, col, 2, 0, ks[i].test_min, NULL, RC_OTHER); - tab_double (table, col, 3, 0, ks[i].test_max, NULL, RC_OTHER); + values[n++] = ks[i].test_min; + values[n++] = ks[i].test_max; break; case KS_NORMAL: - tab_double (table, col, 1, 0, ks[i].obs_cc, NULL, RC_WEIGHT); - tab_double (table, col, 2, 0, ks[i].mu, NULL, RC_OTHER); - tab_double (table, col, 3, 0, ks[i].sigma, NULL, RC_OTHER); + values[n++] = ks[i].mu; + values[n++] = ks[i].sigma; break; case KS_POISSON: case KS_EXPONENTIAL: - tab_double (table, col, 1, 0, ks[i].obs_cc, NULL, RC_WEIGHT); - tab_double (table, col, 2, 0, ks[i].mu, NULL, RC_OTHER); + values[n++] = ks[i].mu; break; default: NOT_REACHED (); } - abs = ks[i].diff_pos; + double abs = ks[i].diff_pos; maximize (&abs, -ks[i].diff_neg); - z = sqrt (ks[i].obs_cc) * abs; - - tab_double (table, col, 5, 0, ks[i].diff_pos, NULL, RC_OTHER); - tab_double (table, col, 6, 0, ks[i].diff_neg, NULL, RC_OTHER); + double z = sqrt (ks[i].obs_cc) * abs; - tab_double (table, col, 4, 0, abs, NULL, RC_OTHER); + values[n++] = abs; + values[n++] = ks[i].diff_pos; + values[n++] = ks[i].diff_neg; + values[n++] = z; + values[n++] = ks_asymp_sig (z); - tab_double (table, col, 7, 0, z, NULL, RC_OTHER); - tab_double (table, col, 8, 0, ks_asymp_sig (z), NULL, RC_PVALUE); + for (size_t j = 0; j < n; j++) + pivot_table_put2 (table, j, col, pivot_value_new_number (values[j])); } - - tab_text (table, 0, 4, - TAT_TITLE | TAB_LEFT , _("Most Extreme Differences")); - - tab_text (table, 1, 4, - TAT_TITLE | TAB_LEFT , _("Absolute")); - - tab_text (table, 1, 5, - TAT_TITLE | TAB_LEFT , _("Positive")); - - tab_text (table, 1, 6, - TAT_TITLE | TAB_LEFT , _("Negative")); - - tab_text (table, 0, 7, - TAT_TITLE | TAB_LEFT , _("Kolmogorov-Smirnov Z")); - - tab_text (table, 0, 8, - TAT_TITLE | TAB_LEFT , _("Asymp. Sig. (2-tailed)")); - - tab_submit (table); + pivot_table_submit (table); } diff --git a/src/language/stats/logistic.c b/src/language/stats/logistic.c index 14c317ff72..6d2366518b 100644 --- a/src/language/stats/logistic.c +++ b/src/language/stats/logistic.c @@ -60,17 +60,17 @@ #include "language/lexer/value-parser.h" #include "language/lexer/variable-parser.h" #include "libpspp/assertion.h" +#include "libpspp/hash-functions.h" +#include "libpspp/hmap.h" #include "libpspp/ll.h" #include "libpspp/message.h" #include "libpspp/misc.h" #include "math/categoricals.h" #include "math/interaction.h" -#include "libpspp/hmap.h" -#include "libpspp/hash-functions.h" - -#include "output/tab.h" +#include "output/pivot-table.h" #include "gettext.h" +#define N_(msgid) msgid #define _(msgid) gettext (msgid) @@ -1137,43 +1137,26 @@ cmd_logistic (struct lexer *lexer, struct dataset *ds) static void output_depvarmap (const struct lr_spec *cmd, const struct lr_result *res) { - const int heading_columns = 0; - const int heading_rows = 1; - struct tab_table *t; - struct string str; - - const int nc = 2; - int nr = heading_rows + 2; - - t = tab_create (nc, nr); - tab_title (t, _("Dependent Variable Encoding")); - - tab_headers (t, heading_columns, 0, heading_rows, 0); - - tab_box (t, TAL_2, TAL_2, -1, TAL_1, 0, 0, nc - 1, nr - 1); - - tab_hline (t, TAL_2, 0, nc - 1, heading_rows); - tab_vline (t, TAL_2, heading_columns, 0, nr - 1); + struct pivot_table *table = pivot_table_create ( + N_("Dependent Variable Encoding")); - tab_text (t, 0, 0, TAB_CENTER | TAT_TITLE, _("Original Value")); - tab_text (t, 1, 0, TAB_CENTER | TAT_TITLE, _("Internal Value")); + pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Mapping"), + N_("Internal Value")); + struct pivot_dimension *original = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Original Value")); + original->root->show_label = true; + for (int i = 0; i < 2; i++) + { + const union value *v = i ? &res->y1 : &res->y0; + int orig_idx = pivot_category_create_leaf ( + original->root, pivot_value_new_var_value (cmd->dep_var, v)); + pivot_table_put2 (table, 0, orig_idx, pivot_value_new_number ( + map_dependent_var (cmd, res, v))); + } - ds_init_empty (&str); - var_append_value_name (cmd->dep_var, &res->y0, &str); - tab_text (t, 0, 0 + heading_rows, 0, ds_cstr (&str)); - - ds_clear (&str); - var_append_value_name (cmd->dep_var, &res->y1, &str); - tab_text (t, 0, 1 + heading_rows, 0, ds_cstr (&str)); - - - tab_double (t, 1, 0 + heading_rows, 0, map_dependent_var (cmd, res, &res->y0), NULL, RC_INTEGER); - tab_double (t, 1, 1 + heading_rows, 0, map_dependent_var (cmd, res, &res->y1), NULL, RC_INTEGER); - ds_destroy (&str); - - tab_submit (t); + pivot_table_submit (table); } @@ -1182,84 +1165,62 @@ static void output_variables (const struct lr_spec *cmd, const struct lr_result *res) { - int row = 0; - const int heading_columns = 1; - int heading_rows = 1; - struct tab_table *t; + struct pivot_table *table = pivot_table_create ( + N_("Variables in the Equation")); + + struct pivot_dimension *statistics = pivot_dimension_create ( + table, PIVOT_AXIS_COLUMN, N_("Statistics"), + N_("B"), PIVOT_RC_OTHER, + N_("S.E."), PIVOT_RC_OTHER, + N_("Wald"), PIVOT_RC_OTHER, + N_("df"), PIVOT_RC_INTEGER, + N_("Sig."), PIVOT_RC_SIGNIFICANCE, + N_("Exp(B)"), PIVOT_RC_OTHER); + if (cmd->print & PRINT_CI) + { + struct pivot_category *group = pivot_category_create_group__ ( + statistics->root, + pivot_value_new_text_format (N_("%d%% CI for Exp(B)"), + cmd->confidence)); + pivot_category_create_leaves (group, N_("Lower"), N_("Upper")); + } + + struct pivot_dimension *variables = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Variables")); + struct pivot_category *step1 = pivot_category_create_group ( + variables->root, N_("Step 1")); - int nc = 8; - int nr ; - int i = 0; int ivar = 0; int idx_correction = 0; + int i = 0; - if (cmd->print & PRINT_CI) - { - nc += 2; - heading_rows += 1; - row++; - } - nr = heading_rows + cmd->n_predictor_vars; + int nr = cmd->n_predictor_vars; if (cmd->constant) nr++; - if (res->cats) nr += categoricals_df_total (res->cats) + cmd->n_cat_predictors; - t = tab_create (nc, nr); - tab_title (t, _("Variables in the Equation")); - - tab_headers (t, heading_columns, 0, heading_rows, 0); - - tab_box (t, TAL_2, TAL_2, -1, TAL_1, 0, 0, nc - 1, nr - 1); - - tab_hline (t, TAL_2, 0, nc - 1, heading_rows); - tab_vline (t, TAL_2, heading_columns, 0, nr - 1); - - tab_text (t, 0, row + 1, TAB_CENTER | TAT_TITLE, _("Step 1")); - - tab_text (t, 2, row, TAB_CENTER | TAT_TITLE, _("B")); - tab_text (t, 3, row, TAB_CENTER | TAT_TITLE, _("S.E.")); - tab_text (t, 4, row, TAB_CENTER | TAT_TITLE, _("Wald")); - tab_text (t, 5, row, TAB_CENTER | TAT_TITLE, _("df")); - tab_text (t, 6, row, TAB_CENTER | TAT_TITLE, _("Sig.")); - tab_text (t, 7, row, TAB_CENTER | TAT_TITLE, _("Exp(B)")); - - if (cmd->print & PRINT_CI) - { - tab_joint_text_format (t, 8, 0, 9, 0, - TAB_CENTER | TAT_TITLE, _("%d%% CI for Exp(B)"), cmd->confidence); - - tab_text (t, 8, row, TAB_CENTER | TAT_TITLE, _("Lower")); - tab_text (t, 9, row, TAB_CENTER | TAT_TITLE, _("Upper")); - } - - for (row = heading_rows ; row < nr; ++row) + for (int row = 0; row < nr; row++) { - const int idx = row - heading_rows - idx_correction; - - const double b = gsl_vector_get (res->beta_hat, idx); - const double sigma2 = gsl_matrix_get (res->hessian, idx, idx); - const double wald = pow2 (b) / sigma2; - const double df = 1; + const int idx = row - idx_correction; + int var_idx; if (idx < cmd->n_predictor_vars) - { - tab_text (t, 1, row, TAB_LEFT | TAT_TITLE, - var_to_string (cmd->predictor_vars[idx])); - } + var_idx = pivot_category_create_leaf ( + step1, pivot_value_new_variable (cmd->predictor_vars[idx])); else if (i < cmd->n_cat_predictors) { - double wald; - bool summary = false; - struct string str; const struct interaction *cat_predictors = cmd->cat_predictors[i]; - const int df = categoricals_df (res->cats, i); - - ds_init_empty (&str); + struct string str = DS_EMPTY_INITIALIZER; interaction_to_string (cat_predictors, &str); - - if (ivar == 0) + if (ivar != 0) + ds_put_format (&str, "(%d)", ivar); + var_idx = pivot_category_create_leaf ( + step1, pivot_value_new_user_text_nocopy (ds_steal_cstr (&str))); + + int df = categoricals_df (res->cats, i); + bool summary = ivar == 0; + if (summary) { /* Calculate the Wald statistic, which is \beta' C^-1 \beta . @@ -1278,64 +1239,56 @@ output_variables (const struct lr_spec *cmd, gsl_linalg_cholesky_invert (subhessian); gsl_blas_dgemv (CblasTrans, 1.0, subhessian, &vv.vector, 0, temp); + double wald; gsl_blas_ddot (temp, &vv.vector, &wald); - tab_double (t, 4, row, 0, wald, NULL, RC_OTHER); - tab_double (t, 5, row, 0, df, NULL, RC_INTEGER); - tab_double (t, 6, row, 0, gsl_cdf_chisq_Q (wald, df), NULL, RC_PVALUE); + double entries[] = { wald, df, gsl_cdf_chisq_Q (wald, df) }; + for (size_t j = 0; j < sizeof entries / sizeof *entries; j++) + pivot_table_put2 (table, j + 2, var_idx, + pivot_value_new_number (entries[j])); - idx_correction ++; - summary = true; + idx_correction++; gsl_matrix_free (subhessian); gsl_vector_free (temp); } - else - { - ds_put_format (&str, "(%d)", ivar); - } - tab_text (t, 1, row, TAB_LEFT | TAT_TITLE, ds_cstr (&str)); if (ivar++ == df) { ++i; /* next interaction */ ivar = 0; } - ds_destroy (&str); - if (summary) continue; } else - { - tab_text (t, 1, row, TAB_LEFT | TAT_TITLE, _("Constant")); - } - - tab_double (t, 2, row, 0, b, NULL, RC_OTHER); - tab_double (t, 3, row, 0, sqrt (sigma2), NULL, RC_OTHER); - tab_double (t, 4, row, 0, wald, NULL, RC_OTHER); - tab_double (t, 5, row, 0, df, NULL, RC_INTEGER); - tab_double (t, 6, row, 0, gsl_cdf_chisq_Q (wald, df), NULL, RC_PVALUE); - tab_double (t, 7, row, 0, exp (b), NULL, RC_OTHER); - - if (cmd->print & PRINT_CI) - { - int last_ci = nr; - double wc = gsl_cdf_ugaussian_Pinv (0.5 + cmd->confidence / 200.0); - wc *= sqrt (sigma2); - - if (cmd->constant) - last_ci--; - - if (row < last_ci) - { - tab_double (t, 8, row, 0, exp (b - wc), NULL, RC_OTHER); - tab_double (t, 9, row, 0, exp (b + wc), NULL, RC_OTHER); - } - } + var_idx = pivot_category_create_leaves (step1, N_("Constant")); + + double b = gsl_vector_get (res->beta_hat, idx); + double sigma2 = gsl_matrix_get (res->hessian, idx, idx); + double wald = pow2 (b) / sigma2; + double df = 1; + double wc = (gsl_cdf_ugaussian_Pinv (0.5 + cmd->confidence / 200.0) + * sqrt (sigma2)); + bool show_ci = cmd->print & PRINT_CI && row < nr - cmd->constant; + + double entries[] = { + b, + sqrt (sigma2), + wald, + df, + gsl_cdf_chisq_Q (wald, df), + exp (b), + show_ci ? exp (b - wc) : SYSMIS, + show_ci ? exp (b + wc) : SYSMIS, + }; + for (size_t j = 0; j < sizeof entries / sizeof *entries; j++) + if (entries[j] != SYSMIS) + pivot_table_put2 (table, j, var_idx, + pivot_value_new_number (entries[j])); } - tab_submit (t); + pivot_table_submit (table); } @@ -1344,105 +1297,79 @@ static void output_model_summary (const struct lr_result *res, double initial_log_likelihood, double log_likelihood) { - const int heading_columns = 0; - const int heading_rows = 1; - struct tab_table *t; - - const int nc = 4; - int nr = heading_rows + 1; - double cox; - - t = tab_create (nc, nr); - tab_title (t, _("Model Summary")); - - tab_headers (t, heading_columns, 0, heading_rows, 0); - - tab_box (t, TAL_2, TAL_2, -1, TAL_1, 0, 0, nc - 1, nr - 1); - - tab_hline (t, TAL_2, 0, nc - 1, heading_rows); - tab_vline (t, TAL_2, heading_columns, 0, nr - 1); - - tab_text (t, 0, 0, TAB_LEFT | TAT_TITLE, _("Step 1")); - tab_text (t, 1, 0, TAB_CENTER | TAT_TITLE, _("-2 Log likelihood")); - tab_double (t, 1, 1, 0, -2 * log_likelihood, NULL, RC_OTHER); - - - tab_text (t, 2, 0, TAB_CENTER | TAT_TITLE, _("Cox & Snell R Square")); - cox = 1.0 - exp((initial_log_likelihood - log_likelihood) * (2 / res->cc)); - tab_double (t, 2, 1, 0, cox, NULL, RC_OTHER); - - tab_text (t, 3, 0, TAB_CENTER | TAT_TITLE, _("Nagelkerke R Square")); - tab_double (t, 3, 1, 0, cox / ( 1.0 - exp(initial_log_likelihood * (2 / res->cc))), NULL, RC_OTHER); - - - tab_submit (t); + struct pivot_table *table = pivot_table_create (N_("Model Summary")); + + pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Statistics"), + N_("-2 Log likelihood"), PIVOT_RC_OTHER, + N_("Cox & Snell R Square"), PIVOT_RC_OTHER, + N_("Nagelkerke R Square"), PIVOT_RC_OTHER); + + struct pivot_dimension *step = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Step")); + step->root->show_label = true; + pivot_category_create_leaf (step->root, pivot_value_new_integer (1)); + + double cox = (1.0 - exp ((initial_log_likelihood - log_likelihood) + * (2 / res->cc))); + double entries[] = { + -2 * log_likelihood, + cox, + cox / ( 1.0 - exp(initial_log_likelihood * (2 / res->cc))) + }; + for (size_t i = 0; i < sizeof entries / sizeof *entries; i++) + pivot_table_put2 (table, i, 0, pivot_value_new_number (entries[i])); + + pivot_table_submit (table); } /* Show the case processing summary box */ static void case_processing_summary (const struct lr_result *res) { - const int heading_columns = 1; - const int heading_rows = 1; - struct tab_table *t; - - const int nc = 3; - const int nr = heading_rows + 3; - casenumber total; - - t = tab_create (nc, nr); - tab_title (t, _("Case Processing Summary")); - - tab_headers (t, heading_columns, 0, heading_rows, 0); - - tab_box (t, TAL_2, TAL_2, -1, TAL_1, 0, 0, nc - 1, nr - 1); + struct pivot_table *table = pivot_table_create ( + N_("Case Processing Summary")); - tab_hline (t, TAL_2, 0, nc - 1, heading_rows); - tab_vline (t, TAL_2, heading_columns, 0, nr - 1); + pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Statistics"), + N_("N"), PIVOT_RC_COUNT, + N_("Percent"), PIVOT_RC_PERCENT); - tab_text (t, 0, 0, TAB_LEFT | TAT_TITLE, _("Unweighted Cases")); - tab_text (t, 1, 0, TAB_CENTER | TAT_TITLE, _("N")); - tab_text (t, 2, 0, TAB_CENTER | TAT_TITLE, _("Percent")); + struct pivot_dimension *cases = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Unweighted Cases"), + N_("Included in Analysis"), N_("Missing Cases"), N_("Total")); + cases->root->show_label = true; - - tab_text (t, 0, 1, TAB_LEFT | TAT_TITLE, _("Included in Analysis")); - tab_text (t, 0, 2, TAB_LEFT | TAT_TITLE, _("Missing Cases")); - tab_text (t, 0, 3, TAB_LEFT | TAT_TITLE, _("Total")); - - tab_double (t, 1, 1, 0, res->n_nonmissing, NULL, RC_INTEGER); - tab_double (t, 1, 2, 0, res->n_missing, NULL, RC_INTEGER); - - total = res->n_nonmissing + res->n_missing; - tab_double (t, 1, 3, 0, total , NULL, RC_INTEGER); - - tab_double (t, 2, 1, 0, 100 * res->n_nonmissing / (double) total, NULL, RC_OTHER); - tab_double (t, 2, 2, 0, 100 * res->n_missing / (double) total, NULL, RC_OTHER); - tab_double (t, 2, 3, 0, 100 * total / (double) total, NULL, RC_OTHER); - - tab_submit (t); + double total = res->n_nonmissing + res->n_missing; + struct entry + { + int stat_idx; + int case_idx; + double x; + } + entries[] = { + { 0, 0, res->n_nonmissing }, + { 0, 1, res->n_missing }, + { 0, 2, total }, + { 1, 0, 100.0 * res->n_nonmissing / total }, + { 1, 1, 100.0 * res->n_missing / total }, + { 1, 2, 100.0 }, + }; + for (size_t i = 0; i < sizeof entries / sizeof *entries; i++) + pivot_table_put2 (table, entries[i].stat_idx, entries[i].case_idx, + pivot_value_new_number (entries[i].x)); + + pivot_table_submit (table); } static void output_categories (const struct lr_spec *cmd, const struct lr_result *res) { - const struct fmt_spec *wfmt = - cmd->wv ? var_get_print_format (cmd->wv) : &F_8_0; - - int cumulative_df; - int i = 0; - const int heading_columns = 2; - const int heading_rows = 2; - struct tab_table *t; - - int nc ; - int nr ; - - int v; - int r = 0; + struct pivot_table *table = pivot_table_create ( + N_("Categorical Variables' Codings")); + pivot_table_set_weight_var (table, dict_get_weight (cmd->dict)); int max_df = 0; int total_cats = 0; - for (i = 0; i < cmd->n_cat_predictors; ++i) + for (int i = 0; i < cmd->n_cat_predictors; ++i) { size_t n = categoricals_n_count (res->cats, i); size_t df = categoricals_df (res->cats, i); @@ -1451,164 +1378,121 @@ output_categories (const struct lr_spec *cmd, const struct lr_result *res) total_cats += n; } - nc = heading_columns + 1 + max_df; - nr = heading_rows + total_cats; - - t = tab_create (nc, nr); - tab_set_format (t, RC_WEIGHT, wfmt); - - tab_title (t, _("Categorical Variables' Codings")); - - tab_headers (t, heading_columns, 0, heading_rows, 0); - - tab_box (t, TAL_2, TAL_2, -1, TAL_1, 0, 0, nc - 1, nr - 1); - - tab_hline (t, TAL_2, 0, nc - 1, heading_rows); - tab_vline (t, TAL_2, heading_columns, 0, nr - 1); - - - tab_text (t, heading_columns, 1, TAB_CENTER | TAT_TITLE, _("Frequency")); - - tab_joint_text_format (t, heading_columns + 1, 0, nc - 1, 0, - TAB_CENTER | TAT_TITLE, _("Parameter coding")); - - - for (i = 0; i < max_df; ++i) - { - int c = heading_columns + 1 + i; - tab_text_format (t, c, 1, TAB_CENTER | TAT_TITLE, _("(%d)"), i + 1); - } - - cumulative_df = 0; - for (v = 0; v < cmd->n_cat_predictors; ++v) + struct pivot_dimension *codings = pivot_dimension_create ( + table, PIVOT_AXIS_COLUMN, N_("Codings"), + N_("Frequency"), PIVOT_RC_COUNT); + struct pivot_category *coding_group = pivot_category_create_group ( + codings->root, N_("Parameter coding")); + for (int i = 0; i < max_df; ++i) + pivot_category_create_leaf_rc ( + coding_group, + pivot_value_new_user_text_nocopy (xasprintf ("(%d)", i + 1)), + PIVOT_RC_INTEGER); + + struct pivot_dimension *categories = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Categories")); + + int cumulative_df = 0; + for (int v = 0; v < cmd->n_cat_predictors; ++v) { int cat; const struct interaction *cat_predictors = cmd->cat_predictors[v]; - int df = categoricals_df (res->cats, v); - struct string str; - ds_init_empty (&str); + int df = categoricals_df (res->cats, v); + struct string str = DS_EMPTY_INITIALIZER; interaction_to_string (cat_predictors, &str); - - tab_text (t, 0, heading_rows + r, TAB_LEFT | TAT_TITLE, ds_cstr (&str) ); - - ds_destroy (&str); + struct pivot_category *var_group = pivot_category_create_group__ ( + categories->root, + pivot_value_new_user_text_nocopy (ds_steal_cstr (&str))); for (cat = 0; cat < categoricals_n_count (res->cats, v) ; ++cat) { - struct string str; - const struct ccase *c = categoricals_get_case_by_category_real (res->cats, v, cat); - const double *freq = categoricals_get_user_data_by_category_real (res->cats, v, cat); - - int x; - ds_init_empty (&str); - - for (x = 0; x < cat_predictors->n_vars; ++x) + const struct ccase *c = categoricals_get_case_by_category_real ( + res->cats, v, cat); + struct string label = DS_EMPTY_INITIALIZER; + for (int x = 0; x < cat_predictors->n_vars; ++x) { - const union value *val = case_data (c, cat_predictors->vars[x]); - var_append_value_name (cat_predictors->vars[x], val, &str); + if (!ds_is_empty (&label)) + ds_put_byte (&label, ' '); - if (x < cat_predictors->n_vars - 1) - ds_put_cstr (&str, " "); + const union value *val = case_data (c, cat_predictors->vars[x]); + var_append_value_name (cat_predictors->vars[x], val, &label); } + int cat_idx = pivot_category_create_leaf ( + var_group, + pivot_value_new_user_text_nocopy (ds_steal_cstr (&label))); - tab_text (t, 1, heading_rows + r, 0, ds_cstr (&str)); - ds_destroy (&str); - tab_double (t, 2, heading_rows + r, 0, *freq, NULL, RC_WEIGHT); + double *freq = categoricals_get_user_data_by_category_real ( + res->cats, v, cat); + pivot_table_put2 (table, 0, cat_idx, pivot_value_new_number (*freq)); - for (x = 0; x < df; ++x) - { - tab_double (t, heading_columns + 1 + x, heading_rows + r, 0, (cat == x), NULL, RC_INTEGER); - } - ++r; + for (int x = 0; x < df; ++x) + pivot_table_put2 (table, x + 1, cat_idx, + pivot_value_new_number (cat == x)); } cumulative_df += df; } - tab_submit (t); - + pivot_table_submit (table); } +static void +create_classification_dimension (const struct lr_spec *cmd, + const struct lr_result *res, + struct pivot_table *table, + enum pivot_axis_type axis_type, + const char *label, const char *total) +{ + struct pivot_dimension *d = pivot_dimension_create ( + table, axis_type, label); + d->root->show_label = true; + struct pivot_category *pred_group = pivot_category_create_group__ ( + d->root, pivot_value_new_variable (cmd->dep_var)); + for (int i = 0; i < 2; i++) + { + const union value *y = i ? &res->y1 : &res->y0; + pivot_category_create_leaf_rc ( + pred_group, pivot_value_new_var_value (cmd->dep_var, y), + PIVOT_RC_COUNT); + } + pivot_category_create_leaves (d->root, total, PIVOT_RC_PERCENT); +} static void output_classification_table (const struct lr_spec *cmd, const struct lr_result *res) { - const struct fmt_spec *wfmt = - cmd->wv ? var_get_print_format (cmd->wv) : &F_8_0; - - const int heading_columns = 3; - const int heading_rows = 3; - - struct string sv0, sv1; - - const int nc = heading_columns + 3; - const int nr = heading_rows + 3; - - struct tab_table *t = tab_create (nc, nr); - tab_set_format (t, RC_WEIGHT, wfmt); - - ds_init_empty (&sv0); - ds_init_empty (&sv1); - - tab_title (t, _("Classification Table")); - - tab_headers (t, heading_columns, 0, heading_rows, 0); - - tab_box (t, TAL_2, TAL_2, -1, -1, 0, 0, nc - 1, nr - 1); - tab_box (t, -1, -1, -1, TAL_1, heading_columns, 0, nc - 1, nr - 1); - - tab_hline (t, TAL_2, 0, nc - 1, heading_rows); - tab_vline (t, TAL_2, heading_columns, 0, nr - 1); - - tab_text (t, 0, heading_rows, TAB_CENTER | TAT_TITLE, _("Step 1")); - - - tab_joint_text (t, heading_columns, 0, nc - 1, 0, - TAB_CENTER | TAT_TITLE, _("Predicted")); - - tab_joint_text (t, heading_columns, 1, heading_columns + 1, 1, - 0, var_to_string (cmd->dep_var) ); + struct pivot_table *table = pivot_table_create (N_("Classification Table")); + pivot_table_set_weight_var (table, cmd->wv); - tab_joint_text (t, 1, 2, 2, 2, - TAB_LEFT | TAT_TITLE, _("Observed")); + create_classification_dimension (cmd, res, table, PIVOT_AXIS_COLUMN, + N_("Predicted"), N_("Percentage Correct")); + create_classification_dimension (cmd, res, table, PIVOT_AXIS_ROW, + N_("Observed"), N_("Overall Percentage")); - tab_text (t, 1, 3, TAB_LEFT, var_to_string (cmd->dep_var) ); - - - tab_joint_text (t, nc - 1, 1, nc - 1, 2, - TAB_CENTER | TAT_TITLE, _("Percentage\nCorrect")); - - - tab_joint_text (t, 1, nr - 1, 2, nr - 1, - TAB_LEFT | TAT_TITLE, _("Overall Percentage")); - - - tab_hline (t, TAL_1, 1, nc - 1, nr - 1); - - var_append_value_name (cmd->dep_var, &res->y0, &sv0); - var_append_value_name (cmd->dep_var, &res->y1, &sv1); - - tab_text (t, 2, heading_rows, TAB_LEFT, ds_cstr (&sv0)); - tab_text (t, 2, heading_rows + 1, TAB_LEFT, ds_cstr (&sv1)); - - tab_text (t, heading_columns, 2, 0, ds_cstr (&sv0)); - tab_text (t, heading_columns + 1, 2, 0, ds_cstr (&sv1)); - - ds_destroy (&sv0); - ds_destroy (&sv1); - - tab_double (t, heading_columns, 3, 0, res->tn, NULL, RC_WEIGHT); - tab_double (t, heading_columns + 1, 4, 0, res->tp, NULL, RC_WEIGHT); - - tab_double (t, heading_columns + 1, 3, 0, res->fp, NULL, RC_WEIGHT); - tab_double (t, heading_columns, 4, 0, res->fn, NULL, RC_WEIGHT); - - tab_double (t, heading_columns + 2, 3, 0, 100 * res->tn / (res->tn + res->fp), NULL, RC_OTHER); - tab_double (t, heading_columns + 2, 4, 0, 100 * res->tp / (res->tp + res->fn), NULL, RC_OTHER); - - tab_double (t, heading_columns + 2, 5, 0, - 100 * (res->tp + res->tn) / (res->tp + res->tn + res->fp + res->fn), NULL, RC_OTHER); + pivot_dimension_create (table, PIVOT_AXIS_ROW, N_("Step"), N_("Step 1")); + struct entry + { + int pred_idx; + int obs_idx; + double x; + } + entries[] = { + { 0, 0, res->tn }, + { 0, 1, res->fn }, + { 1, 0, res->fp }, + { 1, 1, res->tp }, + { 2, 0, 100 * res->tn / (res->tn + res->fp) }, + { 2, 1, 100 * res->tp / (res->tp + res->fn) }, + { 2, 2, + 100 * (res->tp + res->tn) / (res->tp + res->tn + res->fp + res->fn)}, + }; + for (size_t i = 0; i < sizeof entries / sizeof *entries; i++) + { + const struct entry *e = &entries[i]; + pivot_table_put3 (table, e->pred_idx, e->obs_idx, 0, + pivot_value_new_number (e->x)); + } - tab_submit (t); + pivot_table_submit (table); } diff --git a/src/language/stats/mann-whitney.c b/src/language/stats/mann-whitney.c index e117cc366c..ad3a95733e 100644 --- a/src/language/stats/mann-whitney.c +++ b/src/language/stats/mann-whitney.c @@ -29,7 +29,11 @@ #include "libpspp/cast.h" #include "libpspp/misc.h" #include "math/sort.h" -#include "output/tab.h" +#include "output/pivot-table.h" + +#include "gettext.h" +#define N_(msgid) msgid +#define _(msgid) gettext (msgid) /* Calculates the adjustment necessary for tie compensation */ static void @@ -50,8 +54,9 @@ struct mw double z; }; -static void show_ranks_box (const struct n_sample_test *nst, const struct mw *mw); -static void show_statistics_box (const struct n_sample_test *nst, const struct mw *mw, bool exact); +static void show_ranks_box (const struct n_sample_test *, const struct mw *); +static void show_statistics_box (const struct n_sample_test *, + const struct mw *); @@ -79,7 +84,7 @@ mann_whitney_execute (const struct dataset *ds, struct casereader *input, enum mv_class exclude, const struct npar_test *test, - bool exact, + bool exact UNUSED, double timer UNUSED) { int i; @@ -166,157 +171,104 @@ mann_whitney_execute (const struct dataset *ds, casereader_destroy (input); show_ranks_box (nst, mw); - show_statistics_box (nst, mw, exact); + show_statistics_box (nst, mw); free (mw); } - - -#include "gettext.h" -#define _(msgid) gettext (msgid) - static void show_ranks_box (const struct n_sample_test *nst, const struct mw *mwv) { - int i; - const int row_headers = 1; - const int column_headers = 2; - struct tab_table *table = - tab_create (row_headers + 7, column_headers + nst->n_vars); - - struct string g1str, g2str;; - ds_init_empty (&g1str); - var_append_value_name (nst->indep_var, &nst->val1, &g1str); - - ds_init_empty (&g2str); - var_append_value_name (nst->indep_var, &nst->val2, &g2str); - - tab_headers (table, row_headers, 0, column_headers, 0); - - tab_title (table, _("Ranks")); - - /* Vertical lines inside the box */ - tab_box (table, 1, 0, -1, TAL_1, - row_headers, 0, tab_nc (table) - 1, tab_nr (table) - 1 ); - - /* Box around the table */ - tab_box (table, TAL_2, TAL_2, -1, -1, - 0, 0, tab_nc (table) - 1, tab_nr (table) - 1 ); - - tab_hline (table, TAL_2, 0, tab_nc (table) -1, column_headers); - tab_vline (table, TAL_2, row_headers, 0, tab_nr (table) - 1); - - tab_hline (table, TAL_1, row_headers, tab_nc (table) -1, 1); - - tab_text (table, 1, 1, TAT_TITLE | TAB_CENTER, ds_cstr (&g1str)); - tab_text (table, 2, 1, TAT_TITLE | TAB_CENTER, ds_cstr (&g2str)); - tab_text (table, 3, 1, TAT_TITLE | TAB_CENTER, _("Total")); - tab_joint_text (table, 1, 0, 3, 0, - TAT_TITLE | TAB_CENTER, _("N")); - tab_vline (table, TAL_2, 4, 0, tab_nr (table) - 1); - - tab_text (table, 4, 1, TAT_TITLE | TAB_CENTER, ds_cstr (&g1str)); - tab_text (table, 5, 1, TAT_TITLE | TAB_CENTER, ds_cstr (&g2str)); - tab_joint_text (table, 4, 0, 5, 0, - TAT_TITLE | TAB_CENTER, _("Mean Rank")); - tab_vline (table, TAL_2, 6, 0, tab_nr (table) - 1); - - tab_text (table, 6, 1, TAT_TITLE | TAB_CENTER, ds_cstr (&g1str)); - tab_text (table, 7, 1, TAT_TITLE | TAB_CENTER, ds_cstr (&g2str)); - tab_joint_text (table, 6, 0, 7, 0, - TAT_TITLE | TAB_CENTER, _("Sum of Ranks")); - - ds_destroy (&g1str); - ds_destroy (&g2str); - - for (i = 0 ; i < nst->n_vars ; ++i) + struct pivot_table *table = pivot_table_create (N_("Ranks")); + + pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Statistics"), + N_("N"), PIVOT_RC_COUNT, + N_("Mean Rank"), PIVOT_RC_OTHER, + N_("Sum of Ranks"), PIVOT_RC_OTHER); + + struct pivot_dimension *indep = pivot_dimension_create__ ( + table, PIVOT_AXIS_ROW, pivot_value_new_variable (nst->indep_var)); + pivot_category_create_leaf (indep->root, + pivot_value_new_var_value (nst->indep_var, + &nst->val1)); + pivot_category_create_leaf (indep->root, + pivot_value_new_var_value (nst->indep_var, + &nst->val2)); + pivot_category_create_leaves (indep->root, N_("Total")); + + struct pivot_dimension *dep = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Dependent Variables")); + + for (size_t i = 0 ; i < nst->n_vars ; ++i) { const struct mw *mw = &mwv[i]; - tab_text (table, 0, column_headers + i, TAT_TITLE, - var_to_string (nst->vars[i])); - - tab_double (table, 1, column_headers + i, 0, - mw->n[0], NULL, RC_OTHER); - - tab_double (table, 2, column_headers + i, 0, - mw->n[1], NULL, RC_OTHER); - - tab_double (table, 3, column_headers + i, 0, - mw->n[1] + mw->n[0], NULL, RC_OTHER); - /* Mean Ranks */ - tab_double (table, 4, column_headers + i, 0, - mw->rank_sum[0] / mw->n[0], NULL, RC_OTHER); - - tab_double (table, 5, column_headers + i, 0, - mw->rank_sum[1] / mw->n[1], NULL, RC_OTHER); - - /* Sum of Ranks */ - tab_double (table, 6, column_headers + i, 0, - mw->rank_sum[0], NULL, RC_OTHER); - - tab_double (table, 7, column_headers + i, 0, - mw->rank_sum[1], NULL, RC_OTHER); + int dep_idx = pivot_category_create_leaf ( + dep->root, pivot_value_new_variable (nst->vars[i])); + + struct entry + { + int stat_idx; + int indep_idx; + double x; + } + entries[] = { + /* N. */ + { 0, 0, mw->n[0] }, + { 0, 1, mw->n[1] }, + { 0, 2, mw->n[0] + mw->n[1] }, + + /* Mean Rank. */ + { 1, 0, mw->rank_sum[0] / mw->n[0] }, + { 1, 1, mw->rank_sum[1] / mw->n[1] }, + + /* Sum of Ranks. */ + { 2, 0, mw->rank_sum[0] }, + { 2, 1, mw->rank_sum[1] }, + }; + + for (size_t j = 0; j < sizeof entries / sizeof *entries; j++) + { + const struct entry *e = &entries[j]; + pivot_table_put3 (table, e->stat_idx, e->indep_idx, dep_idx, + pivot_value_new_number (e->x)); + } } - tab_submit (table); + pivot_table_submit (table); } static void -show_statistics_box (const struct n_sample_test *nst, const struct mw *mwv, bool exact) +show_statistics_box (const struct n_sample_test *nst, const struct mw *mwv) { - int i; - const int row_headers = 1; - const int column_headers = 1; - struct tab_table *table = - tab_create (row_headers + (exact ? 6 : 4), column_headers + nst->n_vars); - - tab_headers (table, row_headers, 0, column_headers, 0); + struct pivot_table *table = pivot_table_create (N_("Test Statistics")); - tab_title (table, _("Test Statistics")); + pivot_dimension_create ( + table, PIVOT_AXIS_COLUMN, N_("Statistics"), + _("Mann-Whitney U"), PIVOT_RC_OTHER, + _("Wilcoxon W"), PIVOT_RC_OTHER, + _("Z"), PIVOT_RC_OTHER, + _("Asymp. Sig. (2-tailed)"), PIVOT_RC_SIGNIFICANCE); - /* Vertical lines inside the box */ - tab_box (table, 1, 0, -1, TAL_1, - row_headers, 0, tab_nc (table) - 1, tab_nr (table) - 1 ); + struct pivot_dimension *variables = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Variables")); - /* Box around the table */ - tab_box (table, TAL_2, TAL_2, -1, -1, - 0, 0, tab_nc (table) - 1, tab_nr (table) - 1 ); - - tab_hline (table, TAL_2, 0, tab_nc (table) -1, column_headers); - tab_vline (table, TAL_2, row_headers, 0, tab_nr (table) - 1); - - tab_text (table, 1, 0, TAT_TITLE | TAB_CENTER, _("Mann-Whitney U")); - tab_text (table, 2, 0, TAT_TITLE | TAB_CENTER, _("Wilcoxon W")); - tab_text (table, 3, 0, TAT_TITLE | TAB_CENTER, _("Z")); - tab_text (table, 4, 0, TAT_TITLE | TAB_CENTER, _("Asymp. Sig. (2-tailed)")); - - if (exact) - { - tab_text (table, 5, 0, TAT_TITLE | TAB_CENTER, _("Exact Sig. (2-tailed)")); - tab_text (table, 6, 0, TAT_TITLE | TAB_CENTER, _("Point Probability")); - } - - for (i = 0 ; i < nst->n_vars ; ++i) + for (size_t i = 0 ; i < nst->n_vars ; ++i) { const struct mw *mw = &mwv[i]; - tab_text (table, 0, column_headers + i, TAT_TITLE, - var_to_string (nst->vars[i])); - - tab_double (table, 1, column_headers + i, 0, - mw->u, NULL, RC_OTHER); - - tab_double (table, 2, column_headers + i, 0, - mw->w, NULL, RC_OTHER); - - tab_double (table, 3, column_headers + i, 0, - mw->z, NULL, RC_OTHER); - - tab_double (table, 4, column_headers + i, 0, - 2.0 * gsl_cdf_ugaussian_P (mw->z), NULL, RC_PVALUE); + int row = pivot_category_create_leaf ( + variables->root, pivot_value_new_variable (nst->vars[i])); + + double entries[] = { + mw->u, + mw->w, + mw->z, + 2.0 * gsl_cdf_ugaussian_P (mw->z), + }; + for (size_t i = 0; i < sizeof entries / sizeof *entries; i++) + pivot_table_put2 (table, i, row, pivot_value_new_number (entries[i])); } - tab_submit (table); + pivot_table_submit (table); } diff --git a/src/language/stats/mcnemar.c b/src/language/stats/mcnemar.c index d3f48192fa..0456b909c5 100644 --- a/src/language/stats/mcnemar.c +++ b/src/language/stats/mcnemar.c @@ -29,7 +29,7 @@ #include "data/variable.h" #include "language/stats/npar.h" #include "libpspp/str.h" -#include "output/tab.h" +#include "output/pivot-table.h" #include "libpspp/message.h" #include "gl/minmax.h" @@ -38,6 +38,7 @@ #include "data/value.h" #include "gettext.h" +#define N_(msgid) msgid #define _(msgid) gettext (msgid) @@ -155,142 +156,93 @@ mcnemar_execute (const struct dataset *ds, free (mc); } +static char * +make_pair_name (const variable_pair *pair) +{ + return xasprintf ("%s & %s", var_to_string ((*pair)[0]), + var_to_string ((*pair)[1])); +} static void output_freq_table (variable_pair *vp, const struct mcnemar *param, const struct dictionary *dict) { - const int header_rows = 2; - const int header_cols = 1; - - struct tab_table *table = tab_create (header_cols + 2, header_rows + 2); - - const struct fmt_spec *wfmt = dict_get_weight_format (dict); - - - struct string pair_name; - struct string val1str ; - struct string val0str ; - - tab_set_format (table, RC_WEIGHT, wfmt); - - ds_init_empty (&val0str); - ds_init_empty (&val1str); - - var_append_value_name ((*vp)[0], ¶m->val0, &val0str); - var_append_value_name ((*vp)[1], ¶m->val1, &val1str); - - ds_init_cstr (&pair_name, var_to_string ((*vp)[0])); - ds_put_cstr (&pair_name, " & "); - ds_put_cstr (&pair_name, var_to_string ((*vp)[1])); - - tab_title (table, "%s", ds_cstr (&pair_name)); - - ds_destroy (&pair_name); + struct pivot_table *table = pivot_table_create__ ( + pivot_value_new_user_text_nocopy (make_pair_name (vp))); + pivot_table_set_weight_var (table, dict_get_weight (dict)); - tab_headers (table, header_cols, 0, header_rows, 0); - - /* Vertical lines inside the box */ - tab_box (table, 0, 0, -1, TAL_1, - 1, 0, tab_nc (table) - 1, tab_nr (table) - 1 ); - - /* Box around entire table */ - tab_box (table, TAL_2, TAL_2, -1, -1, - 0, 0, tab_nc (table) - 1, tab_nr (table) - 1 ); - - tab_vline (table, TAL_2, header_cols, 0, tab_nr (table) - 1); - tab_hline (table, TAL_2, 0, tab_nc (table) - 1, header_rows); - - tab_text (table, 0, 0, TAB_CENTER, var_to_string ((*vp)[0])); - - tab_joint_text (table, 1, 0, 2, 0, TAB_CENTER, var_to_string ((*vp)[1])); - tab_hline (table, TAL_1, 1, tab_nc (table) - 1, 1); - - - tab_text (table, 0, header_rows + 0, TAB_LEFT, ds_cstr (&val0str)); - tab_text (table, 0, header_rows + 1, TAB_LEFT, ds_cstr (&val1str)); - - tab_text (table, header_cols + 0, 1, TAB_LEFT, ds_cstr (&val0str)); - tab_text (table, header_cols + 1, 1, TAB_LEFT, ds_cstr (&val1str)); - - tab_double (table, header_cols + 0, header_rows + 0, TAB_RIGHT, param->n00, NULL, RC_WEIGHT); - tab_double (table, header_cols + 0, header_rows + 1, TAB_RIGHT, param->n01, NULL, RC_WEIGHT); - tab_double (table, header_cols + 1, header_rows + 0, TAB_RIGHT, param->n10, NULL, RC_WEIGHT); - tab_double (table, header_cols + 1, header_rows + 1, TAB_RIGHT, param->n11, NULL, RC_WEIGHT); + struct pivot_dimension *vars[2]; + for (int i = 0; i < 2; i++) + { + vars[i] = pivot_dimension_create__ ( + table, i ? PIVOT_AXIS_COLUMN : PIVOT_AXIS_ROW, + pivot_value_new_variable ((*vp)[i])); + vars[i]->root->show_label = true; + + for (int j = 0; j < 2; j++) + { + const union value *val = j ? ¶m->val1 : ¶m->val0; + pivot_category_create_leaf_rc ( + vars[i]->root, pivot_value_new_var_value ((*vp)[0], val), + PIVOT_RC_COUNT); + } + } - tab_submit (table); + struct entry + { + int idx0; + int idx1; + double x; + } + entries[] = { + { 0, 0, param->n00 }, + { 1, 0, param->n01 }, + { 0, 1, param->n10 }, + { 1, 1, param->n11 }, + }; + for (size_t i = 0; i < sizeof entries / sizeof *entries; i++) + { + const struct entry *e = &entries[i]; + pivot_table_put2 (table, e->idx0, e->idx1, + pivot_value_new_number (e->x)); + } - ds_destroy (&val0str); - ds_destroy (&val1str); + pivot_table_submit (table); } - static void output_statistics_table (const struct two_sample_test *t2s, const struct mcnemar *mc, const struct dictionary *dict) { - int i; - - struct tab_table *table = tab_create (5, t2s->n_pairs + 1); - - const struct fmt_spec *wfmt = dict_get_weight_format (dict); - - tab_title (table, _("Test Statistics")); - tab_set_format (table, RC_WEIGHT, wfmt); - - tab_headers (table, 0, 1, 0, 1); - - tab_hline (table, TAL_2, 0, tab_nc (table) - 1, 1); - tab_vline (table, TAL_2, 1, 0, tab_nr (table) - 1); + struct pivot_table *table = pivot_table_create (N_("Test Statistics")); + pivot_table_set_weight_var (table, dict_get_weight (dict)); + pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Statistics"), + N_("N"), PIVOT_RC_COUNT, + N_("Exact Sig. (2-tailed)"), PIVOT_RC_SIGNIFICANCE, + N_("Exact Sig. (1-tailed)"), PIVOT_RC_SIGNIFICANCE, + N_("Point Probability"), PIVOT_RC_OTHER); - /* Vertical lines inside the box */ - tab_box (table, -1, -1, -1, TAL_1, - 0, 0, - tab_nc (table) - 1, tab_nr (table) - 1); + struct pivot_dimension *pairs = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Pairs")); - /* Box around entire table */ - tab_box (table, TAL_2, TAL_2, -1, -1, - 0, 0, tab_nc (table) - 1, - tab_nr (table) - 1); - - tab_text (table, 1, 0, TAT_TITLE | TAB_CENTER, - _("N")); - - tab_text (table, 2, 0, TAT_TITLE | TAB_CENTER, - _("Exact Sig. (2-tailed)")); - - tab_text (table, 3, 0, TAT_TITLE | TAB_CENTER, - _("Exact Sig. (1-tailed)")); - - tab_text (table, 4, 0, TAT_TITLE | TAB_CENTER, - _("Point Probability")); - - for (i = 0 ; i < t2s->n_pairs; ++i) + for (size_t i = 0 ; i < t2s->n_pairs; ++i) { - double sig; variable_pair *vp = &t2s->pairs[i]; - - struct string pair_name; - ds_init_cstr (&pair_name, var_to_string ((*vp)[0])); - ds_put_cstr (&pair_name, " & "); - ds_put_cstr (&pair_name, var_to_string ((*vp)[1])); - - tab_text (table, 0, 1 + i, TAB_LEFT, ds_cstr (&pair_name)); - ds_destroy (&pair_name); - - tab_double (table, 1, 1 + i, TAB_RIGHT, mc[i].n00 + mc[i].n01 + mc[i].n10 + mc[i].n11, NULL, RC_WEIGHT); - - sig = gsl_cdf_binomial_P (mc[i].n01, 0.5, mc[i].n01 + mc[i].n10); - - tab_double (table, 2, 1 + i, TAB_RIGHT, 2 * sig, NULL, RC_PVALUE); - tab_double (table, 3, 1 + i, TAB_RIGHT, sig, NULL, RC_PVALUE); - - tab_double (table, 4, 1 + i, TAB_RIGHT, gsl_ran_binomial_pdf (mc[i].n01, 0.5, mc[i].n01 + mc[i].n10), - NULL, RC_OTHER); + int pair_idx = pivot_category_create_leaf ( + pairs->root, pivot_value_new_user_text_nocopy (make_pair_name (vp))); + + double n = mc[i].n00 + mc[i].n01 + mc[i].n10 + mc[i].n11; + double sig = gsl_cdf_binomial_P (mc[i].n01, 0.5, mc[i].n01 + mc[i].n10); + double point = gsl_ran_binomial_pdf (mc[i].n01, 0.5, + mc[i].n01 + mc[i].n10); + double entries[] = { n, 2.0 * sig, sig, point }; + for (size_t j = 0; j < sizeof entries / sizeof *entries; j++) + pivot_table_put2 (table, j, pair_idx, + pivot_value_new_number (entries[j])); } - tab_submit (table); + pivot_table_submit (table); } diff --git a/src/language/stats/means.c b/src/language/stats/means.c index df747fb5d0..7e7642adf1 100644 --- a/src/language/stats/means.c +++ b/src/language/stats/means.c @@ -35,7 +35,7 @@ #include "math/interaction.h" #include "math/moments.h" -#include "output/tab.h" +#include "output/pivot-table.h" #include @@ -834,7 +834,8 @@ is_missing (const struct means *cmd, return false; } -static void output_case_processing_summary (const struct mtable *); +static void output_case_processing_summary (const struct mtable *, + const struct variable *wv); static void output_report (const struct means *, int, const struct mtable *); @@ -1033,7 +1034,7 @@ run_means (struct means *cmd, struct casereader *input, int i; const struct mtable *table = &cmd->table[t]; - output_case_processing_summary (table); + output_case_processing_summary (table, wv); for (i = 0; i < table->n_layers; ++i) { @@ -1047,201 +1048,143 @@ run_means (struct means *cmd, struct casereader *input, static void -output_case_processing_summary (const struct mtable *table) +output_case_processing_summary (const struct mtable *mt, + const struct variable *wv) { - int i, v; - const int heading_columns = 1; - const int heading_rows = 3; - struct tab_table *t; - - const int nr = heading_rows + table->n_layers * table->n_dep_vars; - const int nc = 7; - - t = tab_create (nc, nr); - tab_title (t, _("Case Processing Summary")); - - tab_headers (t, heading_columns, 0, heading_rows, 0); - - tab_box (t, TAL_2, TAL_2, -1, TAL_1, 0, 0, nc - 1, nr - 1); - - tab_hline (t, TAL_2, 0, nc - 1, heading_rows); - tab_vline (t, TAL_2, heading_columns, 0, nr - 1); - - - tab_joint_text (t, heading_columns, 0, - nc - 1, 0, TAB_CENTER | TAT_TITLE, _("Cases")); - - tab_joint_text (t, 1, 1, 2, 1, TAB_CENTER | TAT_TITLE, _("Included")); - tab_joint_text (t, 3, 1, 4, 1, TAB_CENTER | TAT_TITLE, _("Excluded")); - tab_joint_text (t, 5, 1, 6, 1, TAB_CENTER | TAT_TITLE, _("Total")); + struct pivot_table *table = pivot_table_create ( + N_("Case Processing Summary")); + pivot_table_set_weight_var (table, wv); - tab_hline (t, TAL_1, heading_columns, nc - 1, 1); - tab_hline (t, TAL_1, heading_columns, nc - 1, 2); + pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Statistics"), + N_("N"), PIVOT_RC_COUNT, + N_("Percent"), PIVOT_RC_PERCENT); + pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Cases"), + N_("Included"), N_("Excluded"), N_("Total")) + ->root->show_label = true; + struct pivot_dimension *tables = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Tables")); - for (i = 0; i < 3; ++i) - { - tab_text (t, heading_columns + i * 2, 2, TAB_CENTER | TAT_TITLE, - _("N")); - tab_text (t, heading_columns + i * 2 + 1, 2, TAB_CENTER | TAT_TITLE, - _("Percent")); - } - - for (v = 0; v < table->n_dep_vars; ++v) + for (size_t v = 0; v < mt->n_dep_vars; ++v) { - const struct variable *var = table->dep_vars[v]; - const char *dv_name = var_to_string (var); - for (i = 0; i < table->n_layers; ++i) + const struct variable *var = mt->dep_vars[v]; + for (size_t i = 0; i < mt->n_layers; ++i) { - const int row = v * table->n_layers + i; - const struct interaction *iact = table->interactions[i]; - casenumber n_total; - - struct string str; - ds_init_cstr (&str, dv_name); - ds_put_cstr (&str, ": "); + const int row = v * mt->n_layers + i; + const struct interaction *iact = mt->interactions[i]; + struct string str = DS_EMPTY_INITIALIZER; + ds_put_format (&str, "%s: ", var_to_string (var)); interaction_to_string (iact, &str); - - tab_text (t, 0, row + heading_rows, - TAB_LEFT | TAT_TITLE, ds_cstr (&str)); - - - n_total = table->summary[row].missing + - table->summary[row].non_missing; - - tab_double (t, 1, row + heading_rows, - 0, table->summary[row].non_missing, NULL, RC_INTEGER); - - tab_text_format (t, 2, row + heading_rows, - 0, _("%g%%"), - table->summary[row].non_missing / (double) n_total * 100.0); - - - tab_double (t, 3, row + heading_rows, - 0, table->summary[row].missing, NULL, RC_INTEGER); - - - tab_text_format (t, 4, row + heading_rows, - 0, _("%g%%"), - table->summary[row].missing / (double) n_total * 100.0); - - - tab_double (t, 5, row + heading_rows, - 0, table->summary[row].missing + - table->summary[row].non_missing, NULL, RC_INTEGER); - - tab_text_format (t, 6, row + heading_rows, - 0, _("%g%%"), - n_total / (double) n_total * 100.0); - - - ds_destroy (&str); + int table_idx = pivot_category_create_leaf ( + tables->root, pivot_value_new_user_text_nocopy ( + ds_steal_cstr (&str))); + + const struct summary *s = &mt->summary[row]; + double n_total = s->missing + s->non_missing; + struct entry + { + int stat_idx; + int case_idx; + double x; + } + entries[] = + { + { 0, 0, s->non_missing }, + { 1, 0, s->non_missing / n_total * 100.0 }, + { 0, 1, s->missing }, + { 1, 1, s->missing / n_total * 100.0 }, + { 0, 2, n_total }, + { 1, 2, 100.0 }, + }; + + for (size_t j = 0; j < sizeof entries / sizeof *entries; j++) + { + const struct entry *e = &entries[j]; + pivot_table_put3 (table, e->stat_idx, e->case_idx, table_idx, + pivot_value_new_number (e->x)); + } } } - tab_submit (t); + pivot_table_submit (table); } - static void -output_report (const struct means *cmd, int iact_idx, - const struct mtable *table) +create_interaction_dimensions (struct pivot_table *table, + const struct categoricals *cats, + const struct interaction *iact) { - int grp; - int i; - - const struct interaction *iact = table->interactions[iact_idx]; - - const int heading_columns = 1 + iact->n_vars; - const int heading_rows = 1; - struct tab_table *t; - - const int n_cats = categoricals_n_count (table->cats, iact_idx); - - const int nr = n_cats * table->n_dep_vars + heading_rows; - - const int nc = heading_columns + cmd->n_cells; - - t = tab_create (nc, nr); - tab_title (t, _("Report")); - - tab_headers (t, heading_columns, 0, heading_rows, 0); - - tab_box (t, TAL_2, TAL_2, -1, TAL_1, 0, 0, nc - 1, nr - 1); - - tab_hline (t, TAL_2, 0, nc - 1, heading_rows); - tab_vline (t, TAL_2, heading_columns, 0, nr - 1); - - for (i = 0; i < iact->n_vars; ++i) - { - tab_text (t, 1 + i, 0, TAB_CENTER | TAT_TITLE, - var_to_string (iact->vars[i])); - } - - for (i = 0; i < cmd->n_cells; ++i) + for (size_t i = iact->n_vars; i-- > 0; ) { - tab_text (t, heading_columns + i, 0, - TAB_CENTER | TAT_TITLE, - gettext (cell_spec[cmd->cells[i]].title)); + const struct variable *var = iact->vars[i]; + struct pivot_dimension *d = pivot_dimension_create__ ( + table, PIVOT_AXIS_ROW, pivot_value_new_variable (var)); + d->root->show_label = true; + + size_t n; + union value *values = categoricals_get_var_values (cats, var, &n); + for (size_t j = 0; j < n; j++) + pivot_category_create_leaf ( + d->root, pivot_value_new_var_value (var, &values[j])); } +} +static void +output_report (const struct means *cmd, int iact_idx, + const struct mtable *mt) +{ + struct pivot_table *table = pivot_table_create (N_("Report")); + table->omit_empty = true; - for (i = 0; i < n_cats; ++i) - { - int v, dv; - const struct ccase *c = - categoricals_get_case_by_category_real (table->cats, iact_idx, i); - - for (dv = 0; dv < table->n_dep_vars; ++dv) - { - tab_text (t, 0, - heading_rows + dv * n_cats, - TAB_RIGHT | TAT_TITLE, - var_to_string (table->dep_vars[dv]) - ); - - if ( dv > 0) - tab_hline (t, TAL_1, 0, nc - 1, heading_rows + dv * n_cats); + struct pivot_dimension *statistics = pivot_dimension_create ( + table, PIVOT_AXIS_COLUMN, N_("Statistics")); + for (int i = 0; i < cmd->n_cells; ++i) + pivot_category_create_leaf ( + statistics->root, pivot_value_new_text (cell_spec[cmd->cells[i]].title)); - for (v = 0; v < iact->n_vars; ++v) - { - const struct variable *var = iact->vars[v]; - const union value *val = case_data (c, var); - struct string str; - ds_init_empty (&str); - var_append_value_name (var, val, &str); + const struct interaction *iact = mt->interactions[iact_idx]; + create_interaction_dimensions (table, mt->cats, iact); - tab_text (t, 1 + v, heading_rows + dv * n_cats + i, - TAB_RIGHT | TAT_TITLE, ds_cstr (&str)); + struct pivot_dimension *dep_dim = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Dependent Variables")); - ds_destroy (&str); - } - } - } + size_t *indexes = xnmalloc (table->n_dimensions, sizeof *indexes); - for (grp = 0; grp < n_cats; ++grp) + size_t n_cats = categoricals_n_count (mt->cats, iact_idx); + for (size_t v = 0; v < mt->n_dep_vars; ++v) { - int dv; - struct per_cat_data *per_cat_data = - categoricals_get_user_data_by_category_real (table->cats, iact_idx, grp); - - for (dv = 0; dv < table->n_dep_vars; ++dv) - { - const struct per_var_data *pvd = &per_cat_data->pvd[dv]; - for (i = 0; i < cmd->n_cells; ++i) - { - const int csi = cmd->cells[i]; - const struct cell_spec *cs = &cell_spec[csi]; - - double result = cs->sd (pvd, pvd->cell_stats[i]); - - tab_double (t, heading_columns + i, - heading_rows + grp + dv * n_cats, - 0, result, NULL, RC_OTHER); - } - } + indexes[table->n_dimensions - 1] = pivot_category_create_leaf ( + dep_dim->root, pivot_value_new_variable (mt->dep_vars[v])); + + for (size_t i = 0; i < n_cats; ++i) + { + for (size_t j = 0; j < iact->n_vars; j++) + { + int idx = categoricals_get_value_index_by_category_real ( + mt->cats, iact_idx, i, j); + indexes[table->n_dimensions - 2 - j] = idx; + } + + struct per_cat_data *per_cat_data + = categoricals_get_user_data_by_category_real ( + mt->cats, iact_idx, i); + + const struct per_var_data *pvd = &per_cat_data->pvd[v]; + for (int stat_idx = 0; stat_idx < cmd->n_cells; ++stat_idx) + { + indexes[0] = stat_idx; + const int csi = cmd->cells[stat_idx]; + const struct cell_spec *cs = &cell_spec[csi]; + + double result = cs->sd (pvd, pvd->cell_stats[stat_idx]); + pivot_table_put (table, indexes, table->n_dimensions, + pivot_value_new_number (result)); + } + } } + free (indexes); - tab_submit (t); + pivot_table_submit (table); } + diff --git a/src/language/stats/median.c b/src/language/stats/median.c index 7bb87f92f2..0f1ecd2948 100644 --- a/src/language/stats/median.c +++ b/src/language/stats/median.c @@ -41,9 +41,10 @@ #include "libpspp/str.h" #include "libpspp/misc.h" -#include "output/tab.h" +#include "output/pivot-table.h" #include "gettext.h" +#define N_(msgid) msgid #define _(msgid) gettext (msgid) @@ -301,157 +302,85 @@ median_execute (const struct dataset *ds, static void show_frequencies (const struct n_sample_test *nst, const struct results *results, int n_vals, const struct dictionary *dict) { - const struct fmt_spec *wfmt = dict_get_weight_format (dict); - - int i; - int v; - - const int row_headers = 2; - const int column_headers = 2; - const int nc = row_headers + n_vals; - const int nr = column_headers + nst->n_vars * 2; - - struct tab_table *table = tab_create (nc, nr); - tab_set_format (table, RC_WEIGHT, wfmt); - - tab_headers (table, row_headers, 0, column_headers, 0); - - tab_title (table, _("Frequencies")); - - /* Box around the table and vertical lines inside*/ - tab_box (table, TAL_2, TAL_2, -1, TAL_1, - 0, 0, tab_nc (table) - 1, tab_nr (table) - 1 ); - - tab_hline (table, TAL_2, 0, tab_nc (table) -1, column_headers); - tab_vline (table, TAL_2, row_headers, 0, tab_nr (table) - 1); - - tab_joint_text (table, - row_headers, 0, row_headers + n_vals - 1, 0, - TAT_TITLE | TAB_CENTER, var_to_string (nst->indep_var)); - - - tab_hline (table, TAL_1, row_headers, tab_nc (table) - 1, 1); - - - for (i = 0; i < n_vals; ++i) - { - const struct results *rs = results + 0; - struct string label; - ds_init_empty (&label); - - var_append_value_name (nst->indep_var, &rs->sorted_array[i]->val, - &label); - - tab_text (table, row_headers + i, 1, - TAT_TITLE | TAB_LEFT, ds_cstr (&label)); - - ds_destroy (&label); - } - - for (v = 0; v < nst->n_vars; ++v) + struct pivot_table *table = pivot_table_create (N_("Frequencies")); + pivot_table_set_weight_var (table, dict_get_weight (dict)); + + struct pivot_dimension *indep = pivot_dimension_create__ ( + table, PIVOT_AXIS_COLUMN, pivot_value_new_variable (nst->indep_var)); + indep->root->show_label = true; + for (int i = 0; i < n_vals; ++i) + pivot_category_create_leaf_rc ( + indep->root, pivot_value_new_var_value ( + nst->indep_var, &results->sorted_array[i]->val), PIVOT_RC_COUNT); + pivot_dimension_create (table, PIVOT_AXIS_ROW, N_("Statistics"), + N_("> Median"), N_("≤ Median")); + + struct pivot_dimension *dep = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Dependent Variables")); + + for (int v = 0; v < nst->n_vars; ++v) { const struct results *rs = &results[v]; - tab_text (table, 0, column_headers + v * 2, - TAT_TITLE | TAB_LEFT, var_to_string (rs->var) ); - - tab_text (table, 1, column_headers + v * 2, - TAT_TITLE | TAB_LEFT, _("> Median") ); - - tab_text (table, 1, column_headers + v * 2 + 1, - TAT_TITLE | TAB_LEFT, _("≤ Median") ); - if ( v > 0) - tab_hline (table, TAL_1, 0, tab_nc (table) - 1, column_headers + v * 2); - } - - for (v = 0; v < nst->n_vars; ++v) - { - int i; - const struct results *rs = &results[v]; + int dep_idx = pivot_category_create_leaf ( + dep->root, pivot_value_new_variable (rs->var)); - for (i = 0; i < n_vals; ++i) + for (int indep_idx = 0; indep_idx < n_vals; indep_idx++) { - const struct val_node *vn = rs->sorted_array[i]; - tab_double (table, row_headers + i, column_headers + v * 2, - 0, vn->gt, NULL, RC_WEIGHT); - - tab_double (table, row_headers + i, column_headers + v * 2 + 1, - 0, vn->le, NULL, RC_WEIGHT); + const struct val_node *vn = rs->sorted_array[indep_idx]; + pivot_table_put3 (table, indep_idx, 0, dep_idx, + pivot_value_new_number (vn->gt)); + pivot_table_put3 (table, indep_idx, 1, dep_idx, + pivot_value_new_number (vn->le)); } } - tab_submit (table); + pivot_table_submit (table); } - static void show_test_statistics (const struct n_sample_test *nst, const struct results *results, int n_vals, const struct dictionary *dict) { - const struct fmt_spec *wfmt = dict_get_weight_format (dict); - - int v; - - const int row_headers = 1; - const int column_headers = 1; - const int nc = row_headers + 5; - const int nr = column_headers + nst->n_vars; - - struct tab_table *table = tab_create (nc, nr); - tab_set_format (table, RC_WEIGHT, wfmt); - - tab_headers (table, row_headers, 0, column_headers, 0); - - tab_title (table, _("Test Statistics")); - + struct pivot_table *table = pivot_table_create (N_("Test Statistics")); + pivot_table_set_weight_var (table, dict_get_weight (dict)); - tab_box (table, TAL_2, TAL_2, -1, TAL_1, - 0, 0, tab_nc (table) - 1, tab_nr (table) - 1 ); + pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Statistics"), + N_("N"), PIVOT_RC_COUNT, + N_("Median"), + N_("Chi-Square"), PIVOT_RC_OTHER, + N_("df"), PIVOT_RC_COUNT, + N_("Asymp. Sig."), PIVOT_RC_SIGNIFICANCE); - tab_hline (table, TAL_2, 0, tab_nc (table) -1, column_headers); - tab_vline (table, TAL_2, row_headers, 0, tab_nr (table) - 1); + struct pivot_dimension *variables = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Variables")); - tab_text (table, row_headers + 0, 0, - TAT_TITLE | TAB_CENTER, _("N")); - - tab_text (table, row_headers + 1, 0, - TAT_TITLE | TAB_CENTER, _("Median")); - - tab_text (table, row_headers + 2, 0, - TAT_TITLE | TAB_CENTER, _("Chi-Square")); - - tab_text (table, row_headers + 3, 0, - TAT_TITLE | TAB_CENTER, _("df")); - - tab_text (table, row_headers + 4, 0, - TAT_TITLE | TAB_CENTER, _("Asymp. Sig.")); - - - for (v = 0; v < nst->n_vars; ++v) + for (int v = 0; v < nst->n_vars; ++v) { double df = n_vals - 1; const struct results *rs = &results[v]; - tab_text (table, 0, column_headers + v, - TAT_TITLE | TAB_LEFT, var_to_string (rs->var)); - - - tab_double (table, row_headers + 0, column_headers + v, - 0, rs->n, NULL, RC_WEIGHT); - - tab_double (table, row_headers + 1, column_headers + v, - 0, rs->median, NULL, RC_OTHER); - - tab_double (table, row_headers + 2, column_headers + v, - 0, rs->chisq, NULL, RC_OTHER); - - tab_double (table, row_headers + 3, column_headers + v, - 0, df, NULL, RC_WEIGHT); - tab_double (table, row_headers + 4, column_headers + v, - 0, gsl_cdf_chisq_Q (rs->chisq, df), NULL, RC_PVALUE); + int var_idx = pivot_category_create_leaf ( + variables->root, pivot_value_new_variable (rs->var)); + + double entries[] = { + rs->n, + rs->median, + rs->chisq, + df, + gsl_cdf_chisq_Q (rs->chisq, df), + }; + for (size_t i = 0; i < sizeof entries / sizeof *entries; i++) + { + struct pivot_value *value + = pivot_value_new_number (entries[i]); + if (i == 1) + value->numeric.format = *var_get_print_format (rs->var); + pivot_table_put2 (table, i, var_idx, value); + } } - tab_submit (table); + pivot_table_submit (table); } diff --git a/src/language/stats/npar-summary.c b/src/language/stats/npar-summary.c index 332486adc8..e45879565b 100644 --- a/src/language/stats/npar-summary.c +++ b/src/language/stats/npar-summary.c @@ -26,11 +26,12 @@ #include "data/format.h" #include "data/variable.h" #include "math/moments.h" -#include "output/tab.h" +#include "output/pivot-table.h" #include "gl/minmax.h" #include "gettext.h" +#define N_(msgid) msgid #define _(msgid) gettext (msgid) @@ -91,87 +92,42 @@ npar_summary_calc_descriptives (struct descriptives *desc, void do_summary_box (const struct descriptives *desc, const struct variable *const *vv, - int n_vars) + int n_vars, + const struct fmt_spec *wfmt) { - int v; - bool quartiles = false; + if (!desc) + return; - int col; - int columns = 1 ; - struct tab_table *table ; + struct pivot_table *table = pivot_table_create ( + N_("Descriptive Statistics")); + pivot_table_set_weight_format (table, wfmt); - if ( desc ) columns += 5; - if ( quartiles ) columns += 3; + pivot_dimension_create ( + table, PIVOT_AXIS_COLUMN, N_("Statistics"), + N_("N"), PIVOT_RC_COUNT, + N_("Mean"), PIVOT_RC_OTHER, + N_("Std. Deviation"), PIVOT_RC_OTHER, + N_("Minimum"), N_("Maximum")); - table = tab_create (columns, 2 + n_vars); + struct pivot_dimension *variables = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Variable")); - - tab_title (table, _("Descriptive Statistics")); - - tab_headers (table, 1, 0, 1, 0); - - tab_box (table, TAL_1, TAL_1, -1, TAL_1, - 0, 0, tab_nc (table) - 1, tab_nr(table) - 1 ); - - tab_hline (table, TAL_2, 0, tab_nc (table) -1, 2); - tab_vline (table, TAL_2, 1, 0, tab_nr (table) - 1); - - col = 1; - if ( desc ) + for (int v = 0; v < n_vars; ++v) { - tab_joint_text (table, col, 0, col, 1, TAT_TITLE | TAB_CENTER, - _("N")); - col++; - tab_joint_text (table, col, 0, col, 1, TAT_TITLE | TAB_CENTER, - _("Mean")); - col++; - tab_joint_text (table, col, 0, col, 1, TAT_TITLE | TAB_CENTER, - _("Std. Deviation")); - col++; - tab_joint_text (table, col, 0, col, 1, TAT_TITLE | TAB_CENTER, - _("Minimum")); - col++; - tab_joint_text (table, col, 0, col, 1, TAT_TITLE | TAB_CENTER, - _("Maximum")); - col++; - } + const struct variable *var = vv[v]; - if ( quartiles ) - { - tab_joint_text (table, col, 0, col + 2, 0, TAT_TITLE | TAB_CENTER, - _("Percentiles")); - tab_hline (table, TAL_1, col, col + 2, 1); - - tab_text (table, col, 1, TAT_TITLE | TAB_CENTER, - _("25th")); - col++; - tab_text (table, col, 1, TAT_TITLE | TAB_CENTER, - _("50th (Median)")); - col++; - tab_text (table, col, 1, TAT_TITLE | TAB_CENTER, - _("75th")); - col++; - } + int row = pivot_category_create_leaf (variables->root, + pivot_value_new_variable (var)); + double entries[] = { desc[v].n, desc[v].mean, desc[v].std_dev }; + for (size_t j = 0; j < sizeof entries / sizeof *entries; j++) + pivot_table_put2 (table, j, row, pivot_value_new_number (entries[j])); - for ( v = 0 ; v < n_vars ; ++v ) - { - const struct variable *var = vv[v]; - const struct fmt_spec *fmt = var_get_print_format (var); - - tab_text (table, 0, 2 + v, 0, var_to_string (var)); - - col = 1; - if (desc != NULL) - { - tab_double (table, col++, 2 + v, 0, desc[v].n, fmt, RC_OTHER); - tab_double (table, col++, 2 + v, 0, desc[v].mean, fmt, RC_OTHER); - tab_double (table, col++, 2 + v, 0, desc[v].std_dev, fmt, RC_OTHER); - tab_double (table, col++, 2 + v, 0, desc[v].min, fmt, RC_OTHER); - tab_double (table, col++, 2 + v, 0, desc[v].max, fmt, RC_OTHER); - } + union value extrema[2] = { { .f = desc[v].min }, { .f = desc[v].max } }; + for (size_t j = 0; j < 2; j++) + pivot_table_put2 (table, 3 + j, row, + pivot_value_new_var_value (var, &extrema[j])); } - - tab_submit (table); + pivot_table_submit (table); } diff --git a/src/language/stats/npar-summary.h b/src/language/stats/npar-summary.h index a78d1b7e2a..3955bd6411 100644 --- a/src/language/stats/npar-summary.h +++ b/src/language/stats/npar-summary.h @@ -22,6 +22,7 @@ struct variable ; struct casereader ; struct dictionary; +struct fmt_spec; struct descriptives { @@ -35,7 +36,8 @@ struct descriptives void do_summary_box (const struct descriptives *desc, const struct variable *const *vv, - int n_vars); + int n_vars, + const struct fmt_spec *wfmt); void npar_summary_calc_descriptives (struct descriptives *desc, struct casereader *input, diff --git a/src/language/stats/npar.c b/src/language/stats/npar.c index 071a02ee16..1d369eca44 100644 --- a/src/language/stats/npar.c +++ b/src/language/stats/npar.c @@ -553,7 +553,8 @@ npar_execute (struct casereader *input, if ( (specs->descriptives || specs->quartiles) && !taint_has_tainted_successor (casereader_get_taint (input)) ) - do_summary_box (summary_descriptives, specs->vv, specs->n_vars ); + do_summary_box (summary_descriptives, specs->vv, specs->n_vars, + dict_get_weight_format (dataset_dict (ds))); free (summary_descriptives); casereader_destroy (input); diff --git a/src/language/stats/oneway.c b/src/language/stats/oneway.c index d0a6e5d786..ef20cbafbf 100644 --- a/src/language/stats/oneway.c +++ b/src/language/stats/oneway.c @@ -44,7 +44,7 @@ #include "math/covariance.h" #include "math/levene.h" #include "math/moments.h" -#include "output/tab.h" +#include "output/pivot-table.h" #include "gettext.h" #define _(msgid) gettext (msgid) @@ -143,6 +143,7 @@ struct oneway_spec /* The weight variable */ const struct variable *wv; + const struct fmt_spec *wfmt; /* The confidence level for multiple comparisons */ double alpha; @@ -429,6 +430,7 @@ cmd_oneway (struct lexer *lexer, struct dataset *ds) oneway.missing_type = MISS_ANALYSIS; oneway.exclude = MV_ANY; oneway.wv = dict_get_weight (dict); + oneway.wfmt = dict_get_weight_format (dict); oneway.alpha = 0.05; oneway.posthoc = NULL; oneway.n_posthoc = 0; @@ -963,306 +965,220 @@ output_oneway (const struct oneway_spec *cmd, struct oneway_workspace *ws) static void show_anova_table (const struct oneway_spec *cmd, const struct oneway_workspace *ws) { - size_t i; - int n_cols =7; - size_t n_rows = cmd->n_vars * 3 + 1; + struct pivot_table *table = pivot_table_create (N_("ANOVA")); - struct tab_table *t = tab_create (n_cols, n_rows); + pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Statistics"), + N_("Sum of Squares"), PIVOT_RC_OTHER, + N_("df"), PIVOT_RC_INTEGER, + N_("Mean Square"), PIVOT_RC_OTHER, + N_("F"), PIVOT_RC_OTHER, + N_("Sig."), PIVOT_RC_SIGNIFICANCE); - tab_headers (t, 2, 0, 1, 0); + pivot_dimension_create (table, PIVOT_AXIS_ROW, N_("Type"), + N_("Between Groups"), N_("Within Groups"), + N_("Total")); - tab_box (t, - TAL_2, TAL_2, - -1, TAL_1, - 0, 0, - n_cols - 1, n_rows - 1); + struct pivot_dimension *variables = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Variables")); - tab_hline (t, TAL_2, 0, n_cols - 1, 1 ); - tab_vline (t, TAL_2, 2, 0, n_rows - 1); - tab_vline (t, TAL_0, 1, 0, 0); - - tab_text (t, 2, 0, TAB_CENTER | TAT_TITLE, _("Sum of Squares")); - tab_text (t, 3, 0, TAB_CENTER | TAT_TITLE, _("df")); - tab_text (t, 4, 0, TAB_CENTER | TAT_TITLE, _("Mean Square")); - tab_text (t, 5, 0, TAB_CENTER | TAT_TITLE, _("F")); - tab_text (t, 6, 0, TAB_CENTER | TAT_TITLE, _("Sig.")); - - - for (i = 0; i < cmd->n_vars; ++i) + for (size_t i = 0; i < cmd->n_vars; ++i) { - double n; - double df1, df2; - double msa; - const char *s = var_to_string (cmd->vars[i]); + int var_idx = pivot_category_create_leaf ( + variables->root, pivot_value_new_variable (cmd->vars[i])); + const struct per_var_ws *pvw = &ws->vws[i]; + double n; moments1_calculate (ws->dd_total[i]->mom, &n, NULL, NULL, NULL, NULL); - df1 = pvw->n_groups - 1; - df2 = n - pvw->n_groups; - msa = pvw->ssa / df1; - - tab_text (t, 0, i * 3 + 1, TAB_LEFT | TAT_TITLE, s); - tab_text (t, 1, i * 3 + 1, TAB_LEFT | TAT_TITLE, _("Between Groups")); - tab_text (t, 1, i * 3 + 2, TAB_LEFT | TAT_TITLE, _("Within Groups")); - tab_text (t, 1, i * 3 + 3, TAB_LEFT | TAT_TITLE, _("Total")); - - if (i > 0) - tab_hline (t, TAL_1, 0, n_cols - 1, i * 3 + 1); - - - /* Sums of Squares */ - tab_double (t, 2, i * 3 + 1, 0, pvw->ssa, NULL, RC_OTHER); - tab_double (t, 2, i * 3 + 3, 0, pvw->sst, NULL, RC_OTHER); - tab_double (t, 2, i * 3 + 2, 0, pvw->sse, NULL, RC_OTHER); - - - /* Degrees of freedom */ - tab_double (t, 3, i * 3 + 1, 0, df1, NULL, RC_INTEGER); - tab_double (t, 3, i * 3 + 2, 0, df2, NULL, RC_INTEGER); - tab_double (t, 3, i * 3 + 3, 0, n - 1, NULL, RC_INTEGER); + double df1 = pvw->n_groups - 1; + double df2 = n - pvw->n_groups; + double msa = pvw->ssa / df1; + double F = msa / pvw->mse ; - /* Mean Squares */ - tab_double (t, 4, i * 3 + 1, TAB_RIGHT, msa, NULL, RC_OTHER); - tab_double (t, 4, i * 3 + 2, TAB_RIGHT, pvw->mse, NULL, RC_OTHER); - - { - const double F = msa / pvw->mse ; - - /* The F value */ - tab_double (t, 5, i * 3 + 1, 0, F, NULL, RC_OTHER); - - /* The significance */ - tab_double (t, 6, i * 3 + 1, 0, gsl_cdf_fdist_Q (F, df1, df2), NULL, RC_PVALUE); - } + struct entry + { + int stat_idx; + int type_idx; + double x; + } + entries[] = { + /* Sums of Squares. */ + { 0, 0, pvw->ssa }, + { 0, 1, pvw->sse }, + { 0, 2, pvw->sst }, + /* Degrees of Freedom. */ + { 1, 0, df1 }, + { 1, 1, df2 }, + { 1, 2, n - 1 }, + /* Mean Squares. */ + { 2, 0, msa }, + { 2, 1, pvw->mse }, + /* F. */ + { 3, 0, F }, + /* Significance. */ + { 4, 0, gsl_cdf_fdist_Q (F, df1, df2) }, + }; + for (size_t j = 0; j < sizeof entries / sizeof *entries; j++) + { + const struct entry *e = &entries[j]; + pivot_table_put3 (table, e->stat_idx, e->type_idx, var_idx, + pivot_value_new_number (e->x)); + } } - tab_title (t, _("ANOVA")); - tab_submit (t); + pivot_table_submit (table); } - /* Show the descriptives table */ static void show_descriptives (const struct oneway_spec *cmd, const struct oneway_workspace *ws) { - size_t v; - int n_cols = 10; - struct tab_table *t; - int row; - - const double confidence = 0.95; - const double q = (1.0 - confidence) / 2.0; - - const struct fmt_spec *wfmt = cmd->wv ? var_get_print_format (cmd->wv) : &F_8_0; - - int n_rows = 2; - - for (v = 0; v < cmd->n_vars; ++v) - n_rows += ws->actual_number_of_groups + 1; - - t = tab_create (n_cols, n_rows); - tab_set_format (t, RC_WEIGHT, wfmt); - tab_headers (t, 2, 0, 2, 0); - - /* Put a frame around the entire box, and vertical lines inside */ - tab_box (t, - TAL_2, TAL_2, - -1, TAL_1, - 0, 0, - n_cols - 1, n_rows - 1); - - /* Underline headers */ - tab_hline (t, TAL_2, 0, n_cols - 1, 2); - tab_vline (t, TAL_2, 2, 0, n_rows - 1); - - tab_text (t, 2, 1, TAB_CENTER | TAT_TITLE, _("N")); - tab_text (t, 3, 1, TAB_CENTER | TAT_TITLE, _("Mean")); - tab_text (t, 4, 1, TAB_CENTER | TAT_TITLE, _("Std. Deviation")); - tab_text (t, 5, 1, TAB_CENTER | TAT_TITLE, _("Std. Error")); + if (!cmd->n_vars) + return; + const struct categoricals *cats = covariance_get_categoricals ( + ws->vws[0].cov); + struct pivot_table *table = pivot_table_create (N_("Descriptives")); + pivot_table_set_weight_format (table, cmd->wfmt); - tab_vline (t, TAL_0, 7, 0, 0); - tab_hline (t, TAL_1, 6, 7, 1); - tab_joint_text_format (t, 6, 0, 7, 0, TAB_CENTER | TAT_TITLE, - _("%g%% Confidence Interval for Mean"), - confidence*100.0); - - tab_text (t, 6, 1, TAB_CENTER | TAT_TITLE, _("Lower Bound")); - tab_text (t, 7, 1, TAB_CENTER | TAT_TITLE, _("Upper Bound")); - - tab_text (t, 8, 1, TAB_CENTER | TAT_TITLE, _("Minimum")); - tab_text (t, 9, 1, TAB_CENTER | TAT_TITLE, _("Maximum")); + const double confidence = 0.95; - tab_title (t, _("Descriptives")); + struct pivot_dimension *statistics = pivot_dimension_create ( + table, PIVOT_AXIS_COLUMN, N_("Statistics"), + N_("N"), PIVOT_RC_COUNT, N_("Mean"), N_("Std. Deviation"), + N_("Std. Error")); + struct pivot_category *interval = pivot_category_create_group__ ( + statistics->root, + pivot_value_new_text_format (N_("%g%% Confidence Interval for Mean"), + confidence * 100.0)); + pivot_category_create_leaves (interval, N_("Lower Bound"), + N_("Upper Bound")); + pivot_category_create_leaves (statistics->root, + N_("Minimum"), N_("Maximum")); + + struct pivot_dimension *indep_var = pivot_dimension_create__ ( + table, PIVOT_AXIS_ROW, pivot_value_new_variable (cmd->indep_var)); + indep_var->root->show_label = true; + size_t n; + union value *values = categoricals_get_var_values (cats, cmd->indep_var, &n); + for (size_t j = 0; j < n; j++) + pivot_category_create_leaf ( + indep_var->root, pivot_value_new_var_value (cmd->indep_var, &values[j])); + pivot_category_create_leaf ( + indep_var->root, pivot_value_new_text_format (N_("Total"))); + + struct pivot_dimension *dep_var = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Dependent Variable")); - row = 2; - for (v = 0; v < cmd->n_vars; ++v) + const double q = (1.0 - confidence) / 2.0; + for (int v = 0; v < cmd->n_vars; ++v) { - const char *s = var_to_string (cmd->vars[v]); - const struct fmt_spec *fmt = var_get_print_format (cmd->vars[v]); - - int count = 0; + int dep_var_idx = pivot_category_create_leaf ( + dep_var->root, pivot_value_new_variable (cmd->vars[v])); struct per_var_ws *pvw = &ws->vws[v]; const struct categoricals *cats = covariance_get_categoricals (pvw->cov); - tab_text (t, 0, row, TAB_LEFT | TAT_TITLE, s); - if ( v > 0) - tab_hline (t, TAL_1, 0, n_cols - 1, row); - + int count; for (count = 0; count < categoricals_n_total (cats); ++count) { - double T; - double n, mean, variance; - double std_dev, std_error ; - - struct string vstr; - - const struct ccase *gcc = categoricals_get_case_by_category (cats, count); - const struct descriptive_data *dd = categoricals_get_user_data_by_category (cats, count); + const struct descriptive_data *dd + = categoricals_get_user_data_by_category (cats, count); + double n, mean, variance; moments1_calculate (dd->mom, &n, &mean, &variance, NULL, NULL); - std_dev = sqrt (variance); - std_error = std_dev / sqrt (n) ; - - ds_init_empty (&vstr); - - var_append_value_name (cmd->indep_var, case_data (gcc, cmd->indep_var), &vstr); - - tab_text (t, 1, row + count, - TAB_LEFT | TAT_TITLE, - ds_cstr (&vstr)); - - ds_destroy (&vstr); - - /* Now fill in the numbers ... */ - - tab_double (t, 2, row + count, 0, n, NULL, RC_WEIGHT); - - tab_double (t, 3, row + count, 0, mean, NULL, RC_OTHER); - - tab_double (t, 4, row + count, 0, std_dev, NULL, RC_OTHER); - - - tab_double (t, 5, row + count, 0, std_error, NULL, RC_OTHER); - - /* Now the confidence interval */ - - T = gsl_cdf_tdist_Qinv (q, n - 1); - - tab_double (t, 6, row + count, 0, - mean - T * std_error, NULL, RC_OTHER); - - tab_double (t, 7, row + count, 0, - mean + T * std_error, NULL, RC_OTHER); - - /* Min and Max */ - - tab_double (t, 8, row + count, 0, dd->minimum, fmt, RC_OTHER); - tab_double (t, 9, row + count, 0, dd->maximum, fmt, RC_OTHER); + double std_dev = sqrt (variance); + double std_error = std_dev / sqrt (n) ; + double T = gsl_cdf_tdist_Qinv (q, n - 1); + + double entries[] = { + n, + mean, + std_dev, + std_error, + mean - T * std_error, + mean + T * std_error, + dd->minimum, + dd->maximum, + }; + for (size_t i = 0; i < sizeof entries / sizeof *entries; i++) + pivot_table_put3 (table, i, count, dep_var_idx, + pivot_value_new_number (entries[i])); } if (categoricals_is_complete (cats)) - { - double T; - double n, mean, variance; - double std_dev; - double std_error; - - moments1_calculate (ws->dd_total[v]->mom, &n, &mean, &variance, NULL, NULL); - - std_dev = sqrt (variance); - std_error = std_dev / sqrt (n) ; - - tab_text (t, 1, row + count, - TAB_LEFT | TAT_TITLE, _("Total")); - - tab_double (t, 2, row + count, 0, n, NULL, RC_WEIGHT); - - tab_double (t, 3, row + count, 0, mean, NULL, RC_OTHER); - - tab_double (t, 4, row + count, 0, std_dev, NULL, RC_OTHER); - - tab_double (t, 5, row + count, 0, std_error, NULL, RC_OTHER); - - /* Now the confidence interval */ - T = gsl_cdf_tdist_Qinv (q, n - 1); - - tab_double (t, 6, row + count, 0, - mean - T * std_error, NULL, RC_OTHER); - - tab_double (t, 7, row + count, 0, - mean + T * std_error, NULL, RC_OTHER); - - - /* Min and Max */ - tab_double (t, 8, row + count, 0, ws->dd_total[v]->minimum, fmt, RC_OTHER); - tab_double (t, 9, row + count, 0, ws->dd_total[v]->maximum, fmt, RC_OTHER); - } - - row += categoricals_n_total (cats) + 1; + { + double n, mean, variance; + moments1_calculate (ws->dd_total[v]->mom, &n, &mean, &variance, + NULL, NULL); + + double std_dev = sqrt (variance); + double std_error = std_dev / sqrt (n) ; + double T = gsl_cdf_tdist_Qinv (q, n - 1); + + double entries[] = { + n, + mean, + std_dev, + std_error, + mean - T * std_error, + mean + T * std_error, + ws->dd_total[v]->minimum, + ws->dd_total[v]->maximum, + }; + for (size_t i = 0; i < sizeof entries / sizeof *entries; i++) + pivot_table_put3 (table, i, count, dep_var_idx, + pivot_value_new_number (entries[i])); + } } - tab_submit (t); + pivot_table_submit (table); } /* Show the homogeneity table */ static void show_homogeneity (const struct oneway_spec *cmd, const struct oneway_workspace *ws) { - size_t v; - int n_cols = 5; - size_t n_rows = cmd->n_vars + 1; - - struct tab_table *t = tab_create (n_cols, n_rows); - tab_headers (t, 1, 0, 1, 0); - - /* Put a frame around the entire box, and vertical lines inside */ - tab_box (t, - TAL_2, TAL_2, - -1, TAL_1, - 0, 0, - n_cols - 1, n_rows - 1); + struct pivot_table *table = pivot_table_create ( + N_("Test of Homogeneity of Variances")); + pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Statistics"), + N_("Levene Statistic"), PIVOT_RC_OTHER, + N_("df1"), PIVOT_RC_INTEGER, + N_("df2"), PIVOT_RC_INTEGER, + N_("Sig."), PIVOT_RC_SIGNIFICANCE); - tab_hline (t, TAL_2, 0, n_cols - 1, 1); - tab_vline (t, TAL_2, 1, 0, n_rows - 1); + struct pivot_dimension *variables = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Variables")); - tab_text (t, 1, 0, TAB_CENTER | TAT_TITLE, _("Levene Statistic")); - tab_text (t, 2, 0, TAB_CENTER | TAT_TITLE, _("df1")); - tab_text (t, 3, 0, TAB_CENTER | TAT_TITLE, _("df2")); - tab_text (t, 4, 0, TAB_CENTER | TAT_TITLE, _("Sig.")); - - tab_title (t, _("Test of Homogeneity of Variances")); - - for (v = 0; v < cmd->n_vars; ++v) + for (int v = 0; v < cmd->n_vars; ++v) { - double n; - const struct per_var_ws *pvw = &ws->vws[v]; - double F = levene_calculate (pvw->nl); - - const struct variable *var = cmd->vars[v]; - const char *s = var_to_string (var); - double df1, df2; + int var_idx = pivot_category_create_leaf ( + variables->root, pivot_value_new_variable (cmd->vars[v])); + double n; moments1_calculate (ws->dd_total[v]->mom, &n, NULL, NULL, NULL, NULL); - df1 = pvw->n_groups - 1; - df2 = n - pvw->n_groups; - - tab_text (t, 0, v + 1, TAB_LEFT | TAT_TITLE, s); - - tab_double (t, 1, v + 1, TAB_RIGHT, F, NULL, RC_OTHER); - tab_double (t, 2, v + 1, TAB_RIGHT, df1, NULL, RC_INTEGER); - tab_double (t, 3, v + 1, TAB_RIGHT, df2, NULL, RC_INTEGER); + const struct per_var_ws *pvw = &ws->vws[v]; + double df1 = pvw->n_groups - 1; + double df2 = n - pvw->n_groups; + double F = levene_calculate (pvw->nl); - /* Now the significance */ - tab_double (t, 4, v + 1, TAB_RIGHT, gsl_cdf_fdist_Q (F, df1, df2), NULL, RC_PVALUE); + double entries[] = + { + F, + df1, + df2, + gsl_cdf_fdist_Q (F, df1, df2), + }; + for (size_t i = 0; i < sizeof entries / sizeof *entries; i++) + pivot_table_put2 (table, i, var_idx, + pivot_value_new_number (entries[i])); } - tab_submit (t); + pivot_table_submit (table); } @@ -1270,155 +1186,87 @@ show_homogeneity (const struct oneway_spec *cmd, const struct oneway_workspace * static void show_contrast_coeffs (const struct oneway_spec *cmd, const struct oneway_workspace *ws) { - int c_num = 0; - struct ll *cli; - - int n_contrasts = ll_count (&cmd->contrast_list); - int n_cols = 2 + ws->actual_number_of_groups; - int n_rows = 2 + n_contrasts; - - struct tab_table *t; - - const struct covariance *cov = ws->vws[0].cov ; - - t = tab_create (n_cols, n_rows); - tab_headers (t, 2, 0, 2, 0); + struct pivot_table *table = pivot_table_create (N_("Contrast Coefficients")); - /* Put a frame around the entire box, and vertical lines inside */ - tab_box (t, - TAL_2, TAL_2, - -1, TAL_1, - 0, 0, - n_cols - 1, n_rows - 1); + struct pivot_dimension *indep_var = pivot_dimension_create__ ( + table, PIVOT_AXIS_COLUMN, pivot_value_new_variable (cmd->indep_var)); + indep_var->root->show_label = true; - tab_box (t, - -1, -1, - TAL_0, TAL_0, - 2, 0, - n_cols - 1, 0); + struct pivot_dimension *contrast = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Contrast")); + contrast->root->show_label = true; - tab_box (t, - -1, -1, - TAL_0, TAL_0, - 0, 0, - 1, 1); + const struct covariance *cov = ws->vws[0].cov; - tab_hline (t, TAL_1, 2, n_cols - 1, 1); - tab_hline (t, TAL_2, 0, n_cols - 1, 2); - - tab_vline (t, TAL_2, 2, 0, n_rows - 1); - - tab_title (t, _("Contrast Coefficients")); - - tab_text (t, 0, 2, TAB_LEFT | TAT_TITLE, _("Contrast")); - - - tab_joint_text (t, 2, 0, n_cols - 1, 0, TAB_CENTER | TAT_TITLE, - var_to_string (cmd->indep_var)); - - for ( cli = ll_head (&cmd->contrast_list); - cli != ll_null (&cmd->contrast_list); - cli = ll_next (cli)) + const struct contrasts_node *cn; + int c_num = 1; + ll_for_each (cn, struct contrasts_node, ll, &cmd->contrast_list) { - int count = 0; - struct contrasts_node *cn = ll_data (cli, struct contrasts_node, ll); - struct ll *coeffi ; + int contrast_idx = pivot_category_create_leaf ( + contrast->root, pivot_value_new_integer (c_num++)); - tab_text_format (t, 1, c_num + 2, TAB_CENTER, "%d", c_num + 1); - - for (coeffi = ll_head (&cn->coefficient_list); - coeffi != ll_null (&cn->coefficient_list); - ++count, coeffi = ll_next (coeffi)) + const struct coeff_node *coeffn; + int indep_idx = 0; + ll_for_each (coeffn, struct coeff_node, ll, &cn->coefficient_list) { const struct categoricals *cats = covariance_get_categoricals (cov); - const struct ccase *gcc = categoricals_get_case_by_category (cats, count); - struct coeff_node *coeffn = ll_data (coeffi, struct coeff_node, ll); - struct string vstr; - - ds_init_empty (&vstr); - - var_append_value_name (cmd->indep_var, case_data (gcc, cmd->indep_var), &vstr); + const struct ccase *gcc = categoricals_get_case_by_category ( + cats, indep_idx); - tab_text (t, count + 2, 1, TAB_CENTER | TAT_TITLE, ds_cstr (&vstr)); + if (!contrast_idx) + pivot_category_create_leaf ( + indep_var->root, pivot_value_new_var_value ( + cmd->indep_var, case_data (gcc, cmd->indep_var))); - ds_destroy (&vstr); - - tab_text_format (t, count + 2, c_num + 2, TAB_RIGHT, "%.*g", - DBL_DIG + 1, coeffn->coeff); + pivot_table_put2 (table, indep_idx++, contrast_idx, + pivot_value_new_integer (coeffn->coeff)); } - ++c_num; } - tab_submit (t); + pivot_table_submit (table); } - /* Show the results of the contrast tests */ static void show_contrast_tests (const struct oneway_spec *cmd, const struct oneway_workspace *ws) { + struct pivot_table *table = pivot_table_create (N_("Contrast Tests")); + + pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Statistics"), + N_("Value of Contrast"), PIVOT_RC_OTHER, + N_("Std. Error"), PIVOT_RC_OTHER, + N_("t"), PIVOT_RC_OTHER, + N_("df"), PIVOT_RC_OTHER, + N_("Sig. (2-tailed)"), PIVOT_RC_SIGNIFICANCE); + + struct pivot_dimension *contrasts = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Contrast")); + contrasts->root->show_label = true; int n_contrasts = ll_count (&cmd->contrast_list); - size_t v; - int n_cols = 8; - size_t n_rows = 1 + cmd->n_vars * 2 * n_contrasts; - - struct tab_table *t; + for (int i = 1; i <= n_contrasts; i++) + pivot_category_create_leaf (contrasts->root, pivot_value_new_integer (i)); - t = tab_create (n_cols, n_rows); - tab_headers (t, 3, 0, 1, 0); + pivot_dimension_create (table, PIVOT_AXIS_ROW, N_("Assumption"), + N_("Assume equal variances"), + N_("Does not assume equal variances")); - /* Put a frame around the entire box, and vertical lines inside */ - tab_box (t, - TAL_2, TAL_2, - -1, TAL_1, - 0, 0, - n_cols - 1, n_rows - 1); + struct pivot_dimension *variables = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Dependent Variable")); - tab_box (t, - -1, -1, - TAL_0, TAL_0, - 0, 0, - 2, 0); - - tab_hline (t, TAL_2, 0, n_cols - 1, 1); - tab_vline (t, TAL_2, 3, 0, n_rows - 1); - - tab_title (t, _("Contrast Tests")); - - tab_text (t, 2, 0, TAB_CENTER | TAT_TITLE, _("Contrast")); - tab_text (t, 3, 0, TAB_CENTER | TAT_TITLE, _("Value of Contrast")); - tab_text (t, 4, 0, TAB_CENTER | TAT_TITLE, _("Std. Error")); - tab_text (t, 5, 0, TAB_CENTER | TAT_TITLE, _("t")); - tab_text (t, 6, 0, TAB_CENTER | TAT_TITLE, _("df")); - tab_text (t, 7, 0, TAB_CENTER | TAT_TITLE, _("Sig. (2-tailed)")); - - for (v = 0; v < cmd->n_vars; ++v) + for (int v = 0; v < cmd->n_vars; ++v) { const struct per_var_ws *pvw = &ws->vws[v]; const struct categoricals *cats = covariance_get_categoricals (pvw->cov); if (!categoricals_is_complete (cats)) continue; - struct ll *cli; - int i = 0; - int lines_per_variable = 2 * n_contrasts; - tab_text (t, 0, (v * lines_per_variable) + 1, TAB_LEFT | TAT_TITLE, - var_to_string (cmd->vars[v])); + int var_idx = pivot_category_create_leaf ( + variables->root, pivot_value_new_variable (cmd->vars[v])); - for ( cli = ll_head (&cmd->contrast_list); - cli != ll_null (&cmd->contrast_list); - ++i, cli = ll_next (cli)) + struct contrasts_node *cn; + int contrast_idx = 0; + ll_for_each (cn, struct contrasts_node, ll, &cmd->contrast_list) { - struct contrasts_node *cn = ll_data (cli, struct contrasts_node, ll); - struct ll *coeffi ; - int ci = 0; - double contrast_value = 0.0; - double coef_msq = 0.0; - - double T; - double std_error_contrast; - double df; - double sec_vneq = 0.0; /* Note: The calculation of the degrees of freedom in the "variances not equal" case is painfull!! @@ -1431,254 +1279,174 @@ show_contrast_tests (const struct oneway_spec *cmd, const struct oneway_workspac } */ - double df_denominator = 0.0; - double df_numerator = 0.0; - double grand_n; - moments1_calculate (ws->dd_total[v]->mom, &grand_n, NULL, NULL, NULL, NULL); - df = grand_n - pvw->n_groups; + moments1_calculate (ws->dd_total[v]->mom, &grand_n, NULL, NULL, + NULL, NULL); + double df = grand_n - pvw->n_groups; - if ( i == 0 ) + double contrast_value = 0.0; + double coef_msq = 0.0; + double sec_vneq = 0.0; + double df_denominator = 0.0; + double df_numerator = 0.0; + struct coeff_node *coeffn; + int ci = 0; + ll_for_each (coeffn, struct coeff_node, ll, &cn->coefficient_list) { - tab_text (t, 1, (v * lines_per_variable) + i + 1, - TAB_LEFT | TAT_TITLE, - _("Assume equal variances")); - - tab_text (t, 1, (v * lines_per_variable) + i + 1 + n_contrasts, - TAB_LEFT | TAT_TITLE, - _("Does not assume equal")); - } - - tab_text_format (t, 2, (v * lines_per_variable) + i + 1, - TAB_CENTER | TAT_TITLE, "%d", i + 1); - + const struct descriptive_data *dd + = categoricals_get_user_data_by_category (cats, ci); + const double coef = coeffn->coeff; - tab_text_format (t, 2, - (v * lines_per_variable) + i + 1 + n_contrasts, - TAB_CENTER | TAT_TITLE, "%d", i + 1); - - for (coeffi = ll_head (&cn->coefficient_list); - coeffi != ll_null (&cn->coefficient_list); - ++ci, coeffi = ll_next (coeffi)) - { double n, mean, variance; - const struct descriptive_data *dd = categoricals_get_user_data_by_category (cats, ci); - struct coeff_node *cn = ll_data (coeffi, struct coeff_node, ll); - const double coef = cn->coeff; - double winv ; - moments1_calculate (dd->mom, &n, &mean, &variance, NULL, NULL); - winv = variance / n; - + double winv = variance / n; contrast_value += coef * mean; + coef_msq += pow2 (coef) / n; + sec_vneq += pow2 (coef) * variance / n; + df_numerator += pow2 (coef) * winv; + df_denominator += pow2(pow2 (coef) * winv) / (n - 1); - coef_msq += (pow2 (coef)) / n; - - sec_vneq += (pow2 (coef)) * variance / n; - - df_numerator += (pow2 (coef)) * winv; - df_denominator += pow2((pow2 (coef)) * winv) / (n - 1); + ci++; } - sec_vneq = sqrt (sec_vneq); - df_numerator = pow2 (df_numerator); - tab_double (t, 3, (v * lines_per_variable) + i + 1, - TAB_RIGHT, contrast_value, NULL, RC_OTHER); - - tab_double (t, 3, (v * lines_per_variable) + i + 1 + - n_contrasts, - TAB_RIGHT, contrast_value, NULL, RC_OTHER); - - std_error_contrast = sqrt (pvw->mse * coef_msq); - - /* Std. Error */ - tab_double (t, 4, (v * lines_per_variable) + i + 1, - TAB_RIGHT, std_error_contrast, - NULL, RC_OTHER); + double std_error_contrast = sqrt (pvw->mse * coef_msq); + double T = fabs (contrast_value / std_error_contrast); + double T_ne = contrast_value / sec_vneq; + double df_ne = df_numerator / df_denominator; + double p_ne = gsl_cdf_tdist_P (T_ne, df_ne); + double q_ne = gsl_cdf_tdist_Q (T_ne, df_ne); - T = fabs (contrast_value / std_error_contrast); - - /* T Statistic */ - - tab_double (t, 5, (v * lines_per_variable) + i + 1, - TAB_RIGHT, T, - NULL, RC_OTHER); - - - /* Degrees of Freedom */ - tab_double (t, 6, (v * lines_per_variable) + i + 1, - TAB_RIGHT, df, NULL, RC_INTEGER); - - - /* Significance TWO TAILED !!*/ - tab_double (t, 7, (v * lines_per_variable) + i + 1, - TAB_RIGHT, 2 * gsl_cdf_tdist_Q (T, df), - NULL, RC_PVALUE); - - /* Now for the Variances NOT Equal case */ - - /* Std. Error */ - tab_double (t, 4, - (v * lines_per_variable) + i + 1 + n_contrasts, - TAB_RIGHT, sec_vneq, - NULL, RC_OTHER); - - T = contrast_value / sec_vneq; - tab_double (t, 5, - (v * lines_per_variable) + i + 1 + n_contrasts, - TAB_RIGHT, T, - NULL, RC_OTHER); - - df = df_numerator / df_denominator; - - tab_double (t, 6, - (v * lines_per_variable) + i + 1 + n_contrasts, - TAB_RIGHT, df, - NULL, RC_OTHER); - - { - double p = gsl_cdf_tdist_P (T, df); - double q = gsl_cdf_tdist_Q (T, df); + struct entry + { + int stat_idx; + int assumption_idx; + double x; + } + entries[] = + { + /* Assume equal. */ + { 0, 0, contrast_value }, + { 1, 0, std_error_contrast }, + { 2, 0, T }, + { 3, 0, df }, + { 4, 0, 2 * gsl_cdf_tdist_Q (T, df) }, + /* Do not assume equal. */ + { 0, 1, contrast_value }, + { 1, 1, sec_vneq }, + { 2, 1, T_ne }, + { 3, 1, df_ne }, + { 4, 1, 2 * (T > 0 ? q_ne : p_ne) }, + }; + + for (size_t i = 0; i < sizeof entries / sizeof *entries; i++) + { + const struct entry *e = &entries[i]; + pivot_table_put4 ( + table, e->stat_idx, contrast_idx, e->assumption_idx, var_idx, + pivot_value_new_number (e->x)); + } - /* The Significance */ - tab_double (t, 7, (v * lines_per_variable) + i + 1 + n_contrasts, - TAB_RIGHT, 2 * ((T > 0) ? q : p), - NULL, RC_PVALUE); - } + contrast_idx++; } - - if ( v > 0 ) - tab_hline (t, TAL_1, 0, n_cols - 1, (v * lines_per_variable) + 1); } - tab_submit (t); + pivot_table_submit (table); } - - static void show_comparisons (const struct oneway_spec *cmd, const struct oneway_workspace *ws, int v) { - const int n_cols = 8; - const int heading_rows = 2; - const int heading_cols = 3; - - int p; - int r = heading_rows ; + struct pivot_table *table = pivot_table_create__ ( + pivot_value_new_user_text_nocopy (xasprintf ( + _("Multiple Comparisons (%s)"), + var_to_string (cmd->vars[v])))); + table->omit_empty = true; + + struct pivot_dimension *statistics = pivot_dimension_create ( + table, PIVOT_AXIS_COLUMN, N_("Statistics"), + N_("Mean Difference (I - J)"), PIVOT_RC_OTHER, + N_("Std. Error"), PIVOT_RC_OTHER, + N_("Sig."), PIVOT_RC_SIGNIFICANCE); + struct pivot_category *interval = pivot_category_create_group__ ( + statistics->root, + pivot_value_new_text_format (N_("%g%% Confidence Interval"), + (1 - cmd->alpha) * 100.0)); + pivot_category_create_leaves (interval, + N_("Lower Bound"), PIVOT_RC_OTHER, + N_("Upper Bound"), PIVOT_RC_OTHER); + + struct pivot_dimension *j_family = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("(J) Family")); + j_family->root->show_label = true; + + struct pivot_dimension *i_family = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("(J) Family")); + i_family->root->show_label = true; const struct per_var_ws *pvw = &ws->vws[v]; const struct categoricals *cat = pvw->cat; - const int n_rows = heading_rows + cmd->n_posthoc * pvw->n_groups * (pvw->n_groups - 1); - - struct tab_table *t = tab_create (n_cols, n_rows); - - tab_headers (t, heading_cols, 0, heading_rows, 0); - - /* Put a frame around the entire box, and vertical lines inside */ - tab_box (t, - TAL_2, TAL_2, - -1, -1, - 0, 0, - n_cols - 1, n_rows - 1); - - tab_box (t, - -1, -1, - -1, TAL_1, - heading_cols, 0, - n_cols - 1, n_rows - 1); - - tab_vline (t, TAL_2, heading_cols, 0, n_rows - 1); - - tab_title (t, _("Multiple Comparisons (%s)"), var_to_string (cmd->vars[v])); - - tab_text_format (t, 1, 1, TAB_LEFT | TAT_TITLE, _("(I) %s"), var_to_string (cmd->indep_var)); - tab_text_format (t, 2, 1, TAB_LEFT | TAT_TITLE, _("(J) %s"), var_to_string (cmd->indep_var)); - tab_text (t, 3, 0, TAB_CENTER | TAT_TITLE, _("Mean Difference")); - tab_text (t, 3, 1, TAB_CENTER | TAT_TITLE, _("(I - J)")); - tab_text (t, 4, 1, TAB_CENTER | TAT_TITLE, _("Std. Error")); - tab_text (t, 5, 1, TAB_CENTER | TAT_TITLE, _("Sig.")); - - tab_joint_text_format (t, 6, 0, 7, 0, TAB_CENTER | TAT_TITLE, - _("%g%% Confidence Interval"), - (1 - cmd->alpha) * 100.0); - - tab_text (t, 6, 1, TAB_CENTER | TAT_TITLE, _("Lower Bound")); - tab_text (t, 7, 1, TAB_CENTER | TAT_TITLE, _("Upper Bound")); + for (int i = 0; i < pvw->n_groups; i++) + { + const struct ccase *gcc = categoricals_get_case_by_category (cat, i); + for (int j = 0; j < 2; j++) + pivot_category_create_leaf ( + j ? j_family->root : i_family->root, + pivot_value_new_var_value (cmd->indep_var, + case_data (gcc, cmd->indep_var))); + } + struct pivot_dimension *test = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Test")); - for (p = 0; p < cmd->n_posthoc; ++p) + for (int p = 0; p < cmd->n_posthoc; ++p) { - int i; const struct posthoc *ph = &ph_tests[cmd->posthoc[p]]; - tab_hline (t, TAL_2, 0, n_cols - 1, r); - - tab_text (t, 0, r, TAB_LEFT | TAT_TITLE, gettext (ph->label)); + int test_idx = pivot_category_create_leaf ( + test->root, pivot_value_new_text (ph->label)); - for (i = 0; i < pvw->n_groups ; ++i) + for (int i = 0; i < pvw->n_groups ; ++i) { + struct descriptive_data *dd_i + = categoricals_get_user_data_by_category (cat, i); double weight_i, mean_i, var_i; - int rx = 0; - struct string vstr; - int j; - struct descriptive_data *dd_i = categoricals_get_user_data_by_category (cat, i); - const struct ccase *gcc = categoricals_get_case_by_category (cat, i); - - - ds_init_empty (&vstr); - var_append_value_name (cmd->indep_var, case_data (gcc, cmd->indep_var), &vstr); - - if ( i != 0) - tab_hline (t, TAL_1, 1, n_cols - 1, r); - tab_text (t, 1, r, TAB_LEFT | TAT_TITLE, ds_cstr (&vstr)); - moments1_calculate (dd_i->mom, &weight_i, &mean_i, &var_i, 0, 0); - for (j = 0 ; j < pvw->n_groups; ++j) + for (int j = 0 ; j < pvw->n_groups; ++j) { - double std_err; - double weight_j, mean_j, var_j; - double half_range; - const struct ccase *cc; - struct descriptive_data *dd_j = categoricals_get_user_data_by_category (cat, j); if (j == i) continue; - ds_clear (&vstr); - cc = categoricals_get_case_by_category (cat, j); - var_append_value_name (cmd->indep_var, case_data (cc, cmd->indep_var), &vstr); - tab_text (t, 2, r + rx, TAB_LEFT | TAT_TITLE, ds_cstr (&vstr)); - + struct descriptive_data *dd_j + = categoricals_get_user_data_by_category (cat, j); + double weight_j, mean_j, var_j; moments1_calculate (dd_j->mom, &weight_j, &mean_j, &var_j, 0, 0); - tab_double (t, 3, r + rx, 0, mean_i - mean_j, NULL, RC_OTHER); - - std_err = pvw->mse; + double std_err = pvw->mse; std_err *= weight_i + weight_j; std_err /= weight_i * weight_j; std_err = sqrt (std_err); - tab_double (t, 4, r + rx, 0, std_err, NULL, RC_OTHER); - - tab_double (t, 5, r + rx, 0, 2 * multiple_comparison_sig (std_err, pvw, dd_i, dd_j, ph), NULL, RC_PVALUE); - - half_range = mc_half_range (cmd, pvw, std_err, dd_i, dd_j, ph); - - tab_double (t, 6, r + rx, 0, - (mean_i - mean_j) - half_range, NULL, RC_OTHER); - - tab_double (t, 7, r + rx, 0, - (mean_i - mean_j) + half_range, NULL, RC_OTHER); - - rx++; + double sig = 2 * multiple_comparison_sig (std_err, pvw, + dd_i, dd_j, ph); + double half_range = mc_half_range (cmd, pvw, std_err, + dd_i, dd_j, ph); + double entries[] = { + mean_i - mean_j, + std_err, + sig, + (mean_i - mean_j) - half_range, + (mean_i - mean_j) + half_range, + }; + for (size_t k = 0; k < sizeof entries / sizeof *entries; k++) + pivot_table_put4 (table, k, j, i, test_idx, + pivot_value_new_number (entries[k])); } - ds_destroy (&vstr); - r += pvw->n_groups - 1; } } - tab_submit (t); + pivot_table_submit (table); } diff --git a/src/language/stats/quick-cluster.c b/src/language/stats/quick-cluster.c index b171951557..a3387bb630 100644 --- a/src/language/stats/quick-cluster.c +++ b/src/language/stats/quick-cluster.c @@ -39,7 +39,7 @@ #include "libpspp/assertion.h" #include "libpspp/str.h" #include "math/random.h" -#include "output/tab.h" +#include "output/pivot-table.h" #include "output/text-item.h" #include "gettext.h" @@ -514,97 +514,69 @@ kmeans_cluster (struct Kmeans *kmeans, struct casereader *reader, const struct q static void quick_cluster_show_centers (struct Kmeans *kmeans, bool initial, const struct qc *qc) { - struct tab_table *t; - int nc, nr, currow; - int i, j; - nc = qc->ngroups + 1; - nr = qc->n_vars + 4; - t = tab_create (nc, nr); - tab_headers (t, 0, nc - 1, 0, 1); - currow = 0; - if (!initial) - { - tab_title (t, _("Final Cluster Centers")); - } - else - { - tab_title (t, _("Initial Cluster Centers")); - } - tab_box (t, TAL_2, TAL_2, TAL_0, TAL_1, 0, 0, nc - 1, nr - 1); - tab_joint_text (t, 1, 0, nc - 1, 0, TAB_CENTER, _("Cluster")); - tab_hline (t, TAL_1, 1, nc - 1, 2); - currow += 2; - - for (i = 0; i < qc->ngroups; i++) - { - tab_text_format (t, (i + 1), currow, TAB_CENTER, "%d", (i + 1)); - } - currow++; - tab_hline (t, TAL_1, 1, nc - 1, currow); - currow++; - for (i = 0; i < qc->n_vars; i++) - { - tab_text (t, 0, currow + i, TAB_LEFT, - var_to_string (qc->vars[i])); + struct pivot_table *table = pivot_table_create ( + initial ? N_("Initial Cluster Centers") : N_("Final Cluster Centers")); + + struct pivot_dimension *clusters = pivot_dimension_create ( + table, PIVOT_AXIS_COLUMN, N_("Cluster")); + clusters->root->show_label = true; + for (size_t i = 0; i < qc->ngroups; i++) + pivot_category_create_leaf (clusters->root, + pivot_value_new_integer (i + 1)); + + struct pivot_dimension *variables = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Variable")); + for (size_t i = 0; i < qc->n_vars; i++) + pivot_category_create_leaf (variables->root, + pivot_value_new_variable (qc->vars[i])); + + const gsl_matrix *matrix = (initial + ? kmeans->initial_centers + : kmeans->centers); + for (size_t i = 0; i < qc->ngroups; i++) + for (size_t j = 0; j < qc->n_vars; j++) + { + double x = gsl_matrix_get (matrix, kmeans->group_order->data[i], j); + union value v = { .f = x }; + pivot_table_put2 (table, i, j, + pivot_value_new_var_value (qc->vars[j], &v)); } - for (i = 0; i < qc->ngroups; i++) - { - for (j = 0; j < qc->n_vars; j++) - { - if (!initial) - { - tab_double (t, i + 1, j + 4, TAB_CENTER, - gsl_matrix_get (kmeans->centers, - kmeans->group_order->data[i], j), - var_get_print_format (qc->vars[j]), RC_OTHER); - } - else - { - tab_double (t, i + 1, j + 4, TAB_CENTER, - gsl_matrix_get (kmeans->initial_centers, - kmeans->group_order->data[i], j), - var_get_print_format (qc->vars[j]), RC_OTHER); - } - } - } - tab_submit (t); + pivot_table_submit (table); } /* Reports cluster membership for each case. */ static void quick_cluster_show_membership (struct Kmeans *kmeans, const struct casereader *reader, const struct qc *qc) { - struct tab_table *t; - int nc, nr, i; + struct pivot_table *table = pivot_table_create (N_("Cluster Membership")); - struct ccase *c; - struct casereader *cs = casereader_clone (reader); - nc = 2; - nr = kmeans->n + 1; - t = tab_create (nc, nr); - tab_headers (t, 0, nc - 1, 0, 0); - tab_title (t, _("Cluster Membership")); - tab_text (t, 0, 0, TAB_CENTER, _("Case Number")); - tab_text (t, 1, 0, TAB_CENTER, _("Cluster")); - tab_box (t, TAL_2, TAL_2, TAL_0, TAL_1, 0, 0, nc - 1, nr - 1); - tab_hline (t, TAL_1, 0, nc - 1, 1); + pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Cluster"), + N_("Cluster")); + + struct pivot_dimension *cases = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Case Number")); + cases->root->show_label = true; gsl_permutation *ip = gsl_permutation_alloc (qc->ngroups); gsl_permutation_inverse (ip, kmeans->group_order); - for (i = 0; (c = casereader_read (cs)) != NULL; i++, case_unref (c)) + struct casereader *cs = casereader_clone (reader); + struct ccase *c; + for (int i = 0; (c = casereader_read (cs)) != NULL; i++, case_unref (c)) { - int clust = -1; assert (i < kmeans->n); + int clust; kmeans_get_nearest_group (kmeans, c, qc, &clust, NULL, NULL, NULL); - clust = ip->data[clust]; - tab_text_format (t, 0, i+1, TAB_CENTER, "%d", (i + 1)); - tab_text_format (t, 1, i+1, TAB_CENTER, "%d", (clust + 1)); + int cluster = ip->data[clust]; + + int case_idx = pivot_category_create_leaf ( + cases->root, pivot_value_new_integer (i + 1)); + pivot_table_put2 (table, 0, case_idx, + pivot_value_new_integer (cluster + 1)); } gsl_permutation_free (ip); - assert (i == kmeans->n); - tab_submit (t); + pivot_table_submit (table); casereader_destroy (cs); } @@ -613,31 +585,33 @@ quick_cluster_show_membership (struct Kmeans *kmeans, const struct casereader *r static void quick_cluster_show_number_cases (struct Kmeans *kmeans, const struct qc *qc) { - struct tab_table *t; - int nc, nr; - int i, numelem; - long int total; - nc = 3; - nr = qc->ngroups + 1; - t = tab_create (nc, nr); - tab_headers (t, 0, nc - 1, 0, 0); - tab_title (t, _("Number of Cases in each Cluster")); - tab_box (t, TAL_2, TAL_2, TAL_0, TAL_1, 0, 0, nc - 1, nr - 1); - tab_text (t, 0, 0, TAB_LEFT, _("Cluster")); - - total = 0; - for (i = 0; i < qc->ngroups; i++) + struct pivot_table *table = pivot_table_create ( + N_("Number of Cases in each Cluster")); + + pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Statistics"), + N_("Count")); + + struct pivot_dimension *clusters = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Clusters")); + struct pivot_category *group = pivot_category_create_group ( + clusters->root, N_("Cluster")); + + long int total = 0; + for (int i = 0; i < qc->ngroups; i++) { - tab_text_format (t, 1, i, TAB_CENTER, "%d", (i + 1)); - numelem = - kmeans->num_elements_groups->data[kmeans->group_order->data[i]]; - tab_text_format (t, 2, i, TAB_CENTER, "%d", numelem); - total += numelem; + int cluster_idx = pivot_category_create_leaf ( + group, pivot_value_new_integer (i + 1)); + int count = kmeans->num_elements_groups->data[ + kmeans->group_order->data[i]]; + pivot_table_put2 (table, 0, cluster_idx, + pivot_value_new_integer (count)); + total += count; } - tab_text (t, 0, qc->ngroups, TAB_LEFT, _("Valid")); - tab_text_format (t, 2, qc->ngroups, TAB_LEFT, "%ld", total); - tab_submit (t); + int cluster_idx = pivot_category_create_leaf ( + clusters->root, pivot_value_new_text (N_("Valid"))); + pivot_table_put2 (table, 0, cluster_idx, pivot_value_new_integer (total)); + pivot_table_submit (table); } /* Reports. */ diff --git a/src/language/stats/rank.c b/src/language/stats/rank.c index 65a0fb8b57..cd3833dbba 100644 --- a/src/language/stats/rank.c +++ b/src/language/stats/rank.c @@ -41,8 +41,7 @@ #include "libpspp/pool.h" #include "libpspp/string-set.h" #include "libpspp/taint.h" - -#include "output/tab.h" +#include "output/pivot-table.h" #include "gettext.h" #define _(msgid) gettext (msgid) @@ -650,7 +649,6 @@ cmd_rank (struct lexer *lexer, struct dataset *ds) struct string_set new_names; struct rank rank; struct rank_spec *rs; - int i; subcase_init_empty (&rank.sc); @@ -802,11 +800,9 @@ cmd_rank (struct lexer *lexer, struct dataset *ds) created with INTO. */ for (rs = rank.rs; rs < &rank.rs[rank.n_rs]; rs++) { - int v; - rs->dest_labels = pool_calloc (rank.pool, rank.n_vars, sizeof *rs->dest_labels); - for ( v = 0 ; v < rank.n_vars ; v ++ ) + for (int v = 0 ; v < rank.n_vars ; v ++ ) { const char **dst_name = &rs->dest_names[v]; if ( *dst_name == NULL ) @@ -825,72 +821,54 @@ cmd_rank (struct lexer *lexer, struct dataset *ds) if ( rank.print ) { - int v; + struct pivot_table *table = pivot_table_create ( + N_("Variables Created by RANK")); + table->omit_empty = true; - tab_output_text_format (0, _("Variables Created By %s"), "RANK"); - tab_output_text (0, ""); + pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("New Variable"), + N_("New Variable"), N_("Function"), + N_("Fraction"), N_("Grouping Variables")); - for (i = 0 ; i < rank.n_rs ; ++i ) + struct pivot_dimension *variables = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Existing Variable"), + N_("Existing Variable")); + variables->root->show_label = true; + + for (size_t i = 0 ; i < rank.n_rs ; ++i ) { - for ( v = 0 ; v < rank.n_vars ; v ++ ) + for (size_t v = 0 ; v < rank.n_vars ; v ++ ) { - if ( rank.n_group_vars > 0 ) - { - struct string varlist; - int g; - - ds_init_empty (&varlist); - for ( g = 0 ; g < rank.n_group_vars ; ++g ) - { - ds_put_cstr (&varlist, var_get_name (rank.group_vars[g])); - - if ( g < rank.n_group_vars - 1) - ds_put_cstr (&varlist, " "); - } - - if ( rank.rs[i].rfunc == NORMAL || - rank.rs[i].rfunc == PROPORTION ) - tab_output_text_format (0, - _("%s into %s(%s of %s using %s BY %s)"), - var_get_name (rank.vars[v]), - rank.rs[i].dest_names[v], - function_name[rank.rs[i].rfunc], - var_get_name (rank.vars[v]), - fraction_name (&rank), - ds_cstr (&varlist)); - - else - tab_output_text_format (0, - _("%s into %s(%s of %s BY %s)"), - var_get_name (rank.vars[v]), - rank.rs[i].dest_names[v], - function_name[rank.rs[i].rfunc], - var_get_name (rank.vars[v]), - ds_cstr (&varlist)); - ds_destroy (&varlist); - } - else - { - if ( rank.rs[i].rfunc == NORMAL || - rank.rs[i].rfunc == PROPORTION ) - tab_output_text_format (0, - _("%s into %s(%s of %s using %s)"), - var_get_name (rank.vars[v]), - rank.rs[i].dest_names[v], - function_name[rank.rs[i].rfunc], - var_get_name (rank.vars[v]), - fraction_name (&rank)); - - else - tab_output_text_format (0, - _("%s into %s(%s of %s)"), - var_get_name (rank.vars[v]), - rank.rs[i].dest_names[v], - function_name[rank.rs[i].rfunc], - var_get_name (rank.vars[v])); - } + int row_idx = pivot_category_create_leaf ( + variables->root, pivot_value_new_variable (rank.vars[v])); + + struct string group_vars = DS_EMPTY_INITIALIZER; + for (int g = 0 ; g < rank.n_group_vars ; ++g ) + { + if (g) + ds_put_byte (&group_vars, ' '); + ds_put_cstr (&group_vars, var_get_name (rank.group_vars[g])); + } + + enum rank_func rfunc = rank.rs[i].rfunc; + bool has_fraction = rfunc == NORMAL || rfunc == PROPORTION; + const char *entries[] = + { + rank.rs[i].dest_names[v], + function_name[rank.rs[i].rfunc], + has_fraction ? fraction_name (&rank) : NULL, + rank.n_group_vars ? ds_cstr (&group_vars) : NULL, + }; + for (size_t j = 0; j < sizeof entries / sizeof *entries; j++) + { + const char *entry = entries[j]; + if (entry) + pivot_table_put2 (table, j, row_idx, + pivot_value_new_user_text (entry, -1)); + } } } + + pivot_table_submit (table); } /* Do the ranking */ diff --git a/src/language/stats/regression.c b/src/language/stats/regression.c index 72649ba4ac..ecc2279b45 100644 --- a/src/language/stats/regression.c +++ b/src/language/stats/regression.c @@ -44,15 +44,16 @@ #include "libpspp/message.h" #include "libpspp/taint.h" -#include "output/tab.h" +#include "output/pivot-table.h" + +#include "gl/intprops.h" +#include "gl/minmax.h" #include "gettext.h" #define _(msgid) gettext (msgid) #define N_(msgid) msgid -#include - #define STATS_R 1 #define STATS_COEFF 2 #define STATS_ANOVA 4 @@ -782,35 +783,27 @@ run_regression (const struct regression *cmd, static void reg_stats_r (const struct linreg * c, const struct variable *var) { - struct tab_table *t; - int n_rows = 2; - int n_cols = 5; - double rsq; - double adjrsq; - double std_error; - - assert (c != NULL); - rsq = linreg_ssreg (c) / linreg_sst (c); - adjrsq = rsq - - (1.0 - rsq) * linreg_n_coeffs (c) / (linreg_n_obs (c) - - linreg_n_coeffs (c) - 1); - std_error = sqrt (linreg_mse (c)); - t = tab_create (n_cols, n_rows); - tab_box (t, TAL_2, TAL_2, -1, TAL_1, 0, 0, n_cols - 1, n_rows - 1); - tab_hline (t, TAL_2, 0, n_cols - 1, 1); - tab_vline (t, TAL_2, 2, 0, n_rows - 1); - tab_vline (t, TAL_0, 1, 0, 0); - - tab_text (t, 1, 0, TAB_CENTER | TAT_TITLE, _("R")); - tab_text (t, 2, 0, TAB_CENTER | TAT_TITLE, _("R Square")); - tab_text (t, 3, 0, TAB_CENTER | TAT_TITLE, _("Adjusted R Square")); - tab_text (t, 4, 0, TAB_CENTER | TAT_TITLE, _("Std. Error of the Estimate")); - tab_double (t, 1, 1, TAB_RIGHT, sqrt (rsq), NULL, RC_OTHER); - tab_double (t, 2, 1, TAB_RIGHT, rsq, NULL, RC_OTHER); - tab_double (t, 3, 1, TAB_RIGHT, adjrsq, NULL, RC_OTHER); - tab_double (t, 4, 1, TAB_RIGHT, std_error, NULL, RC_OTHER); - tab_title (t, _("Model Summary (%s)"), var_to_string (var)); - tab_submit (t); + struct pivot_table *table = pivot_table_create__ ( + pivot_value_new_text_format (N_("Model Summary (%s)"), + var_to_string (var))); + + pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Statistics"), + N_("R"), N_("R Square"), N_("Adjusted R Square"), + N_("Std. Error of the Estimate")); + + double rsq = linreg_ssreg (c) / linreg_sst (c); + double adjrsq = (rsq - + (1.0 - rsq) * linreg_n_coeffs (c) + / (linreg_n_obs (c) - linreg_n_coeffs (c) - 1)); + double std_error = sqrt (linreg_mse (c)); + + double entries[] = { + sqrt (rsq), rsq, adjrsq, std_error + }; + for (size_t i = 0; i < sizeof entries / sizeof *entries; i++) + pivot_table_put1 (table, i, pivot_value_new_number (entries[i])); + + pivot_table_submit (table); } /* @@ -819,128 +812,82 @@ reg_stats_r (const struct linreg * c, const struct variable *var) static void reg_stats_coeff (const struct linreg * c, const gsl_matrix *cov, const struct variable *var, const struct regression *cmd) { - size_t j; - int n_cols = 7; - const int heading_rows = 2; - int n_rows; - int this_row = heading_rows; - double pval; - double std_err; - double beta; - const char *label; - - const struct variable *v; - struct tab_table *t; - - const double df = linreg_n_obs (c) - linreg_n_coeffs (c) - 1; - double q = (1 - cmd->ci) / 2.0; /* 2-tailed test */ - double tval = gsl_cdf_tdist_Qinv (q, df); - - assert (c != NULL); - n_rows = linreg_n_coeffs (c) + heading_rows + 1; - - if (cmd->stats & STATS_CI) - n_cols += 2; - - t = tab_create (n_cols, n_rows); - tab_headers (t, 2, 0, 1, 0); - tab_box (t, TAL_2, TAL_2, -1, TAL_1, 0, 0, n_cols - 1, n_rows - 1); - tab_hline (t, TAL_2, 0, n_cols - 1, heading_rows); - tab_vline (t, TAL_2, 2, 0, n_rows - 1); - tab_vline (t, TAL_0, 1, 0, 0); - - - tab_hline (t, TAL_1, 2, 4, 1); - tab_joint_text (t, 2, 0, 3, 0, TAB_CENTER | TAT_TITLE, _("Unstandardized Coefficients")); - tab_text (t, 2, 1, TAB_CENTER | TAT_TITLE, _("B")); - tab_text (t, 3, 1, TAB_CENTER | TAT_TITLE, _("Std. Error")); - tab_text (t, 4, 0, TAB_CENTER | TAT_TITLE, _("Standardized Coefficients")); - tab_text (t, 4, 1, TAB_CENTER | TAT_TITLE, _("Beta")); - tab_text (t, 5, 1, TAB_CENTER | TAT_TITLE, _("t")); - tab_text (t, 6, 1, TAB_CENTER | TAT_TITLE, _("Sig.")); - - std_err = sqrt (gsl_matrix_get (linreg_cov (c), 0, 0)); - + struct pivot_table *table = pivot_table_create__ ( + pivot_value_new_text_format (N_("Coefficients (%s)"), + var_to_string (var))); + + struct pivot_dimension *statistics = pivot_dimension_create ( + table, PIVOT_AXIS_COLUMN, N_("Statistics")); + pivot_category_create_group (statistics->root, + N_("Unstandardized Coefficients"), + N_("B"), N_("Std. Error")); + pivot_category_create_group (statistics->root, + N_("Standardized Coefficients"), N_("Beta")); + pivot_category_create_leaves (statistics->root, N_("t"), + N_("Sig."), PIVOT_RC_SIGNIFICANCE); if (cmd->stats & STATS_CI) { - double lower = linreg_intercept (c) - tval * std_err ; - double upper = linreg_intercept (c) + tval * std_err ; - tab_double (t, 7, heading_rows, 0, lower, NULL, RC_OTHER); - tab_double (t, 8, heading_rows, 0, upper, NULL, RC_OTHER); - - tab_joint_text_format (t, 7, 0, 8, 0, TAB_CENTER | TAT_TITLE, _("%g%% Confidence Interval for B"), cmd->ci * 100); - tab_hline (t, TAL_1, 7, 8, 1); - tab_text (t, 7, 1, TAB_CENTER | TAT_TITLE, _("Lower Bound")); - tab_text (t, 8, 1, TAB_CENTER | TAT_TITLE, _("Upper Bound")); + struct pivot_category *interval = pivot_category_create_group__ ( + statistics->root, pivot_value_new_text_format ( + N_("%g%% Confidence Interval for B"), + cmd->ci * 100.0)); + pivot_category_create_leaves (interval, N_("Lower Bound"), + N_("Upper Bound")); } + struct pivot_dimension *variables = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Variables")); + + double df = linreg_n_obs (c) - linreg_n_coeffs (c) - 1; + double q = (1 - cmd->ci) / 2.0; /* 2-tailed test */ + double tval = gsl_cdf_tdist_Qinv (q, df); + if (!cmd->origin) { - tab_text (t, 1, this_row, TAB_LEFT | TAT_TITLE, _("(Constant)")); - tab_double (t, 2, this_row, 0, linreg_intercept (c), NULL, RC_OTHER); - tab_double (t, 3, this_row, 0, std_err, NULL, RC_OTHER); - tab_double (t, 4, this_row, 0, 0.0, NULL, RC_OTHER); - double t_stat = linreg_intercept (c) / std_err; - tab_double (t, 5, this_row, 0, t_stat, NULL, RC_OTHER); + int var_idx = pivot_category_create_leaf ( + variables->root, pivot_value_new_text (N_("(Constant)"))); - double pval = - 2 * gsl_cdf_tdist_Q (fabs (t_stat), - (double) (linreg_n_obs (c) - linreg_n_coeffs (c))); - tab_double (t, 6, this_row, 0, pval, NULL, RC_PVALUE); - this_row++; + double std_err = sqrt (gsl_matrix_get (linreg_cov (c), 0, 0)); + double t_stat = linreg_intercept (c) / std_err; + double entries[] = { + linreg_intercept (c), + std_err, + 0.0, + t_stat, + 2.0 * gsl_cdf_tdist_Q (fabs (t_stat), + linreg_n_obs (c) - linreg_n_coeffs (c)), + linreg_intercept (c) - tval * std_err, + linreg_intercept (c) + tval * std_err, + }; + for (size_t i = 0; i < sizeof entries / sizeof *entries; i++) + pivot_table_put2 (table, i, var_idx, + pivot_value_new_number (entries[i])); } - for (j = 0; j < linreg_n_coeffs (c); j++, this_row++) + for (size_t j = 0; j < linreg_n_coeffs (c); j++) { - struct string tstr; - ds_init_empty (&tstr); - - v = linreg_indep_var (c, j); - label = var_to_string (v); - /* Do not overwrite the variable's name. */ - ds_put_cstr (&tstr, label); - tab_text (t, 1, this_row, TAB_LEFT, ds_cstr (&tstr)); - /* - Regression coefficients. - */ - tab_double (t, 2, this_row, 0, linreg_coeff (c, j), NULL, RC_OTHER); - /* - Standard error of the coefficients. - */ - std_err = sqrt (gsl_matrix_get (linreg_cov (c), j + 1, j + 1)); - tab_double (t, 3, this_row, 0, std_err, NULL, RC_OTHER); - /* - Standardized coefficient, i.e., regression coefficient - if all variables had unit variance. - */ - beta = sqrt (gsl_matrix_get (cov, j, j)); - beta *= linreg_coeff (c, j) / - sqrt (gsl_matrix_get (cov, cov->size1 - 1, cov->size2 - 1)); - tab_double (t, 4, this_row, 0, beta, NULL, RC_OTHER); + const struct variable *v = linreg_indep_var (c, j); + int var_idx = pivot_category_create_leaf ( + variables->root, pivot_value_new_variable (v)); - /* - Test statistic for H0: coefficient is 0. - */ + double std_err = sqrt (gsl_matrix_get (linreg_cov (c), j + 1, j + 1)); double t_stat = linreg_coeff (c, j) / std_err; - tab_double (t, 5, this_row, 0, t_stat, NULL, RC_OTHER); - /* - P values for the test statistic above. - */ - pval = 2 * gsl_cdf_tdist_Q (fabs (t_stat), df); - tab_double (t, 6, this_row, 0, pval, NULL, RC_PVALUE); - ds_destroy (&tstr); - - if (cmd->stats & STATS_CI) - { - double lower = linreg_coeff (c, j) - tval * std_err ; - double upper = linreg_coeff (c, j) + tval * std_err ; - - tab_double (t, 7, this_row, 0, lower, NULL, RC_OTHER); - tab_double (t, 8, this_row, 0, upper, NULL, RC_OTHER); - } + double entries[] = { + linreg_coeff (c, j), + sqrt (gsl_matrix_get (linreg_cov (c), j + 1, j + 1)), + (sqrt (gsl_matrix_get (cov, j, j)) * linreg_coeff (c, j) / + sqrt (gsl_matrix_get (cov, cov->size1 - 1, cov->size2 - 1))), + t_stat, + 2 * gsl_cdf_tdist_Q (fabs (t_stat), df), + linreg_coeff (c, j) - tval * std_err, + linreg_coeff (c, j) + tval * std_err, + }; + for (size_t i = 0; i < sizeof entries / sizeof *entries; i++) + pivot_table_put2 (table, i, var_idx, + pivot_value_new_number (entries[i])); } - tab_title (t, _("Coefficients (%s)"), var_to_string (var)); - tab_submit (t); + + pivot_table_submit (table); } /* @@ -949,98 +896,84 @@ reg_stats_coeff (const struct linreg * c, const gsl_matrix *cov, const struct va static void reg_stats_anova (const struct linreg * c, const struct variable *var) { - int n_cols = 7; - int n_rows = 4; - const double msm = linreg_ssreg (c) / linreg_dfmodel (c); - const double mse = linreg_mse (c); - const double F = msm / mse; - const double pval = gsl_cdf_fdist_Q (F, linreg_dfmodel (c), - linreg_dferror (c)); - - struct tab_table *t; - - assert (c != NULL); - t = tab_create (n_cols, n_rows); - tab_headers (t, 2, 0, 1, 0); + struct pivot_table *table = pivot_table_create__ ( + pivot_value_new_text_format (N_("ANOVA (%s)"), var_to_string (var))); - tab_box (t, TAL_2, TAL_2, -1, TAL_1, 0, 0, n_cols - 1, n_rows - 1); + pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Statistics"), + N_("Sum of Squares"), PIVOT_RC_OTHER, + N_("df"), PIVOT_RC_INTEGER, + N_("Mean Square"), PIVOT_RC_OTHER, + N_("F"), PIVOT_RC_OTHER, + N_("Sig."), PIVOT_RC_SIGNIFICANCE); - tab_hline (t, TAL_2, 0, n_cols - 1, 1); - tab_vline (t, TAL_2, 2, 0, n_rows - 1); - tab_vline (t, TAL_0, 1, 0, 0); + pivot_dimension_create (table, PIVOT_AXIS_ROW, N_("Source"), + N_("Regression"), N_("Residual"), N_("Total")); - tab_text (t, 2, 0, TAB_CENTER | TAT_TITLE, _("Sum of Squares")); - tab_text (t, 3, 0, TAB_CENTER | TAT_TITLE, _("df")); - tab_text (t, 4, 0, TAB_CENTER | TAT_TITLE, _("Mean Square")); - tab_text (t, 5, 0, TAB_CENTER | TAT_TITLE, _("F")); - tab_text (t, 6, 0, TAB_CENTER | TAT_TITLE, _("Sig.")); + double msm = linreg_ssreg (c) / linreg_dfmodel (c); + double mse = linreg_mse (c); + double F = msm / mse; - tab_text (t, 1, 1, TAB_LEFT | TAT_TITLE, _("Regression")); - tab_text (t, 1, 2, TAB_LEFT | TAT_TITLE, _("Residual")); - tab_text (t, 1, 3, TAB_LEFT | TAT_TITLE, _("Total")); - - /* Sums of Squares */ - tab_double (t, 2, 1, 0, linreg_ssreg (c), NULL, RC_OTHER); - tab_double (t, 2, 3, 0, linreg_sst (c), NULL, RC_OTHER); - tab_double (t, 2, 2, 0, linreg_sse (c), NULL, RC_OTHER); - - - /* Degrees of freedom */ - tab_text_format (t, 3, 1, TAB_RIGHT, "%.*g", DBL_DIG + 1, linreg_dfmodel (c)); - tab_text_format (t, 3, 2, TAB_RIGHT, "%.*g", DBL_DIG + 1, linreg_dferror (c)); - tab_text_format (t, 3, 3, TAB_RIGHT, "%.*g", DBL_DIG + 1, linreg_dftotal (c)); - - /* Mean Squares */ - tab_double (t, 4, 1, TAB_RIGHT, msm, NULL, RC_OTHER); - tab_double (t, 4, 2, TAB_RIGHT, mse, NULL, RC_OTHER); - - tab_double (t, 5, 1, 0, F, NULL, RC_OTHER); - - tab_double (t, 6, 1, 0, pval, NULL, RC_PVALUE); + struct entry + { + int stat_idx; + int source_idx; + double x; + } + entries[] = { + /* Sums of Squares. */ + { 0, 0, linreg_ssreg (c) }, + { 0, 1, linreg_sse (c) }, + { 0, 2, linreg_sst (c) }, + /* Degrees of freedom. */ + { 1, 0, linreg_dfmodel (c) }, + { 1, 1, linreg_dferror (c) }, + { 1, 2, linreg_dftotal (c) }, + /* Mean Squares. */ + { 2, 0, msm }, + { 2, 1, mse }, + /* F */ + { 3, 0, F }, + /* Significance. */ + { 4, 0, gsl_cdf_fdist_Q (F, linreg_dfmodel (c), linreg_dferror (c)) }, + }; + for (size_t i = 0; i < sizeof entries / sizeof *entries; i++) + { + const struct entry *e = &entries[i]; + pivot_table_put2 (table, e->stat_idx, e->source_idx, + pivot_value_new_number (e->x)); + } - tab_title (t, _("ANOVA (%s)"), var_to_string (var)); - tab_submit (t); + pivot_table_submit (table); } static void reg_stats_bcov (const struct linreg * c, const struct variable *var) { - int n_cols; - int n_rows; - int i; - int k; - int row; - int col; - const char *label; - struct tab_table *t; - - assert (c != NULL); - n_cols = linreg_n_indeps (c) + 1 + 2; - n_rows = 2 * (linreg_n_indeps (c) + 1); - t = tab_create (n_cols, n_rows); - tab_headers (t, 2, 0, 1, 0); - tab_box (t, TAL_2, TAL_2, -1, TAL_1, 0, 0, n_cols - 1, n_rows - 1); - tab_hline (t, TAL_2, 0, n_cols - 1, 1); - tab_vline (t, TAL_2, 2, 0, n_rows - 1); - tab_vline (t, TAL_0, 1, 0, 0); - tab_text (t, 0, 0, TAB_CENTER | TAT_TITLE, _("Model")); - tab_text (t, 1, 1, TAB_CENTER | TAT_TITLE, _("Covariances")); - for (i = 0; i < linreg_n_coeffs (c); i++) + struct pivot_table *table = pivot_table_create__ ( + pivot_value_new_text_format (N_("Coefficient Correlations (%s)"), + var_to_string (var))); + + for (size_t i = 0; i < 2; i++) { - const struct variable *v = linreg_indep_var (c, i); - label = var_to_string (v); - tab_text (t, 2, i, TAB_CENTER, label); - tab_text (t, i + 2, 0, TAB_CENTER, label); - for (k = 1; k < linreg_n_coeffs (c); k++) - { - col = (i <= k) ? k : i; - row = (i <= k) ? i : k; - tab_double (t, k + 2, i, TAB_CENTER, - gsl_matrix_get (linreg_cov (c), row, col), NULL, RC_OTHER); - } + struct pivot_dimension *models = pivot_dimension_create ( + table, i ? PIVOT_AXIS_ROW : PIVOT_AXIS_COLUMN, N_("Models")); + for (size_t j = 0; j < linreg_n_coeffs (c); j++) + pivot_category_create_leaf ( + models->root, pivot_value_new_variable ( + linreg_indep_var (c, j))); } - tab_title (t, _("Coefficient Correlations (%s)"), var_to_string (var)); - tab_submit (t); + + pivot_dimension_create (table, PIVOT_AXIS_ROW, N_("Statistics"), + N_("Covariances")); + + for (size_t i = 0; i < linreg_n_coeffs (c); i++) + for (size_t k = 0; k < linreg_n_coeffs (c); k++) + { + double cov = gsl_matrix_get (linreg_cov (c), MIN (i, k), MAX (i, k)); + pivot_table_put3 (table, k, i, 0, pivot_value_new_number (cov)); + } + + pivot_table_submit (table); } diff --git a/src/language/stats/reliability.c b/src/language/stats/reliability.c index 27a4656723..756932ba89 100644 --- a/src/language/stats/reliability.c +++ b/src/language/stats/reliability.c @@ -31,7 +31,7 @@ #include "libpspp/misc.h" #include "libpspp/str.h" #include "math/moments.h" -#include "output/tab.h" +#include "output/pivot-table.h" #include "output/text-item.h" #include "gettext.h" @@ -536,345 +536,161 @@ static void case_processing_summary (casenumber n_valid, casenumber n_missing, const struct dictionary *dict) { - const struct fmt_spec *wfmt = dict_get_weight_format (dict); + struct pivot_table *table = pivot_table_create ( + N_("Case Processing Summary")); + pivot_table_set_weight_var (table, dict_get_weight (dict)); - casenumber total; - int n_cols = 4; - int n_rows = 4; - int heading_columns = 2; - int heading_rows = 1; - struct tab_table *tbl; - tbl = tab_create (n_cols, n_rows); - tab_set_format (tbl, RC_WEIGHT, wfmt); - tab_headers (tbl, heading_columns, 0, heading_rows, 0); + pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Statistics"), + N_("N"), PIVOT_RC_COUNT, + N_("Percent"), PIVOT_RC_PERCENT); - tab_title (tbl, _("Case Processing Summary")); + struct pivot_dimension *cases = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Cases"), N_("Valid"), N_("Excluded"), + N_("Total")); + cases->root->show_label = true; - /* Vertical lines for the data only */ - tab_box (tbl, - -1, -1, - -1, TAL_1, - heading_columns, 0, - n_cols - 1, n_rows - 1); + casenumber total = n_missing + n_valid; - /* Box around table */ - tab_box (tbl, - TAL_2, TAL_2, - -1, -1, - 0, 0, - n_cols - 1, n_rows - 1); - - - tab_hline (tbl, TAL_2, 0, n_cols - 1, heading_rows); - - tab_vline (tbl, TAL_2, heading_columns, 0, n_rows - 1); - - - tab_text (tbl, 0, heading_rows, TAB_LEFT | TAT_TITLE, - _("Cases")); - - tab_text (tbl, 1, heading_rows, TAB_LEFT | TAT_TITLE, - _("Valid")); - - tab_text (tbl, 1, heading_rows + 1, TAB_LEFT | TAT_TITLE, - _("Excluded")); - - tab_text (tbl, 1, heading_rows + 2, TAB_LEFT | TAT_TITLE, - _("Total")); - - tab_text (tbl, heading_columns, 0, TAB_CENTER | TAT_TITLE, - _("N")); - - tab_text (tbl, heading_columns + 1, 0, TAB_CENTER | TAT_TITLE, _("%")); - - total = n_missing + n_valid; - - tab_double (tbl, 2, heading_rows, TAB_RIGHT, - n_valid, NULL, RC_WEIGHT); - - - tab_double (tbl, 2, heading_rows + 1, TAB_RIGHT, - n_missing, NULL, RC_WEIGHT); - - - tab_double (tbl, 2, heading_rows + 2, TAB_RIGHT, - total, NULL, RC_WEIGHT); - - - tab_double (tbl, 3, heading_rows, TAB_RIGHT, - 100 * n_valid / (double) total, NULL, RC_OTHER); - - - tab_double (tbl, 3, heading_rows + 1, TAB_RIGHT, - 100 * n_missing / (double) total, NULL, RC_OTHER); - - - tab_double (tbl, 3, heading_rows + 2, TAB_RIGHT, - 100 * total / (double) total, NULL, RC_OTHER); + struct entry + { + int stat_idx; + int case_idx; + double x; + } + entries[] = { + { 0, 0, n_valid }, + { 0, 1, n_missing }, + { 0, 2, total }, + { 1, 0, 100.0 * n_valid / total }, + { 1, 1, 100.0 * n_missing / total }, + { 1, 2, 100.0 } + }; + for (size_t i = 0; i < sizeof entries / sizeof *entries; i++) + { + const struct entry *e = &entries[i]; + pivot_table_put2 (table, e->stat_idx, e->case_idx, + pivot_value_new_number (e->x)); + } - tab_submit (tbl); + pivot_table_submit (table); } - - static void reliability_summary_total (const struct reliability *rel) { - int i; - const int n_cols = 5; - const int heading_columns = 1; - const int heading_rows = 1; - const int n_rows = rel->sc[0].n_items + heading_rows ; - const struct variable *wv = rel->wv; - const struct fmt_spec *wfmt = wv ? var_get_print_format (wv) : & F_8_0; - struct tab_table *tbl = tab_create (n_cols, n_rows); - tab_set_format (tbl, RC_WEIGHT, wfmt); - tab_headers (tbl, heading_columns, 0, heading_rows, 0); - - tab_title (tbl, _("Item-Total Statistics")); - - /* Vertical lines for the data only */ - tab_box (tbl, - -1, -1, - -1, TAL_1, - heading_columns, 0, - n_cols - 1, n_rows - 1); - - /* Box around table */ - tab_box (tbl, - TAL_2, TAL_2, - -1, -1, - 0, 0, - n_cols - 1, n_rows - 1); - - - tab_hline (tbl, TAL_2, 0, n_cols - 1, heading_rows); - - tab_vline (tbl, TAL_2, heading_columns, 0, n_rows - 1); - - tab_text (tbl, 1, 0, TAB_CENTER | TAT_TITLE, - _("Scale Mean if Item Deleted")); + struct pivot_table *table = pivot_table_create (N_("Item-Total Statistics")); - tab_text (tbl, 2, 0, TAB_CENTER | TAT_TITLE, - _("Scale Variance if Item Deleted")); + pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Statistics"), + N_("Scale Mean if Item Deleted"), + N_("Scale Variance if Item Deleted"), + N_("Corrected Item-Total Correlation"), + N_("Cronbach's Alpha if Item Deleted")); - tab_text (tbl, 3, 0, TAB_CENTER | TAT_TITLE, - _("Corrected Item-Total Correlation")); + struct pivot_dimension *variables = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Variables")); - tab_text (tbl, 4, 0, TAB_CENTER | TAT_TITLE, - _("Cronbach's Alpha if Item Deleted")); - - - for (i = 0 ; i < rel->sc[0].n_items; ++i) + for (size_t i = 0 ; i < rel->sc[0].n_items; ++i) { - double cov, item_to_total_r; - double mean, weight, var; - const struct cronbach *s = &rel->sc[rel->total_start + i]; - tab_text (tbl, 0, heading_rows + i, TAB_LEFT| TAT_TITLE, - var_to_string (rel->sc[0].items[i])); - - moments1_calculate (s->total, &weight, &mean, &var, 0, 0); - - tab_double (tbl, 1, heading_rows + i, TAB_RIGHT, - mean, NULL, RC_OTHER); - - tab_double (tbl, 2, heading_rows + i, TAB_RIGHT, - s->variance_of_sums, NULL, RC_OTHER); - - tab_double (tbl, 4, heading_rows + i, TAB_RIGHT, - s->alpha, NULL, RC_OTHER); - - moments1_calculate (rel->sc[0].m[i], &weight, &mean, &var, 0,0); - cov = rel->sc[0].variance_of_sums + var - s->variance_of_sums; - cov /= 2.0; - - item_to_total_r = (cov - var) / (sqrt(var) * sqrt (s->variance_of_sums)); - - - tab_double (tbl, 3, heading_rows + i, TAB_RIGHT, - item_to_total_r, NULL, RC_OTHER); + int var_idx = pivot_category_create_leaf ( + variables->root, pivot_value_new_variable (rel->sc[0].items[i])); + + double mean; + moments1_calculate (s->total, NULL, &mean, NULL, NULL, NULL); + + double var; + moments1_calculate (rel->sc[0].m[i], NULL, NULL, &var, NULL, NULL); + double cov + = (rel->sc[0].variance_of_sums + var - s->variance_of_sums) / 2.0; + + double entries[] = { + mean, + s->variance_of_sums, + (cov - var) / sqrt (var * s->variance_of_sums), + s->alpha, + }; + for (size_t i = 0; i < sizeof entries / sizeof *entries; i++) + pivot_table_put2 (table, i, var_idx, + pivot_value_new_number (entries[i])); } - - tab_submit (tbl); + pivot_table_submit (table); } -static void reliability_statistics_model_alpha (struct tab_table *tbl, - const struct reliability *rel); - -static void reliability_statistics_model_split (struct tab_table *tbl, - const struct reliability *rel); - - -struct reliability_output_table -{ - int n_cols; - int n_rows; - int heading_cols; - int heading_rows; - void (*populate) (struct tab_table *, const struct reliability *); -}; - - -static struct reliability_output_table rol[2] = - { - { 2, 2, 1, 1, reliability_statistics_model_alpha}, - { 4, 9, 3, 0, reliability_statistics_model_split} - }; - static void reliability_statistics (const struct reliability *rel) { - int n_cols = rol[rel->model].n_cols; - int n_rows = rol[rel->model].n_rows; - int heading_columns = rol[rel->model].heading_cols; - int heading_rows = rol[rel->model].heading_rows; - const struct variable *wv = rel->wv; - const struct fmt_spec *wfmt = wv ? var_get_print_format (wv) : & F_8_0; - struct tab_table *tbl = tab_create (n_cols, n_rows); - tab_set_format (tbl, RC_WEIGHT, wfmt); - - tab_headers (tbl, heading_columns, 0, heading_rows, 0); - - tab_title (tbl, _("Reliability Statistics")); - - /* Vertical lines for the data only */ - tab_box (tbl, - -1, -1, - -1, TAL_1, - heading_columns, 0, - n_cols - 1, n_rows - 1); - - /* Box around table */ - tab_box (tbl, - TAL_2, TAL_2, - -1, -1, - 0, 0, - n_cols - 1, n_rows - 1); - - - tab_hline (tbl, TAL_2, 0, n_cols - 1, heading_rows); - - tab_vline (tbl, TAL_2, heading_columns, 0, n_rows - 1); - - if ( rel->model == MODEL_ALPHA ) - reliability_statistics_model_alpha (tbl, rel); - else if (rel->model == MODEL_SPLIT ) - reliability_statistics_model_split (tbl, rel); - - tab_submit (tbl); -} - - -static void -reliability_statistics_model_alpha (struct tab_table *tbl, - const struct reliability *rel) -{ - const struct cronbach *s = &rel->sc[0]; - - tab_text (tbl, 0, 0, TAB_CENTER | TAT_TITLE, - _("Cronbach's Alpha")); - - tab_text (tbl, 1, 0, TAB_CENTER | TAT_TITLE, - _("N of Items")); - - tab_double (tbl, 0, 1, TAB_RIGHT, s->alpha, NULL, RC_OTHER); - - tab_double (tbl, 1, 1, TAB_RIGHT, s->n_items, NULL, RC_WEIGHT); -} - - -static void -reliability_statistics_model_split (struct tab_table *tbl, - const struct reliability *rel) -{ - tab_text (tbl, 0, 0, TAB_LEFT, - _("Cronbach's Alpha")); - - tab_text (tbl, 1, 0, TAB_LEFT, - _("Part 1")); - - tab_text (tbl, 2, 0, TAB_LEFT, - _("Value")); - - tab_text (tbl, 2, 1, TAB_LEFT, - _("N of Items")); - - tab_text (tbl, 1, 2, TAB_LEFT, - _("Part 2")); - - tab_text (tbl, 2, 2, TAB_LEFT, - _("Value")); + struct pivot_table *table = pivot_table_create ( + N_("Reliability Statistics")); + pivot_table_set_weight_var (table, rel->wv); - tab_text (tbl, 2, 3, TAB_LEFT, - _("N of Items")); - - tab_text (tbl, 1, 4, TAB_LEFT, - _("Total N of Items")); - - tab_text (tbl, 0, 5, TAB_LEFT, - _("Correlation Between Forms")); - - tab_text (tbl, 0, 6, TAB_LEFT, - _("Spearman-Brown Coefficient")); - - tab_text (tbl, 1, 6, TAB_LEFT, - _("Equal Length")); - - tab_text (tbl, 1, 7, TAB_LEFT, - _("Unequal Length")); - - - tab_text (tbl, 0, 8, TAB_LEFT, - _("Guttman Split-Half Coefficient")); - - - - tab_double (tbl, 3, 0, TAB_RIGHT, rel->sc[1].alpha, NULL, RC_OTHER); - tab_double (tbl, 3, 2, TAB_RIGHT, rel->sc[2].alpha, NULL, RC_OTHER); - - tab_double (tbl, 3, 1, TAB_RIGHT, rel->sc[1].n_items, NULL, RC_WEIGHT); - tab_double (tbl, 3, 3, TAB_RIGHT, rel->sc[2].n_items, NULL, RC_WEIGHT); - - tab_double (tbl, 3, 4, TAB_RIGHT, - rel->sc[1].n_items + rel->sc[2].n_items, NULL, RC_WEIGHT); - - { - /* R is the correlation between the two parts */ - double r = rel->sc[0].variance_of_sums - - rel->sc[1].variance_of_sums - - rel->sc[2].variance_of_sums ; - - /* Guttman Split Half Coefficient */ - double g = 2 * r / rel->sc[0].variance_of_sums; - - /* Unequal Length Spearman Brown Coefficient, and - intermediate value used in the computation thereof */ - double uly, tmp; - - r /= sqrt (rel->sc[1].variance_of_sums); - r /= sqrt (rel->sc[2].variance_of_sums); - r /= 2.0; - - tab_double (tbl, 3, 5, TAB_RIGHT, r, NULL, RC_OTHER); - - /* Equal length Spearman-Brown Coefficient */ - tab_double (tbl, 3, 6, TAB_RIGHT, 2 * r / (1.0 + r), NULL, RC_OTHER); - - tab_double (tbl, 3, 8, TAB_RIGHT, g, NULL, RC_OTHER); - - tmp = (1.0 - r*r) * rel->sc[1].n_items * rel->sc[2].n_items / - pow2 (rel->sc[0].n_items); - - uly = sqrt( pow4 (r) + 4 * pow2 (r) * tmp); - uly -= pow2 (r); - uly /= 2 * tmp; + if (rel->model == MODEL_ALPHA) + { + pivot_dimension_create (table, PIVOT_AXIS_COLUMN, + N_("Statistics"), + N_("Cronbach's Alpha"), PIVOT_RC_OTHER, + N_("N of Items"), PIVOT_RC_COUNT); + + const struct cronbach *s = &rel->sc[0]; + pivot_table_put1 (table, 0, pivot_value_new_number (s->alpha)); + pivot_table_put1 (table, 1, pivot_value_new_number (s->n_items)); + } + else + { + struct pivot_dimension *statistics = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Statistics")); + struct pivot_category *alpha = pivot_category_create_group ( + statistics->root, N_("Cronbach's Alpha")); + pivot_category_create_group (alpha, N_("Part 1"), + N_("Value"), PIVOT_RC_OTHER, + N_("N of Items"), PIVOT_RC_COUNT); + pivot_category_create_group (alpha, N_("Part 2"), + N_("Value"), PIVOT_RC_OTHER, + N_("N of Items"), PIVOT_RC_COUNT); + pivot_category_create_leaves (alpha, + N_("Total N of Items"), PIVOT_RC_COUNT); + pivot_category_create_leaves (statistics->root, + N_("Correlation Between Forms"), + PIVOT_RC_OTHER); + pivot_category_create_group (statistics->root, + N_("Spearman-Brown Coefficient"), + N_("Equal Length"), PIVOT_RC_OTHER, + N_("Unequal Length"), PIVOT_RC_OTHER); + pivot_category_create_leaves (statistics->root, + N_("Guttman Split-Half Coefficient"), + PIVOT_RC_OTHER); + + /* R is the correlation between the two parts */ + double r0 = rel->sc[0].variance_of_sums - + rel->sc[1].variance_of_sums - + rel->sc[2].variance_of_sums ; + double r1 = (r0 / sqrt (rel->sc[1].variance_of_sums) + / sqrt (rel->sc[2].variance_of_sums) + / 2.0); + + /* Guttman Split Half Coefficient */ + double g = 2 * r0 / rel->sc[0].variance_of_sums; + + double tmp = (1.0 - r1*r1) * rel->sc[1].n_items * rel->sc[2].n_items / + pow2 (rel->sc[0].n_items); + + double entries[] = { + rel->sc[1].alpha, + rel->sc[1].n_items, + rel->sc[2].alpha, + rel->sc[2].n_items, + rel->sc[1].n_items + rel->sc[2].n_items, + r1, + 2 * r1 / (1.0 + r1), + (sqrt ( pow4 (r1) + 4 * pow2 (r1) * tmp) - pow2 (r1)) / (2 * tmp), + g, + }; + for (size_t i = 0; i < sizeof entries / sizeof *entries; i++) + pivot_table_put1 (table, i, pivot_value_new_number (entries[i])); + } - tab_double (tbl, 3, 7, TAB_RIGHT, uly, NULL, RC_OTHER); - } + pivot_table_submit (table); } - diff --git a/src/language/stats/roc.c b/src/language/stats/roc.c index 7d13c2c2cb..eb2430a254 100644 --- a/src/language/stats/roc.c +++ b/src/language/stats/roc.c @@ -35,7 +35,7 @@ #include "math/sort.h" #include "output/chart-item.h" #include "output/charts/roc-chart.h" -#include "output/tab.h" +#include "output/pivot-table.h" #include "gettext.h" #define _(msgid) gettext (msgid) @@ -963,229 +963,161 @@ do_roc (struct cmd_roc *roc, struct casereader *reader, struct dictionary *dict) static void show_auc (struct roc_state *rs, const struct cmd_roc *roc) { - int i; - const int n_fields = roc->print_se ? 5 : 1; - const int n_cols = roc->n_vars > 1 ? n_fields + 1: n_fields; - const int n_rows = 2 + roc->n_vars; - struct tab_table *tbl = tab_create (n_cols, n_rows); - - if ( roc->n_vars > 1) - tab_title (tbl, _("Area Under the Curve")); - else - tab_title (tbl, _("Area Under the Curve (%s)"), var_to_string (roc->vars[0])); - - tab_headers (tbl, n_cols - n_fields, 0, 1, 0); - - - tab_text (tbl, n_cols - n_fields, 1, TAT_TITLE, _("Area")); - - tab_hline (tbl, TAL_2, 0, n_cols - 1, 2); + struct pivot_table *table = pivot_table_create (N_("Area Under the Curve")); - tab_box (tbl, - TAL_2, TAL_2, - -1, TAL_1, - 0, 0, - n_cols - 1, - n_rows - 1); - - if ( roc->print_se ) + struct pivot_dimension *statistics = pivot_dimension_create ( + table, PIVOT_AXIS_COLUMN, N_("Statistics"), + N_("Area"), PIVOT_RC_OTHER); + if (roc->print_se) { - tab_text (tbl, n_cols - 4, 1, TAT_TITLE, _("Std. Error")); - tab_text (tbl, n_cols - 3, 1, TAT_TITLE, _("Asymptotic Sig.")); - - tab_text (tbl, n_cols - 2, 1, TAT_TITLE, _("Lower Bound")); - tab_text (tbl, n_cols - 1, 1, TAT_TITLE, _("Upper Bound")); - - tab_joint_text_format (tbl, n_cols - 2, 0, 4, 0, - TAT_TITLE | TAB_CENTER, - _("Asymp. %g%% Confidence Interval"), roc->ci); - tab_vline (tbl, 0, n_cols - 1, 0, 0); - tab_hline (tbl, TAL_1, n_cols - 2, n_cols - 1, 1); + pivot_category_create_leaves ( + statistics->root, + N_("Std. Error"), PIVOT_RC_OTHER, + N_("Asymptotic Sig."), PIVOT_RC_SIGNIFICANCE); + struct pivot_category *interval = pivot_category_create_group__ ( + statistics->root, + pivot_value_new_text_format (N_("Asymp. %g%% Confidence Interval"), + roc->ci)); + pivot_category_create_leaves (interval, + N_("Lower Bound"), PIVOT_RC_OTHER, + N_("Upper Bound"), PIVOT_RC_OTHER); } - if ( roc->n_vars > 1) - tab_text (tbl, 0, 1, TAT_TITLE, _("Variable under test")); + struct pivot_dimension *variables = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Variable under test")); + variables->root->show_label = true; - if ( roc->n_vars > 1) - tab_vline (tbl, TAL_2, 1, 0, n_rows - 1); - - - for ( i = 0 ; i < roc->n_vars ; ++i ) + for (size_t i = 0 ; i < roc->n_vars ; ++i ) { - tab_text (tbl, 0, 2 + i, TAT_TITLE, var_to_string (roc->vars[i])); + int var_idx = pivot_category_create_leaf ( + variables->root, pivot_value_new_variable (roc->vars[i])); - tab_double (tbl, n_cols - n_fields, 2 + i, 0, rs[i].auc, NULL, RC_OTHER); + pivot_table_put2 (table, 0, var_idx, pivot_value_new_number (rs[i].auc)); if ( roc->print_se ) { - double se ; - const double sd_0_5 = sqrt ((rs[i].n1 + rs[i].n2 + 1) / - (12 * rs[i].n1 * rs[i].n2)); - double ci ; - double yy ; - - se = rs[i].auc * (1 - rs[i].auc) + (rs[i].n1 - 1) * (rs[i].q1hat - pow2 (rs[i].auc)) + - (rs[i].n2 - 1) * (rs[i].q2hat - pow2 (rs[i].auc)); - + double se = (rs[i].auc * (1 - rs[i].auc) + + (rs[i].n1 - 1) * (rs[i].q1hat - pow2 (rs[i].auc)) + + (rs[i].n2 - 1) * (rs[i].q2hat - pow2 (rs[i].auc))); se /= rs[i].n1 * rs[i].n2; - se = sqrt (se); - tab_double (tbl, n_cols - 4, 2 + i, 0, - se, - NULL, RC_OTHER); - - ci = 1 - roc->ci / 100.0; - yy = gsl_cdf_gaussian_Qinv (ci, se) ; - - tab_double (tbl, n_cols - 2, 2 + i, 0, - rs[i].auc - yy, - NULL, RC_OTHER); - - tab_double (tbl, n_cols - 1, 2 + i, 0, - rs[i].auc + yy, - NULL, RC_OTHER); - - tab_double (tbl, n_cols - 3, 2 + i, 0, - 2.0 * gsl_cdf_ugaussian_Q (fabs ((rs[i].auc - 0.5 ) / sd_0_5)), - NULL, RC_PVALUE); + double ci = 1 - roc->ci / 100.0; + double yy = gsl_cdf_gaussian_Qinv (ci, se); + + double sd_0_5 = sqrt ((rs[i].n1 + rs[i].n2 + 1) / + (12 * rs[i].n1 * rs[i].n2)); + double sig = 2.0 * gsl_cdf_ugaussian_Q (fabs ((rs[i].auc - 0.5) + / sd_0_5)); + double entries[] = { se, sig, rs[i].auc - yy, rs[i].auc + yy }; + for (size_t i = 0; i < sizeof entries / sizeof *entries; i++) + pivot_table_put2 (table, i + 1, var_idx, + pivot_value_new_number (entries[i])); } } - tab_submit (tbl); + pivot_table_submit (table); } static void show_summary (const struct cmd_roc *roc) { - const int n_cols = 3; - const int n_rows = 4; - struct tab_table *tbl = tab_create (n_cols, n_rows); - - tab_title (tbl, _("Case Summary")); - - tab_headers (tbl, 1, 0, 2, 0); - - tab_box (tbl, - TAL_2, TAL_2, - -1, -1, - 0, 0, - n_cols - 1, - n_rows - 1); - - tab_hline (tbl, TAL_2, 0, n_cols - 1, 2); - tab_vline (tbl, TAL_2, 1, 0, n_rows - 1); - - - tab_hline (tbl, TAL_2, 1, n_cols - 1, 1); - tab_vline (tbl, TAL_1, 2, 1, n_rows - 1); - + struct pivot_table *table = pivot_table_create (N_("Case Summary")); - tab_text (tbl, 0, 1, TAT_TITLE | TAB_LEFT, var_to_string (roc->state_var)); - tab_text (tbl, 1, 1, TAT_TITLE, _("Unweighted")); - tab_text (tbl, 2, 1, TAT_TITLE, _("Weighted")); + struct pivot_dimension *statistics = pivot_dimension_create ( + table, PIVOT_AXIS_COLUMN, N_("Valid N (listwise)"), + N_("Unweighted"), PIVOT_RC_INTEGER, + N_("Weighted"), PIVOT_RC_OTHER); + statistics->root->show_label = true; - tab_joint_text (tbl, 1, 0, 2, 0, - TAT_TITLE | TAB_CENTER, - _("Valid N (listwise)")); + struct pivot_dimension *cases = pivot_dimension_create__ ( + table, PIVOT_AXIS_ROW, pivot_value_new_variable (roc->state_var)); + cases->root->show_label = true; + pivot_category_create_leaves (cases->root, N_("Positive"), N_("Negative")); - - tab_text (tbl, 0, 2, TAB_LEFT, _("Positive")); - tab_text (tbl, 0, 3, TAB_LEFT, _("Negative")); - - - tab_double (tbl, 1, 2, 0, roc->pos, NULL, RC_INTEGER); - tab_double (tbl, 1, 3, 0, roc->neg, NULL, RC_INTEGER); - - tab_double (tbl, 2, 2, 0, roc->pos_weighted, NULL, RC_OTHER); - tab_double (tbl, 2, 3, 0, roc->neg_weighted, NULL, RC_OTHER); - - tab_submit (tbl); + struct entry + { + int stat_idx; + int case_idx; + double x; + } + entries[] = { + { 0, 0, roc->pos }, + { 0, 1, roc->neg }, + { 1, 0, roc->pos_weighted }, + { 1, 1, roc->neg_weighted }, + }; + for (size_t i = 0; i < sizeof entries / sizeof *entries; i++) + { + const struct entry *e = &entries[i]; + pivot_table_put2 (table, e->stat_idx, e->case_idx, + pivot_value_new_number (e->x)); + } + pivot_table_submit (table); } - static void show_coords (struct roc_state *rs, const struct cmd_roc *roc) { - int x = 1; - int i; - const int n_cols = roc->n_vars > 1 ? 4 : 3; - int n_rows = 1; - struct tab_table *tbl ; - - for (i = 0; i < roc->n_vars; ++i) - n_rows += casereader_count_cases (rs[i].cutpoint_rdr); - - tbl = tab_create (n_cols, n_rows); + struct pivot_table *table = pivot_table_create ( + N_("Coordinates of the Curve")); + table->omit_empty = true; - if ( roc->n_vars > 1) - tab_title (tbl, _("Coordinates of the Curve")); - else - tab_title (tbl, _("Coordinates of the Curve (%s)"), var_to_string (roc->vars[0])); - - - tab_headers (tbl, 1, 0, 1, 0); - - tab_hline (tbl, TAL_2, 0, n_cols - 1, 1); + pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Statistics"), + N_("Positive if greater than or equal to"), + N_("Sensitivity"), N_("1 - Specificity")); - if ( roc->n_vars > 1) - tab_text (tbl, 0, 0, TAT_TITLE, _("Test variable")); + struct pivot_dimension *coordinates = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Coordinates")); + coordinates->hide_all_labels = true; - tab_text (tbl, n_cols - 3, 0, TAT_TITLE, _("Positive if greater than or equal to")); - tab_text (tbl, n_cols - 2, 0, TAT_TITLE, _("Sensitivity")); - tab_text (tbl, n_cols - 1, 0, TAT_TITLE, _("1 - Specificity")); + struct pivot_dimension *variables = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Test variable")); + variables->root->show_label = true; - tab_box (tbl, - TAL_2, TAL_2, - -1, TAL_1, - 0, 0, - n_cols - 1, - n_rows - 1); - if ( roc->n_vars > 1) - tab_vline (tbl, TAL_2, 1, 0, n_rows - 1); - - for (i = 0; i < roc->n_vars; ++i) + int n_coords = 0; + for (size_t i = 0; i < roc->n_vars; ++i) { - struct ccase *cc; struct casereader *r = casereader_clone (rs[i].cutpoint_rdr); - if ( roc->n_vars > 1) - tab_text (tbl, 0, x, TAT_TITLE, var_to_string (roc->vars[i])); - - if ( i > 0) - tab_hline (tbl, TAL_1, 0, n_cols - 1, x); + int var_idx = pivot_category_create_leaf ( + variables->root, pivot_value_new_variable (roc->vars[i])); - - for (; (cc = casereader_read (r)) != NULL; - case_unref (cc), x++) + struct ccase *cc; + int coord_idx = 0; + for (; (cc = casereader_read (r)) != NULL; case_unref (cc)) { const double se = case_data_idx (cc, ROC_TP)->f / - ( - case_data_idx (cc, ROC_TP)->f - + - case_data_idx (cc, ROC_FN)->f - ); + (case_data_idx (cc, ROC_TP)->f + case_data_idx (cc, ROC_FN)->f); const double sp = case_data_idx (cc, ROC_TN)->f / - ( - case_data_idx (cc, ROC_TN)->f - + - case_data_idx (cc, ROC_FP)->f - ); - - tab_double (tbl, n_cols - 3, x, 0, case_data_idx (cc, ROC_CUTPOINT)->f, - var_get_print_format (roc->vars[i]), RC_OTHER); - - tab_double (tbl, n_cols - 2, x, 0, se, NULL, RC_OTHER); - tab_double (tbl, n_cols - 1, x, 0, 1 - sp, NULL, RC_OTHER); + (case_data_idx (cc, ROC_TN)->f + case_data_idx (cc, ROC_FP)->f); + + pivot_table_put3 ( + table, 0, coord_idx, var_idx, + pivot_value_new_var_value (roc->vars[i], + case_data_idx (cc, ROC_CUTPOINT))); + + pivot_table_put3 (table, 1, coord_idx, var_idx, + pivot_value_new_number (se)); + pivot_table_put3 (table, 2, coord_idx, var_idx, + pivot_value_new_number (1 - sp)); + coord_idx++; } + if (coord_idx > n_coords) + n_coords = coord_idx; + casereader_destroy (r); } - tab_submit (tbl); + for (size_t i = 0; i < n_coords; i++) + pivot_category_create_leaf (coordinates->root, + pivot_value_new_integer (i + 1)); + + pivot_table_submit (table); } diff --git a/src/language/stats/runs.c b/src/language/stats/runs.c index 9a32a530e8..eb95372ae8 100644 --- a/src/language/stats/runs.c +++ b/src/language/stats/runs.c @@ -35,9 +35,10 @@ #include "libpspp/misc.h" #include "math/percentiles.h" #include "math/sort.h" -#include "output/tab.h" +#include "output/pivot-table.h" #include "gettext.h" +#define N_(msgid) msgid #define _(msgid) gettext (msgid) @@ -308,99 +309,49 @@ runs_execute (const struct dataset *ds, static void show_runs_result (const struct runs_test *rt, const struct run_state *rs, const struct dictionary *dict) { - const struct fmt_spec *wfmt = dict_get_weight_format (dict); - const struct one_sample_test *otp = &rt->parent; - int i; - const int row_headers = 1; - const int column_headers = 1; - struct tab_table *table = - tab_create (row_headers + otp->n_vars, column_headers + 7); - tab_set_format (table, RC_WEIGHT, wfmt); - - tab_headers (table, row_headers, 0, column_headers, 0); - - tab_title (table, _("Runs Test")); - - /* Box around the table and vertical lines inside*/ - tab_box (table, TAL_2, TAL_2, -1, TAL_1, - 0, 0, tab_nc (table) - 1, tab_nr (table) - 1 ); - - tab_hline (table, TAL_2, 0, tab_nc (table) -1, column_headers); - tab_vline (table, TAL_2, row_headers, 0, tab_nr (table) - 1); - - for (i = 0 ; i < otp->n_vars; ++i) + struct pivot_table *table = pivot_table_create (N_("Runs Test")); + pivot_table_set_weight_var (table, dict_get_weight (dict)); + + pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Statistics"), + (rt->cp_mode == CP_CUSTOM ? N_("Test Value") + : rt->cp_mode == CP_MODE ? N_("Test Value (mode)") + : rt->cp_mode == CP_MEAN ? N_("Test Value (mean)") + : N_("Test Value (median)")), PIVOT_RC_OTHER, + N_("Cases < Test Value"), PIVOT_RC_COUNT, + N_("Cases ≥ Test Value"), PIVOT_RC_COUNT, + N_("Total Cases"), PIVOT_RC_COUNT, + N_("Number of Runs"), PIVOT_RC_INTEGER, + N_("Z"), PIVOT_RC_OTHER, + N_("Asymp. Sig. (2-tailed)"), PIVOT_RC_SIGNIFICANCE); + + struct pivot_dimension *variables = pivot_dimension_create ( + table, PIVOT_AXIS_COLUMN, N_("Variable")); + + for (size_t i = 0 ; i < otp->n_vars; ++i) { const struct run_state *run = &rs[i]; - double z = runs_statistic (run); - - tab_text (table, row_headers + i, 0, - TAT_TITLE | TAB_CENTER , - var_to_string (otp->vars[i])); - - tab_double (table, row_headers +i, 1, 0, - run->cutpoint, NULL, RC_OTHER); + int col = pivot_category_create_leaf ( + variables->root, pivot_value_new_variable (otp->vars[i])); - tab_double (table, row_headers +i, 2, 0, - run->nn, NULL, RC_WEIGHT); - - tab_double (table, row_headers +i, 3, 0, - run->np, NULL, RC_WEIGHT); - - tab_double (table, row_headers +i, 4, 0, - run->n, NULL, RC_WEIGHT); - - tab_double (table, row_headers +i, 5, 0, - run->runs, NULL, RC_INTEGER); - - tab_double (table, row_headers +i, 6, 0, - z, NULL, RC_OTHER); - - tab_double (table, row_headers +i, 7, 0, - 2.0 * (1.0 - gsl_cdf_ugaussian_P (z)), NULL, RC_PVALUE); - } + double z = runs_statistic (run); - switch ( rt->cp_mode) - { - case CP_CUSTOM: - tab_text (table, 0, column_headers , - TAT_TITLE | TAB_LEFT , _("Test Value")); - break; - case CP_MODE: - tab_text (table, 0, column_headers , - TAT_TITLE | TAB_LEFT , _("Test Value (mode)")); - break; - case CP_MEAN: - tab_text (table, 0, column_headers , - TAT_TITLE | TAB_LEFT , _("Test Value (mean)")); - break; - case CP_MEDIAN: - tab_text (table, 0, column_headers , - TAT_TITLE | TAB_LEFT , _("Test Value (median)")); - break; + double rows[] = { + run->cutpoint, + run->nn, + run->np, + run->n, + run->runs, + z, + 2.0 * (1.0 - gsl_cdf_ugaussian_P (z)), + }; + + for (int row = 0; row < sizeof rows / sizeof *rows; row++) + pivot_table_put2 (table, row, col, pivot_value_new_number (rows[row])); } - tab_text (table, 0, column_headers + 1, - TAT_TITLE | TAB_LEFT , _("Cases < Test Value")); - - tab_text (table, 0, column_headers + 2, - TAT_TITLE | TAB_LEFT , _("Cases ≥ Test Value")); - - tab_text (table, 0, column_headers + 3, - TAT_TITLE | TAB_LEFT , _("Total Cases")); - - tab_text (table, 0, column_headers + 4, - TAT_TITLE | TAB_LEFT , _("Number of Runs")); - - tab_text (table, 0, column_headers + 5, - TAT_TITLE | TAB_LEFT , _("Z")); - - tab_text (table, 0, column_headers + 6, - TAT_TITLE | TAB_LEFT , _("Asymp. Sig. (2-tailed)")); - - tab_submit (table); + pivot_table_submit (table); } - - diff --git a/src/language/stats/sign.c b/src/language/stats/sign.c index e16298a6ba..30de7d1e9b 100644 --- a/src/language/stats/sign.c +++ b/src/language/stats/sign.c @@ -29,12 +29,13 @@ #include "data/variable.h" #include "language/stats/npar.h" #include "libpspp/str.h" -#include "output/tab.h" +#include "output/pivot-table.h" #include "gl/minmax.h" #include "gl/xalloc.h" #include "gettext.h" +#define N_(msgid) msgid #define _(msgid) gettext (msgid) struct sign_test_params @@ -47,117 +48,80 @@ struct sign_test_params double point_prob; }; +static int +add_pair_leaf (struct pivot_dimension *dimension, variable_pair *pair) +{ + char *label = xasprintf ("%s - %s", var_to_string ((*pair)[0]), + var_to_string ((*pair)[1])); + return pivot_category_create_leaf ( + dimension->root, + pivot_value_new_user_text_nocopy (label)); +} static void output_frequency_table (const struct two_sample_test *t2s, const struct sign_test_params *param, const struct dictionary *dict) { - int i; - struct tab_table *table = tab_create (3, 1 + 4 * t2s->n_pairs); - - const struct fmt_spec *wfmt = dict_get_weight_format (dict); - - tab_set_format (table, RC_WEIGHT, wfmt); - tab_title (table, _("Frequencies")); - - tab_headers (table, 2, 0, 1, 0); + struct pivot_table *table = pivot_table_create (N_("Frequencies")); + pivot_table_set_weight_var (table, dict_get_weight (dict)); - /* Vertical lines inside the box */ - tab_box (table, 0, 0, -1, TAL_1, - 1, 0, tab_nc (table) - 1, tab_nr (table) - 1 ); + pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("N"), + N_("N"), PIVOT_RC_COUNT); - /* Box around entire table */ - tab_box (table, TAL_2, TAL_2, -1, -1, - 0, 0, tab_nc (table) - 1, tab_nr (table) - 1 ); + pivot_dimension_create (table, PIVOT_AXIS_ROW, N_("Differences"), + N_("Negative Differences"), + N_("Positive Differences"), + N_("Ties"), N_("Total")); - tab_text (table, 2, 0, TAB_CENTER, _("N")); + struct pivot_dimension *pairs = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Pairs")); - for (i = 0 ; i < t2s->n_pairs; ++i) + for (size_t i = 0 ; i < t2s->n_pairs; ++i) { variable_pair *vp = &t2s->pairs[i]; - struct string pair_name; - ds_init_cstr (&pair_name, var_to_string ((*vp)[0])); - ds_put_cstr (&pair_name, " - "); - ds_put_cstr (&pair_name, var_to_string ((*vp)[1])); + int pair_idx = add_pair_leaf (pairs, vp); - - tab_text (table, 0, 1 + i * 4, TAB_LEFT, ds_cstr (&pair_name)); - - ds_destroy (&pair_name); - - tab_hline (table, TAL_1, 0, tab_nc (table) - 1, 1 + i * 4); - - tab_text (table, 1, 1 + i * 4, TAB_LEFT, _("Negative Differences")); - tab_text (table, 1, 2 + i * 4, TAB_LEFT, _("Positive Differences")); - tab_text (table, 1, 3 + i * 4, TAB_LEFT, _("Ties")); - tab_text (table, 1, 4 + i * 4, TAB_LEFT, _("Total")); - - tab_double (table, 2, 1 + i * 4, TAB_RIGHT, param[i].neg, NULL, RC_WEIGHT); - tab_double (table, 2, 2 + i * 4, TAB_RIGHT, param[i].pos, NULL, RC_WEIGHT); - tab_double (table, 2, 3 + i * 4, TAB_RIGHT, param[i].ties, NULL, RC_WEIGHT); - tab_double (table, 2, 4 + i * 4, TAB_RIGHT, - param[i].ties + param[i].neg + param[i].pos, NULL, RC_WEIGHT); + const struct sign_test_params *p = ¶m[i]; + double values[] = { p->neg, p->pos, p->ties, p->ties + p->neg + p->pos }; + for (size_t j = 0; j < sizeof values / sizeof *values; j++) + pivot_table_put3 (table, 0, j, pair_idx, + pivot_value_new_number (values[j])); } - tab_submit (table); + pivot_table_submit (table); } static void output_statistics_table (const struct two_sample_test *t2s, const struct sign_test_params *param) { - int i; - struct tab_table *table = tab_create (1 + t2s->n_pairs, 4); + struct pivot_table *table = pivot_table_create (N_("Test Statistics")); - tab_title (table, _("Test Statistics")); + pivot_dimension_create (table, PIVOT_AXIS_ROW, N_("Statistics"), + N_("Exact Sig. (2-tailed)"), PIVOT_RC_SIGNIFICANCE, + N_("Exact Sig. (1-tailed)"), PIVOT_RC_SIGNIFICANCE, + N_("Point Probability"), PIVOT_RC_SIGNIFICANCE); - tab_headers (table, 0, 1, 0, 1); + struct pivot_dimension *pairs = pivot_dimension_create ( + table, PIVOT_AXIS_COLUMN, N_("Pairs")); - tab_hline (table, TAL_2, 0, tab_nc (table) - 1, 1); - tab_vline (table, TAL_2, 1, 0, tab_nr (table) - 1); - - - /* Vertical lines inside the box */ - tab_box (table, -1, -1, -1, TAL_1, - 0, 0, - tab_nc (table) - 1, tab_nr (table) - 1); - - /* Box around entire table */ - tab_box (table, TAL_2, TAL_2, -1, -1, - 0, 0, tab_nc (table) - 1, - tab_nr (table) - 1); - - tab_text (table, 0, 1, TAT_TITLE | TAB_LEFT, - _("Exact Sig. (2-tailed)")); - - tab_text (table, 0, 2, TAT_TITLE | TAB_LEFT, - _("Exact Sig. (1-tailed)")); - - tab_text (table, 0, 3, TAT_TITLE | TAB_LEFT, - _("Point Probability")); - - for (i = 0 ; i < t2s->n_pairs; ++i) + for (size_t i = 0 ; i < t2s->n_pairs; ++i) { variable_pair *vp = &t2s->pairs[i]; - - struct string pair_name; - ds_init_cstr (&pair_name, var_to_string ((*vp)[0])); - ds_put_cstr (&pair_name, " - "); - ds_put_cstr (&pair_name, var_to_string ((*vp)[1])); - - tab_text (table, 1 + i, 0, TAB_LEFT, ds_cstr (&pair_name)); - ds_destroy (&pair_name); - - tab_double (table, 1 + i, 1, TAB_RIGHT, - param[i].one_tailed_sig * 2, NULL, RC_PVALUE); - - tab_double (table, 1 + i, 2, TAB_RIGHT, param[i].one_tailed_sig, NULL, RC_PVALUE); - tab_double (table, 1 + i, 3, TAB_RIGHT, param[i].point_prob, NULL, RC_PVALUE); + int pair_idx = add_pair_leaf (pairs, vp); + + const struct sign_test_params *p = ¶m[i]; + double values[] = { p->one_tailed_sig * 2, + p->one_tailed_sig, + p->point_prob }; + for (size_t j = 0; j < sizeof values / sizeof *values; j++) + pivot_table_put2 (table, j, pair_idx, + pivot_value_new_number (values[j])); } - tab_submit (table); + pivot_table_submit (table); } void diff --git a/src/language/stats/t-test-indep.c b/src/language/stats/t-test-indep.c index e4e4243308..fff8c968c5 100644 --- a/src/language/stats/t-test-indep.c +++ b/src/language/stats/t-test-indep.c @@ -27,12 +27,12 @@ #include "data/dictionary.h" #include "data/format.h" #include "data/variable.h" - #include "math/moments.h" #include "math/levene.h" +#include "output/pivot-table.h" -#include #include "gettext.h" +#define N_(msgid) msgid #define _(msgid) gettext (msgid) @@ -187,207 +187,170 @@ indep_run (struct tt *tt, const struct variable *gvar, static void indep_summary (const struct tt *tt, struct indep_samples *is, const struct pair_stats *ps) { - const struct fmt_spec *wfmt = tt->wv ? var_get_print_format (tt->wv) : & F_8_0; - - int v; - int cols = 6; - const int heading_rows = 1; - int rows = tt->n_vars * 2 + heading_rows; - - struct string vallab0 ; - struct string vallab1 ; - struct tab_table *t = tab_create (cols, rows); - tab_set_format (t, RC_WEIGHT, wfmt); - ds_init_empty (&vallab0); - ds_init_empty (&vallab1); - - tab_headers (t, 0, 0, 1, 0); - tab_box (t, TAL_2, TAL_2, TAL_0, TAL_1, 0, 0, cols - 1, rows - 1); - tab_hline (t, TAL_2, 0, cols - 1, 1); - - tab_title (t, _("Group Statistics")); - tab_text (t, 1, 0, TAB_CENTER | TAT_TITLE, var_to_string (is->gvar)); - tab_text (t, 2, 0, TAB_CENTER | TAT_TITLE, _("N")); - tab_text (t, 3, 0, TAB_CENTER | TAT_TITLE, _("Mean")); - tab_text (t, 4, 0, TAB_CENTER | TAT_TITLE, _("Std. Deviation")); - tab_text (t, 5, 0, TAB_CENTER | TAT_TITLE, _("S.E. Mean")); - + struct pivot_table *table = pivot_table_create (N_("Group Statistics")); + pivot_table_set_weight_var (table, tt->wv); + + pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Statistics"), + N_("N"), PIVOT_RC_COUNT, + N_("Mean"), PIVOT_RC_OTHER, + N_("Std. Deviation"), PIVOT_RC_OTHER, + N_("S.E. Mean"), PIVOT_RC_OTHER); + + struct pivot_dimension *group = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Group")); + group->root->show_label = true; if (is->cut) { + struct string vallab0 = DS_EMPTY_INITIALIZER; ds_put_cstr (&vallab0, "≥"); - ds_put_cstr (&vallab1, "<"); - var_append_value_name (is->gvar, is->gval0, &vallab0); + pivot_category_create_leaf (group->root, + pivot_value_new_user_text_nocopy ( + ds_steal_cstr (&vallab0))); + + struct string vallab1 = DS_EMPTY_INITIALIZER; + ds_put_cstr (&vallab1, "<"); var_append_value_name (is->gvar, is->gval0, &vallab1); + pivot_category_create_leaf (group->root, + pivot_value_new_user_text_nocopy ( + ds_steal_cstr (&vallab1))); } else { - var_append_value_name (is->gvar, is->gval0, &vallab0); - var_append_value_name (is->gvar, is->gval1, &vallab1); + pivot_category_create_leaf ( + group->root, pivot_value_new_var_value (is->gvar, is->gval0)); + pivot_category_create_leaf ( + group->root, pivot_value_new_var_value (is->gvar, is->gval1)); } - tab_vline (t, TAL_1, 1, heading_rows, rows - 1); + struct pivot_dimension *dep_vars = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Dependent Variables")); - for (v = 0; v < tt->n_vars; ++v) + for (size_t v = 0; v < tt->n_vars; ++v) { - int i; const struct variable *var = tt->vars[v]; - tab_text (t, 0, v * 2 + heading_rows, TAB_LEFT, - var_to_string (var)); - - tab_text (t, 1, v * 2 + heading_rows, TAB_LEFT, - ds_cstr (&vallab0)); + int dep_var_idx = pivot_category_create_leaf ( + dep_vars->root, pivot_value_new_variable (var)); - tab_text (t, 1, v * 2 + 1 + heading_rows, TAB_LEFT, - ds_cstr (&vallab1)); - - for (i = 0 ; i < 2; ++i) + for (int i = 0 ; i < 2; ++i) { double cc, mean, sigma; moments_calculate (ps[v].mom[i], &cc, &mean, &sigma, NULL, NULL); - tab_double (t, 2, v * 2 + i + heading_rows, TAB_RIGHT, cc, NULL, RC_WEIGHT); - tab_double (t, 3, v * 2 + i + heading_rows, TAB_RIGHT, mean, NULL, RC_OTHER); - tab_double (t, 4, v * 2 + i + heading_rows, TAB_RIGHT, sqrt (sigma), NULL, RC_OTHER); - tab_double (t, 5, v * 2 + i + heading_rows, TAB_RIGHT, sqrt (sigma / cc), NULL, RC_OTHER); + double entries[] = { cc, mean, sqrt (sigma), sqrt (sigma / cc) }; + for (size_t j = 0; j < sizeof entries / sizeof *entries; j++) + pivot_table_put3 (table, j, i, dep_var_idx, + pivot_value_new_number (entries[j])); } } - tab_submit (t); - - ds_destroy (&vallab0); - ds_destroy (&vallab1); + pivot_table_submit (table); } static void indep_test (const struct tt *tt, const struct pair_stats *ps) { - int v; - const int heading_rows = 3; - const int rows= tt->n_vars * 2 + heading_rows; - - const size_t cols = 11; - - struct tab_table *t = tab_create (cols, rows); - tab_headers (t, 0, 0, 3, 0); - tab_box (t, TAL_2, TAL_2, TAL_0, TAL_0, 0, 0, cols - 1, rows - 1); - tab_hline (t, TAL_2, 0, cols - 1, 3); - - tab_title (t, _("Independent Samples Test")); - - tab_hline (t, TAL_1, 2, cols - 1, 1); - tab_vline (t, TAL_2, 2, 0, rows - 1); - tab_vline (t, TAL_1, 4, 0, rows - 1); - tab_box (t, -1, -1, -1, TAL_1, 2, 1, cols - 2, rows - 1); - tab_hline (t, TAL_1, cols - 2, cols - 1, 2); - tab_box (t, -1, -1, -1, TAL_1, cols - 2, 2, cols - 1, rows - 1); - tab_joint_text (t, 2, 0, 3, 0, TAB_CENTER, _("Levene's Test for Equality of Variances")); - tab_joint_text (t, 4, 0, cols - 1, 0, TAB_CENTER, _("t-test for Equality of Means")); - - tab_text (t, 2, 2, TAB_CENTER | TAT_TITLE, _("F")); - tab_text (t, 3, 2, TAB_CENTER | TAT_TITLE, _("Sig.")); - tab_text (t, 4, 2, TAB_CENTER | TAT_TITLE, _("t")); - tab_text (t, 5, 2, TAB_CENTER | TAT_TITLE, _("df")); - tab_text (t, 6, 2, TAB_CENTER | TAT_TITLE, _("Sig. (2-tailed)")); - tab_text (t, 7, 2, TAB_CENTER | TAT_TITLE, _("Mean Difference")); - tab_text (t, 8, 2, TAB_CENTER | TAT_TITLE, _("Std. Error Difference")); - tab_text (t, 9, 2, TAB_CENTER | TAT_TITLE, _("Lower")); - tab_text (t, 10, 2, TAB_CENTER | TAT_TITLE, _("Upper")); - - tab_joint_text_format (t, 9, 1, 10, 1, TAB_CENTER, - _("%g%% Confidence Interval of the Difference"), - tt->confidence * 100.0); - - tab_vline (t, TAL_1, 1, heading_rows, rows - 1); - - for (v = 0; v < tt->n_vars; ++v) + struct pivot_table *table = pivot_table_create ( + N_("Independent Samples Test")); + + struct pivot_dimension *statistics = pivot_dimension_create ( + table, PIVOT_AXIS_COLUMN, N_("Statistics")); + pivot_category_create_group ( + statistics->root, N_("Levene's Test for Equality of Variances"), + N_("F"), PIVOT_RC_OTHER, + N_("Sig."), PIVOT_RC_SIGNIFICANCE); + struct pivot_category *group = pivot_category_create_group ( + statistics->root, N_("T-Test for Equality of Means"), + N_("t"), PIVOT_RC_OTHER, + N_("df"), PIVOT_RC_OTHER, + N_("Sig. (2-tailed)"), PIVOT_RC_SIGNIFICANCE, + N_("Mean Difference"), PIVOT_RC_OTHER, + N_("Std. Error Difference"), PIVOT_RC_OTHER); + pivot_category_create_group ( + group, N_("95% Confidence Interval of the Difference"), + N_("Lower"), PIVOT_RC_OTHER, + N_("Upper"), PIVOT_RC_OTHER); + + pivot_dimension_create (table, PIVOT_AXIS_ROW, N_("Assumptions"), + N_("Equal variances assumed"), + N_("Equal variances not assumed")); + + struct pivot_dimension *dep_vars = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Dependent Variables")); + + for (size_t v = 0; v < tt->n_vars; ++v) { - double df, pooled_variance, mean_diff, tval; - double se2, std_err_diff; - double p, q; + int dep_var_idx = pivot_category_create_leaf ( + dep_vars->root, pivot_value_new_variable (tt->vars[v])); + double cc0, mean0, sigma0; double cc1, mean1, sigma1; moments_calculate (ps[v].mom[0], &cc0, &mean0, &sigma0, NULL, NULL); moments_calculate (ps[v].mom[1], &cc1, &mean1, &sigma1, NULL, NULL); - tab_text (t, 0, v * 2 + heading_rows, TAB_LEFT, var_to_string (tt->vars[v])); - tab_text (t, 1, v * 2 + heading_rows, TAB_LEFT, _("Equal variances assumed")); - - df = cc0 + cc1 - 2.0; - tab_double (t, 5, v * 2 + heading_rows, TAB_RIGHT, df, NULL, RC_OTHER); - - pooled_variance = ((cc0 - 1)* sigma0 + (cc1 - 1) * sigma1) / df ; - - tval = (mean0 - mean1) / sqrt (pooled_variance); - tval /= sqrt ((cc0 + cc1) / (cc0 * cc1)); - - tab_double (t, 4, v * 2 + heading_rows, TAB_RIGHT, tval, NULL, RC_OTHER); + double mean_diff = mean0 - mean1; - p = gsl_cdf_tdist_P (tval, df); - q = gsl_cdf_tdist_Q (tval, df); - mean_diff = mean0 - mean1; - - tab_double (t, 6, v * 2 + heading_rows, TAB_RIGHT, 2.0 * (tval > 0 ? q : p), NULL, RC_PVALUE); - tab_double (t, 7, v * 2 + heading_rows, TAB_RIGHT, mean_diff, NULL, RC_OTHER); - - std_err_diff = sqrt (pooled_variance * (1.0/cc0 + 1.0/cc1)); - tab_double (t, 8, v * 2 + heading_rows, TAB_RIGHT, std_err_diff, NULL, RC_OTHER); - - - /* Now work out the confidence interval */ - q = (1 - tt->confidence)/2.0; /* 2-tailed test */ - - tval = gsl_cdf_tdist_Qinv (q, df); - tab_double (t, 9, v * 2 + heading_rows, TAB_RIGHT, mean_diff - tval * std_err_diff, NULL, RC_OTHER); - tab_double (t, 10, v * 2 + heading_rows, TAB_RIGHT, mean_diff + tval * std_err_diff, NULL, RC_OTHER); + /* Equal variances assumed. */ + double e_df = cc0 + cc1 - 2.0; + double e_pooled_variance = ((cc0 - 1)* sigma0 + (cc1 - 1) * sigma1) / e_df; + double e_tval = ((mean0 - mean1) / sqrt (e_pooled_variance) + / sqrt ((cc0 + cc1) / (cc0 * cc1))); + double e_p = gsl_cdf_tdist_P (e_tval, e_df); + double e_q = gsl_cdf_tdist_Q (e_tval, e_df); + double e_sig = 2.0 * (e_tval > 0 ? e_q : e_p); + double e_std_err_diff = sqrt (e_pooled_variance * (1.0/cc0 + 1.0/cc1)); + double e_tval_qinv = gsl_cdf_tdist_Qinv ((1 - tt->confidence) / 2.0, e_df); /* Equal variances not assumed */ - tab_text (t, 1, v * 2 + heading_rows + 1, TAB_LEFT, _("Equal variances not assumed")); - std_err_diff = sqrt ((sigma0 / cc0) + (sigma1 / cc1)); - - se2 = sigma0 / cc0 + sigma1 / cc1; - tval = mean_diff / sqrt (se2); - tab_double (t, 4, v * 2 + heading_rows + 1, TAB_RIGHT, tval, NULL, RC_OTHER); - - { - double p, q; - const double s0 = sigma0 / (cc0); - const double s1 = sigma1 / (cc1); - double df = pow2 (s0 + s1) ; - df /= pow2 (s0) / (cc0 - 1) + pow2 (s1) / (cc1 - 1); - - tab_double (t, 5, v * 2 + heading_rows + 1, TAB_RIGHT, df, NULL, RC_OTHER); - - p = gsl_cdf_tdist_P (tval, df); - q = gsl_cdf_tdist_Q (tval, df); - - tab_double (t, 6, v * 2 + heading_rows + 1, TAB_RIGHT, 2.0 * (tval > 0 ? q : p), NULL, RC_PVALUE); - - /* Now work out the confidence interval */ - q = (1 - tt->confidence) / 2.0; /* 2-tailed test */ - - tval = gsl_cdf_tdist_Qinv (q, df); - } - - tab_double (t, 7, v * 2 + heading_rows + 1, TAB_RIGHT, mean_diff, NULL, RC_OTHER); - tab_double (t, 8, v * 2 + heading_rows + 1, TAB_RIGHT, std_err_diff, NULL, RC_OTHER); - tab_double (t, 9, v * 2 + heading_rows + 1, TAB_RIGHT, mean_diff - tval * std_err_diff, NULL, RC_OTHER); - tab_double (t, 10, v * 2 + heading_rows + 1, TAB_RIGHT, mean_diff + tval * std_err_diff, NULL, RC_OTHER); - - tab_double (t, 2, v * 2 + heading_rows, TAB_CENTER, ps[v].lev, NULL, RC_OTHER); - - - { - /* Now work out the significance of the Levene test */ - double df1 = 1; - double df2 = cc0 + cc1 - 2; - double q = gsl_cdf_fdist_Q (ps[v].lev, df1, df2); - tab_double (t, 3, v * 2 + heading_rows, TAB_CENTER, q, NULL, RC_PVALUE); - } + const double s0 = sigma0 / cc0; + const double s1 = sigma1 / cc1; + double d_df = (pow2 (s0 + s1) / (pow2 (s0) / (cc0 - 1) + + pow2 (s1) / (cc1 - 1))); + double d_tval = mean_diff / sqrt (sigma0 / cc0 + sigma1 / cc1); + double d_p = gsl_cdf_tdist_P (d_tval, d_df); + double d_q = gsl_cdf_tdist_Q (d_tval, d_df); + double d_sig = 2.0 * (d_tval > 0 ? d_q : d_p); + double d_std_err_diff = sqrt ((sigma0 / cc0) + (sigma1 / cc1)); + double d_tval_qinv = gsl_cdf_tdist_Qinv ((1 - tt->confidence) / 2.0, d_df); + + struct entry + { + int assumption_idx; + int stat_idx; + double x; + } + entries[] = + { + { 0, 0, ps[v].lev }, + { 0, 1, gsl_cdf_fdist_Q (ps[v].lev, 1, cc0 + cc1 - 2) }, + + { 0, 2, e_tval }, + { 0, 3, e_df }, + { 0, 4, e_sig }, + { 0, 5, mean_diff }, + { 0, 6, e_std_err_diff }, + { 0, 7, mean_diff - e_tval_qinv * e_std_err_diff }, + { 0, 8, mean_diff + e_tval_qinv * e_std_err_diff }, + + { 1, 2, d_tval }, + { 1, 3, d_df }, + { 1, 4, d_sig }, + { 1, 5, mean_diff }, + { 1, 6, d_std_err_diff }, + { 1, 7, mean_diff - d_tval_qinv * d_std_err_diff }, + { 1, 8, mean_diff + d_tval_qinv * d_std_err_diff }, + }; + + for (size_t i = 0; i < sizeof entries / sizeof *entries; i++) + { + const struct entry *e = &entries[i]; + pivot_table_put3 (table, e->stat_idx, e->assumption_idx, + dep_var_idx, pivot_value_new_number (e->x)); + } } - tab_submit (t); + pivot_table_submit (table); } diff --git a/src/language/stats/t-test-one-sample.c b/src/language/stats/t-test-one-sample.c index fdcef55937..20914c9223 100644 --- a/src/language/stats/t-test-one-sample.c +++ b/src/language/stats/t-test-one-sample.c @@ -31,9 +31,10 @@ #include "libpspp/hmapx.h" #include "math/moments.h" -#include "output/tab.h" +#include "output/pivot-table.h" #include "gettext.h" +#define N_(msgid) msgid #define _(msgid) gettext (msgid) @@ -41,9 +42,6 @@ struct per_var_stats { const struct variable *var; - /* The position for reporting purposes */ - int posn; - /* N, Mean, Variance */ struct moments *mom; @@ -54,7 +52,8 @@ struct per_var_stats struct one_samp { - struct hmapx hmap; + struct per_var_stats *stats; + size_t n_stats; double testval; }; @@ -62,154 +61,118 @@ struct one_samp static void one_sample_test (const struct tt *tt, const struct one_samp *os) { - struct hmapx_node *node; - struct per_var_stats *per_var_stats; - - const int heading_rows = 3; - const size_t rows = heading_rows + tt->n_vars; - const size_t cols = 7; - const struct fmt_spec *wfmt = tt->wv ? var_get_print_format (tt->wv) : & F_8_0; - - struct tab_table *t = tab_create (cols, rows); - tab_set_format (t, RC_WEIGHT, wfmt); - - tab_headers (t, 0, 0, heading_rows, 0); - tab_box (t, TAL_2, TAL_2, TAL_0, TAL_0, 0, 0, cols - 1, rows - 1); - tab_hline (t, TAL_2, 0, cols - 1, 3); - - tab_title (t, _("One-Sample Test")); - tab_hline (t, TAL_1, 1, cols - 1, 1); - tab_vline (t, TAL_2, 1, 0, rows - 1); - - tab_joint_text_format (t, 1, 0, cols - 1, 0, TAB_CENTER, - _("Test Value = %f"), os->testval); - - tab_box (t, -1, -1, -1, TAL_1, 1, 1, cols - 1, rows - 1); - - tab_joint_text_format (t, 5, 1, 6, 1, TAB_CENTER, - _("%g%% Confidence Interval of the Difference"), - tt->confidence * 100.0); - - tab_hline (t, TAL_1, 5, 6, 2); - tab_text (t, 1, 2, TAB_CENTER | TAT_TITLE, _("t")); - tab_text (t, 2, 2, TAB_CENTER | TAT_TITLE, _("df")); - tab_text (t, 3, 2, TAB_CENTER | TAT_TITLE, _("Sig. (2-tailed)")); - tab_text (t, 4, 2, TAB_CENTER | TAT_TITLE, _("Mean Difference")); - tab_text (t, 5, 2, TAB_CENTER | TAT_TITLE, _("Lower")); - tab_text (t, 6, 2, TAB_CENTER | TAT_TITLE, _("Upper")); - - HMAPX_FOR_EACH (per_var_stats, node, &os->hmap) + struct pivot_table *table = pivot_table_create (N_("One-Sample Test")); + pivot_table_set_weight_var (table, tt->wv); + + struct pivot_dimension *statistics = pivot_dimension_create ( + table, PIVOT_AXIS_COLUMN, N_("Statistics")); + struct pivot_category *group = pivot_category_create_group__ ( + statistics->root, pivot_value_new_user_text_nocopy ( + xasprintf (_("Test Value = %.*g"), DBL_DIG + 1, os->testval))); + pivot_category_create_leaves ( + group, + N_("t"), PIVOT_RC_OTHER, + N_("df"), PIVOT_RC_COUNT, + N_("Sig. (2-tailed)"), PIVOT_RC_SIGNIFICANCE, + N_("Mean Difference"), PIVOT_RC_OTHER); + struct pivot_category *subgroup = pivot_category_create_group__ ( + group, pivot_value_new_user_text_nocopy ( + xasprintf (_("%g%% Confidence Interval of the Difference"), + tt->confidence * 100.0))); + pivot_category_create_leaves (subgroup, + N_("Lower"), PIVOT_RC_OTHER, + N_("Upper"), PIVOT_RC_OTHER); + + struct pivot_dimension *dep_vars = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Dependent Variables")); + + for (size_t i = 0; i < os->n_stats; i++) { + const struct per_var_stats *per_var_stats = &os->stats[i]; const struct moments *m = per_var_stats->mom; - double cc, mean, sigma; - double tval, df; - double p, q; - double mean_diff; - double se_mean ; - const int v = per_var_stats->posn; - - moments_calculate (m, &cc, &mean, &sigma, NULL, NULL); - - tval = (mean - os->testval) * sqrt (cc / sigma); - - mean_diff = per_var_stats->sum_diff / cc; - se_mean = sqrt (sigma / cc); - df = cc - 1.0; - p = gsl_cdf_tdist_P (tval, df); - q = gsl_cdf_tdist_Q (tval, df); - - tab_text (t, 0, v + heading_rows, TAB_LEFT, var_to_string (per_var_stats->var)); - tab_double (t, 1, v + heading_rows, TAB_RIGHT, tval, NULL, RC_OTHER); - tab_double (t, 2, v + heading_rows, TAB_RIGHT, df, NULL, RC_WEIGHT); - /* Multiply by 2 to get 2-tailed significance, makeing sure we've got - the correct tail*/ - tab_double (t, 3, v + heading_rows, TAB_RIGHT, 2.0 * (tval > 0 ? q : p), NULL, RC_PVALUE); + int dep_var_idx = pivot_category_create_leaf ( + dep_vars->root, pivot_value_new_variable (per_var_stats->var)); - tab_double (t, 4, v + heading_rows, TAB_RIGHT, mean_diff, NULL, RC_OTHER); - - tval = gsl_cdf_tdist_Qinv ( (1.0 - tt->confidence) / 2.0, df); - - tab_double (t, 5, v + heading_rows, TAB_RIGHT, mean_diff - tval * se_mean, NULL, RC_OTHER); - tab_double (t, 6, v + heading_rows, TAB_RIGHT, mean_diff + tval * se_mean, NULL, RC_OTHER); + double cc, mean, sigma; + moments_calculate (m, &cc, &mean, &sigma, NULL, NULL); + double tval = (mean - os->testval) * sqrt (cc / sigma); + double mean_diff = per_var_stats->sum_diff / cc; + double se_mean = sqrt (sigma / cc); + double df = cc - 1.0; + double p = gsl_cdf_tdist_P (tval, df); + double q = gsl_cdf_tdist_Q (tval, df); + double sig = 2.0 * (tval > 0 ? q : p); + double tval_qinv = gsl_cdf_tdist_Qinv ((1.0 - tt->confidence) / 2.0, df); + double lower = mean_diff - tval_qinv * se_mean; + double upper = mean_diff + tval_qinv * se_mean; + + double entries[] = { tval, df, sig, mean_diff, lower, upper }; + for (size_t j = 0; j < sizeof entries / sizeof *entries; j++) + pivot_table_put2 (table, j, dep_var_idx, + pivot_value_new_number (entries[j])); } - tab_submit (t); + pivot_table_submit (table); } static void one_sample_summary (const struct tt *tt, const struct one_samp *os) { - struct hmapx_node *node; - struct per_var_stats *per_var_stats; - - const int cols = 5; - const int heading_rows = 1; - const int rows = tt->n_vars + heading_rows; - struct tab_table *t = tab_create (cols, rows); - const struct fmt_spec *wfmt = tt->wv ? var_get_print_format (tt->wv) : & F_8_0; - tab_set_format (t, RC_WEIGHT, wfmt); - tab_headers (t, 0, 0, heading_rows, 0); - tab_box (t, TAL_2, TAL_2, TAL_0, TAL_1, 0, 0, cols - 1, rows - 1); - tab_hline (t, TAL_2, 0, cols - 1, 1); - - tab_title (t, _("One-Sample Statistics")); - tab_vline (t, TAL_2, 1, 0, rows - 1); - tab_text (t, 1, 0, TAB_CENTER | TAT_TITLE, _("N")); - tab_text (t, 2, 0, TAB_CENTER | TAT_TITLE, _("Mean")); - tab_text (t, 3, 0, TAB_CENTER | TAT_TITLE, _("Std. Deviation")); - tab_text (t, 4, 0, TAB_CENTER | TAT_TITLE, _("S.E. Mean")); - - HMAPX_FOR_EACH (per_var_stats, node, &os->hmap) + struct pivot_table *table = pivot_table_create (N_("One-Sample Statistics")); + pivot_table_set_weight_var (table, tt->wv); + + pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Statistics"), + N_("N"), PIVOT_RC_COUNT, + N_("Mean"), PIVOT_RC_OTHER, + N_("Std. Deviation"), PIVOT_RC_OTHER, + N_("S.E. Mean"), PIVOT_RC_OTHER); + + struct pivot_dimension *variables = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Variables")); + + for (size_t i = 0; i < os->n_stats; i++) { + const struct per_var_stats *per_var_stats = &os->stats[i]; const struct moments *m = per_var_stats->mom; - const int v = per_var_stats->posn; + + int var_idx = pivot_category_create_leaf ( + variables->root, pivot_value_new_variable (per_var_stats->var)); + double cc, mean, sigma; moments_calculate (m, &cc, &mean, &sigma, NULL, NULL); - tab_text (t, 0, v + heading_rows, TAB_LEFT, var_to_string (per_var_stats->var)); - tab_double (t, 1, v + heading_rows, TAB_RIGHT, cc, NULL, RC_WEIGHT); - tab_double (t, 2, v + heading_rows, TAB_RIGHT, mean, NULL, RC_OTHER); - tab_double (t, 3, v + heading_rows, TAB_RIGHT, sqrt (sigma), NULL, RC_OTHER); - tab_double (t, 4, v + heading_rows, TAB_RIGHT, sqrt (sigma / cc), NULL, RC_OTHER); + double entries[] = { cc, mean, sqrt (sigma), sqrt (sigma / cc) }; + for (size_t j = 0; j < sizeof entries / sizeof *entries; j++) + pivot_table_put2 (table, j, var_idx, + pivot_value_new_number (entries[j])); } - tab_submit (t); + pivot_table_submit (table); } void one_sample_run (const struct tt *tt, double testval, struct casereader *reader) { - int i; - struct ccase *c; struct one_samp os; - struct casereader *r; - struct hmapx_node *node; - struct per_var_stats *per_var_stats; - os.testval = testval; - hmapx_init (&os.hmap); - - /* Insert all the variables into the map */ - for (i = 0; i < tt->n_vars; ++i) + os.stats = xcalloc (tt->n_vars, sizeof *os.stats); + os.n_stats = tt->n_vars; + for (size_t i = 0; i < tt->n_vars; ++i) { - struct per_var_stats *per_var_stats = xzalloc (sizeof (*per_var_stats)); - - per_var_stats->posn = i; + struct per_var_stats *per_var_stats = &os.stats[i]; per_var_stats->var = tt->vars[i]; per_var_stats->mom = moments_create (MOMENT_VARIANCE); - - hmapx_insert (&os.hmap, per_var_stats, hash_pointer (per_var_stats->var, 0)); } - r = casereader_clone (reader); + struct casereader *r = casereader_clone (reader); + struct ccase *c; for ( ; (c = casereader_read (r) ); case_unref (c)) { double w = dict_get_case_weight (tt->dict, c, NULL); - struct hmapx_node *node; - struct per_var_stats *per_var_stats; - HMAPX_FOR_EACH (per_var_stats, node, &os.hmap) - { + for (size_t i = 0; i < os.n_stats; i++) + { + const struct per_var_stats *per_var_stats = &os.stats[i]; const struct variable *var = per_var_stats->var; const union value *val = case_data (c, var); if (var_is_value_missing (var, val, tt->exclude)) @@ -224,10 +187,9 @@ one_sample_run (const struct tt *tt, double testval, struct casereader *reader) for ( ; (c = casereader_read (r) ); case_unref (c)) { double w = dict_get_case_weight (tt->dict, c, NULL); - struct hmapx_node *node; - struct per_var_stats *per_var_stats; - HMAPX_FOR_EACH (per_var_stats, node, &os.hmap) - { + for (size_t i = 0; i < os.n_stats; i++) + { + struct per_var_stats *per_var_stats = &os.stats[i]; const struct variable *var = per_var_stats->var; const union value *val = case_data (c, var); if (var_is_value_missing (var, val, tt->exclude)) @@ -242,12 +204,11 @@ one_sample_run (const struct tt *tt, double testval, struct casereader *reader) one_sample_summary (tt, &os); one_sample_test (tt, &os); - HMAPX_FOR_EACH (per_var_stats, node, &os.hmap) + for (size_t i = 0; i < os.n_stats; i++) { + const struct per_var_stats *per_var_stats = &os.stats[i]; moments_destroy (per_var_stats->mom); - free (per_var_stats); } - - hmapx_destroy (&os.hmap); + free (os.stats); } diff --git a/src/language/stats/t-test-paired.c b/src/language/stats/t-test-paired.c index 4935e9a8cb..921233b68e 100644 --- a/src/language/stats/t-test-paired.c +++ b/src/language/stats/t-test-paired.c @@ -27,18 +27,16 @@ #include "data/dictionary.h" #include "data/format.h" #include "data/variable.h" -#include "libpspp/hmapx.h" -#include "libpspp/hash-functions.h" -#include "output/tab.h" +#include "output/pivot-table.h" #include "gettext.h" +#define N_(msgid) msgid #define _(msgid) gettext (msgid) struct pair_stats { - int posn; double sum_of_prod; struct moments *mom0; const struct variable *var0; @@ -51,7 +49,8 @@ struct pair_stats struct paired_samp { - struct hmapx hmap; + struct pair_stats *ps; + size_t n_ps; }; static void paired_summary (const struct tt *tt, struct paired_samp *os); @@ -61,31 +60,21 @@ static void paired_test (const struct tt *tt, const struct paired_samp *os); void paired_run (const struct tt *tt, size_t n_pairs, vp *pairs, struct casereader *reader) { - int i; struct ccase *c; struct paired_samp ps; struct casereader *r; - struct hmapx_node *node; - struct pair_stats *pp = NULL; - hmapx_init (&ps.hmap); - - for (i = 0; i < n_pairs; ++i) + ps.ps = xcalloc (n_pairs, sizeof *ps.ps); + ps.n_ps = n_pairs; + for (size_t i = 0; i < n_pairs; ++i) { vp *pair = &pairs[i]; - unsigned int hash; - struct pair_stats *pp = xzalloc (sizeof *pp); - pp->posn = i; + struct pair_stats *pp = &ps.ps[i]; pp->var0 = (*pair)[0]; pp->var1 = (*pair)[1]; pp->mom0 = moments_create (MOMENT_VARIANCE); pp->mom1 = moments_create (MOMENT_VARIANCE); pp->mom_diff = moments_create (MOMENT_VARIANCE); - - hash = hash_pointer ((*pair)[0], 0); - hash = hash_pointer ((*pair)[1], hash); - - hmapx_insert (&ps.hmap, pp, hash); } r = casereader_clone (reader); @@ -93,10 +82,9 @@ paired_run (const struct tt *tt, size_t n_pairs, vp *pairs, struct casereader *r { double w = dict_get_case_weight (tt->dict, c, NULL); - struct hmapx_node *node; - struct pair_stats *pp = NULL; - HMAPX_FOR_EACH (pp, node, &ps.hmap) + for (int i = 0; i < ps.n_ps; i++) { + struct pair_stats *pp = &ps.ps[i]; const union value *val0 = case_data (c, pp->var0); const union value *val1 = case_data (c, pp->var1); if (var_is_value_missing (pp->var0, val0, tt->exclude)) @@ -117,10 +105,9 @@ paired_run (const struct tt *tt, size_t n_pairs, vp *pairs, struct casereader *r { double w = dict_get_case_weight (tt->dict, c, NULL); - struct hmapx_node *node; - struct pair_stats *pp = NULL; - HMAPX_FOR_EACH (pp, node, &ps.hmap) + for (int i = 0; i < ps.n_ps; i++) { + struct pair_stats *pp = &ps.ps[i]; const union value *val0 = case_data (c, pp->var0); const union value *val1 = case_data (c, pp->var1); if (var_is_value_missing (pp->var0, val0, tt->exclude)) @@ -142,214 +129,172 @@ paired_run (const struct tt *tt, size_t n_pairs, vp *pairs, struct casereader *r paired_test (tt, &ps); /* Clean up */ - HMAPX_FOR_EACH (pp, node, &ps.hmap) + + for (int i = 0; i < ps.n_ps; i++) { + struct pair_stats *pp = &ps.ps[i]; moments_destroy (pp->mom0); moments_destroy (pp->mom1); moments_destroy (pp->mom_diff); - free (pp); } - - hmapx_destroy (&ps.hmap); + free (ps.ps); } static void paired_summary (const struct tt *tt, struct paired_samp *os) { - size_t n_pairs = hmapx_count (&os->hmap); - struct hmapx_node *node; - struct pair_stats *pp = NULL; - - const int heading_rows = 1; - const int heading_cols = 2; - - const int cols = 4 + heading_cols; - const int rows = n_pairs * 2 + heading_rows; - struct tab_table *t = tab_create (cols, rows); - const struct fmt_spec *wfmt = tt->wv ? var_get_print_format (tt->wv) : & F_8_0; - tab_set_format (t, RC_WEIGHT, wfmt); - tab_headers (t, 0, 0, heading_rows, 0); - tab_box (t, TAL_2, TAL_2, TAL_0, TAL_0, 0, 0, cols - 1, rows - 1); - tab_box (t, -1, -1, TAL_0, TAL_1, heading_cols, 0, cols - 1, rows - 1); - - tab_hline (t, TAL_2, 0, cols - 1, 1); - - tab_title (t, _("Paired Sample Statistics")); - tab_vline (t, TAL_2, heading_cols, 0, rows - 1); - tab_text (t, 3, 0, TAB_CENTER | TAT_TITLE, _("N")); - tab_text (t, 2, 0, TAB_CENTER | TAT_TITLE, _("Mean")); - tab_text (t, 4, 0, TAB_CENTER | TAT_TITLE, _("Std. Deviation")); - tab_text (t, 5, 0, TAB_CENTER | TAT_TITLE, _("S.E. Mean")); - - HMAPX_FOR_EACH (pp, node, &os->hmap) - { - int v = pp->posn; - double cc, mean, sigma; + struct pivot_table *table = pivot_table_create ( + N_("Paired Sample Statistics")); + pivot_table_set_weight_var (table, tt->wv); - tab_text_format (t, 0, v * 2 + heading_rows, TAB_LEFT, _("Pair %d"), pp->posn + 1); - - /* first var */ - moments_calculate (pp->mom0, &cc, &mean, &sigma, NULL, NULL); - tab_text (t, 1, v * 2 + heading_rows, TAB_LEFT, var_to_string (pp->var0)); - tab_double (t, 3, v * 2 + heading_rows, TAB_RIGHT, cc, NULL, RC_WEIGHT); - tab_double (t, 2, v * 2 + heading_rows, TAB_RIGHT, mean, NULL, RC_OTHER); - tab_double (t, 4, v * 2 + heading_rows, TAB_RIGHT, sqrt (sigma), NULL, RC_OTHER); - tab_double (t, 5, v * 2 + heading_rows, TAB_RIGHT, sqrt (sigma / cc), NULL, RC_OTHER); - - /* second var */ - moments_calculate (pp->mom1, &cc, &mean, &sigma, NULL, NULL); - tab_text (t, 1, v * 2 + 1 + heading_rows, TAB_LEFT, var_to_string (pp->var1)); - tab_double (t, 3, v * 2 + 1 + heading_rows, TAB_RIGHT, cc, NULL, RC_WEIGHT); - tab_double (t, 2, v * 2 + 1 + heading_rows, TAB_RIGHT, mean, NULL, RC_OTHER); - tab_double (t, 4, v * 2 + 1 + heading_rows, TAB_RIGHT, sqrt (sigma), NULL, RC_OTHER); - tab_double (t, 5, v * 2 + 1 + heading_rows, TAB_RIGHT, sqrt (sigma / cc), NULL, RC_OTHER); + pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Statistics"), + N_("N"), PIVOT_RC_COUNT, + N_("Mean"), PIVOT_RC_OTHER, + N_("Std. Deviation"), PIVOT_RC_OTHER, + N_("S.E. Mean"), PIVOT_RC_OTHER); + + struct pivot_dimension *variables = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Variables")); + + for (size_t i = 0; i < os->n_ps; i++) + { + struct pair_stats *pp = &os->ps[i]; + struct pivot_category *pair = pivot_category_create_group__ ( + variables->root, pivot_value_new_text_format (N_("Pair %d"), i + 1)); + + for (int j = 0; j < 2; j++) + { + const struct variable *var = j ? pp->var1 : pp->var0; + const struct moments *mom = j ? pp->mom1 : pp->mom0; + double cc, mean, sigma; + moments_calculate (mom, &cc, &mean, &sigma, NULL, NULL); + + int var_idx = pivot_category_create_leaf ( + pair, pivot_value_new_variable (var)); + + double entries[] = { cc, mean, sqrt (sigma), sqrt (sigma / cc) }; + for (size_t j = 0; j < sizeof entries / sizeof *entries; j++) + pivot_table_put2 (table, j, var_idx, + pivot_value_new_number (entries[j])); + } } - tab_submit (t); + pivot_table_submit (table); } static void paired_correlations (const struct tt *tt, struct paired_samp *os) { - size_t n_pairs = hmapx_count (&os->hmap); - struct hmapx_node *node; - struct pair_stats *pp = NULL; - const int heading_rows = 1; - const int heading_cols = 2; - - const int cols = 5; - const int rows = n_pairs + heading_rows; - struct tab_table *t = tab_create (cols, rows); - const struct fmt_spec *wfmt = tt->wv ? var_get_print_format (tt->wv) : & F_8_0; - tab_set_format (t, RC_WEIGHT, wfmt); - tab_headers (t, 0, 0, heading_rows, 0); - tab_box (t, TAL_2, TAL_2, TAL_0, TAL_1, 0, 0, cols - 1, rows - 1); - - tab_hline (t, TAL_2, 0, cols - 1, 1); - - tab_title (t, _("Paired Samples Correlations")); - tab_vline (t, TAL_2, heading_cols, 0, rows - 1); - tab_text (t, 2, 0, TAB_CENTER | TAT_TITLE, _("N")); - tab_text (t, 3, 0, TAB_CENTER | TAT_TITLE, _("Correlation")); - tab_text (t, 4, 0, TAB_CENTER | TAT_TITLE, _("Sig.")); - - HMAPX_FOR_EACH (pp, node, &os->hmap) - { - double corr; - double cc0, mean0, sigma0; - double cc1, mean1, sigma1; - int v = pp->posn; + struct pivot_table *table = pivot_table_create ( + N_("Paired Samples Correlations")); + pivot_table_set_weight_var (table, tt->wv); + + pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Statistics"), + N_("N"), PIVOT_RC_COUNT, + N_("Correlation"), PIVOT_RC_CORRELATION, + N_("Sig."), PIVOT_RC_SIGNIFICANCE); - tab_text_format (t, 0, v + heading_rows, TAB_LEFT, _("Pair %d"), pp->posn + 1); + struct pivot_dimension *pairs = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Pairs")); - tab_text_format (t, 1, v + heading_rows, TAB_LEFT, _("%s & %s"), - var_to_string (pp->var0), - var_to_string (pp->var1)); + for (size_t i = 0; i < os->n_ps; i++) + { + struct pair_stats *pp = &os->ps[i]; + struct pivot_category *group = pivot_category_create_group__ ( + pairs->root, pivot_value_new_text_format (N_("Pair %d"), i + 1)); + + int row = pivot_category_create_leaf ( + group, pivot_value_new_text_format (N_("%s & %s"), + var_to_string (pp->var0), + var_to_string (pp->var1))); + double cc0, mean0, sigma0; + double cc1, mean1, sigma1; moments_calculate (pp->mom0, &cc0, &mean0, &sigma0, NULL, NULL); moments_calculate (pp->mom1, &cc1, &mean1, &sigma1, NULL, NULL); - /* If this fails, then we're not dealing with missing values properly */ assert (cc0 == cc1); - tab_double (t, 2, v + heading_rows, TAB_RIGHT, cc0, NULL, RC_WEIGHT); - - corr = pp->sum_of_prod / cc0 - (mean0 * mean1); - corr /= sqrt (sigma0 * sigma1); - corr *= cc0 / (cc0 - 1); - - tab_double (t, 3, v + heading_rows, TAB_RIGHT, corr, NULL, RC_OTHER); - tab_double (t, 4, v + heading_rows, TAB_RIGHT, - 2.0 * significance_of_correlation (corr, cc0), NULL, RC_PVALUE); + double corr = ((pp->sum_of_prod / cc0 - mean0 * mean1) + / sqrt (sigma0 * sigma1) * cc0 / (cc0 - 1)); + double sig = 2.0 * significance_of_correlation (corr, cc0); + double entries[] = { cc0, corr, sig }; + for (size_t i = 0; i < sizeof entries / sizeof *entries; i++) + pivot_table_put2 (table, i, row, pivot_value_new_number (entries[i])); } - tab_submit (t); + pivot_table_submit (table); } static void paired_test (const struct tt *tt, const struct paired_samp *os) { - size_t n_pairs = hmapx_count (&os->hmap); - struct hmapx_node *node; - struct pair_stats *pp = NULL; - - const int heading_rows = 3; - const int heading_cols = 2; - const size_t rows = heading_rows + n_pairs; - const size_t cols = 10; - const struct fmt_spec *wfmt = tt->wv ? var_get_print_format (tt->wv) : & F_8_0; - - struct tab_table *t = tab_create (cols, rows); - tab_set_format (t, RC_WEIGHT, wfmt); - tab_headers (t, 0, 0, heading_rows, 0); - tab_box (t, TAL_2, TAL_2, TAL_0, TAL_0, 0, 0, cols - 1, rows - 1); - tab_hline (t, TAL_2, 0, cols - 1, 3); - - tab_title (t, _("Paired Samples Test")); - tab_hline (t, TAL_1, heading_cols, 6, 1); - tab_vline (t, TAL_2, heading_cols, 0, rows - 1); - - tab_box (t, -1, -1, -1, TAL_1, heading_cols, 0, cols - 1, rows - 1); - - tab_joint_text (t, 2, 0, 6, 0, TAB_CENTER, - _("Paired Differences")); - - tab_joint_text_format (t, 5, 1, 6, 1, TAB_CENTER, - _("%g%% Confidence Interval of the Difference"), - tt->confidence * 100.0); - - tab_hline (t, TAL_1, 5, 6, 2); - tab_text (t, 7, 2, TAB_CENTER | TAT_TITLE, _("t")); - tab_text (t, 8, 2, TAB_CENTER | TAT_TITLE, _("df")); - tab_text (t, 9, 2, TAB_CENTER | TAT_TITLE, _("Sig. (2-tailed)")); - tab_text (t, 4, 2, TAB_CENTER | TAT_TITLE, _("Std. Error Mean")); - tab_text (t, 3, 2, TAB_CENTER | TAT_TITLE, _("Std. Deviation")); - tab_text (t, 2, 2, TAB_CENTER | TAT_TITLE, _("Mean")); - - tab_text (t, 5, 2, TAB_CENTER | TAT_TITLE, _("Lower")); - tab_text (t, 6, 2, TAB_CENTER | TAT_TITLE, _("Upper")); - - HMAPX_FOR_EACH (pp, node, &os->hmap) + struct pivot_table *table = pivot_table_create (N_("Paired Samples Test")); + pivot_table_set_weight_var (table, tt->wv); + + struct pivot_dimension *statistics = pivot_dimension_create ( + table, PIVOT_AXIS_COLUMN, N_("Statistics")); + struct pivot_category *group = pivot_category_create_group ( + statistics->root, N_("Paired Differences"), + N_("Mean"), PIVOT_RC_OTHER, + N_("Std. Deviation"), PIVOT_RC_OTHER, + N_("S.E. Mean"), PIVOT_RC_OTHER); + struct pivot_category *interval = pivot_category_create_group__ ( + group, pivot_value_new_text_format ( + N_("%g%% Confidence Interval of the Difference"), + tt->confidence * 100.0)); + pivot_category_create_leaves (interval, + N_("Lower"), PIVOT_RC_OTHER, + N_("Upper"), PIVOT_RC_OTHER); + pivot_category_create_leaves (statistics->root, + N_("t"), PIVOT_RC_OTHER, + N_("df"), PIVOT_RC_COUNT, + N_("Sig. (2-tailed)"), PIVOT_RC_SIGNIFICANCE); + + struct pivot_dimension *pairs = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Pairs")); + + for (size_t i = 0; i < os->n_ps; i++) { - int v = pp->posn; - double cc, mean, sigma; - double df ; - double tval; - double p, q; - double se_mean; - - moments_calculate (pp->mom_diff, &cc, &mean, &sigma, NULL, NULL); - - df = cc - 1.0; - tab_text_format (t, 0, v + heading_rows, TAB_LEFT, _("Pair %d"), v + 1); + struct pair_stats *pp = &os->ps[i]; + struct pivot_category *group = pivot_category_create_group__ ( + pairs->root, pivot_value_new_text_format (N_("Pair %d"), i + 1)); - tab_text_format (t, 1, v + heading_rows, TAB_LEFT, _("%s - %s"), - var_to_string (pp->var0), - var_to_string (pp->var1)); + int row = pivot_category_create_leaf ( + group, pivot_value_new_text_format (N_("%s - %s"), + var_to_string (pp->var0), + var_to_string (pp->var1))); - tval = mean * sqrt (cc / sigma); - se_mean = sqrt (sigma / cc); - - tab_double (t, 2, v + heading_rows, TAB_RIGHT, mean, NULL, RC_OTHER); - tab_double (t, 3, v + heading_rows, TAB_RIGHT, sqrt (sigma), NULL, RC_OTHER); - tab_double (t, 4, v + heading_rows, TAB_RIGHT, se_mean, NULL, RC_OTHER); + double cc, mean, sigma; + moments_calculate (pp->mom_diff, &cc, &mean, &sigma, NULL, NULL); - tab_double (t, 7, v + heading_rows, TAB_RIGHT, tval, NULL, RC_OTHER); - tab_double (t, 8, v + heading_rows, TAB_RIGHT, df, NULL, RC_WEIGHT); + double df = cc - 1.0; + double t = mean * sqrt (cc / sigma); + double se_mean = sqrt (sigma / cc); - p = gsl_cdf_tdist_P (tval, df); - q = gsl_cdf_tdist_Q (tval, df); + double p = gsl_cdf_tdist_P (t, df); + double q = gsl_cdf_tdist_Q (t, df); + double sig = 2.0 * (t > 0 ? q : p); - tab_double (t, 9, v + heading_rows, TAB_RIGHT, 2.0 * (tval > 0 ? q : p), NULL, RC_PVALUE); + double t_qinv = gsl_cdf_tdist_Qinv ((1.0 - tt->confidence) / 2.0, df); - tval = gsl_cdf_tdist_Qinv ( (1.0 - tt->confidence) / 2.0, df); + double entries[] = { + mean, + sqrt (sigma), + se_mean, + mean - t_qinv * se_mean, + mean + t_qinv * se_mean, + t, + df, + sig, + }; + for (size_t i = 0; i < sizeof entries / sizeof *entries; i++) + pivot_table_put2 (table, i, row, pivot_value_new_number (entries[i])); - tab_double (t, 5, v + heading_rows, TAB_RIGHT, mean - tval * se_mean, NULL, RC_OTHER); - tab_double (t, 6, v + heading_rows, TAB_RIGHT, mean + tval * se_mean, NULL, RC_OTHER); } - tab_submit (t); + pivot_table_submit (table); } diff --git a/src/language/stats/wilcoxon.c b/src/language/stats/wilcoxon.c index 2c58962047..230e97df57 100644 --- a/src/language/stats/wilcoxon.c +++ b/src/language/stats/wilcoxon.c @@ -35,11 +35,15 @@ #include "libpspp/misc.h" #include "math/sort.h" #include "math/wilcoxon-sig.h" -#include "output/tab.h" +#include "output/pivot-table.h" #include "gl/minmax.h" #include "gl/xalloc.h" +#include "gettext.h" +#define N_(msgid) msgid +#define _(msgid) gettext (msgid) + static double append_difference (const struct ccase *c, casenumber n UNUSED, void *aux) { @@ -203,91 +207,65 @@ wilcoxon_execute (const struct dataset *ds, free (ws); } - - +static void +put_row (struct pivot_table *table, int var_idx, int sign_idx, + double n, double sum) +{ + pivot_table_put3 (table, 0, sign_idx, var_idx, pivot_value_new_number (n)); + if (sum != SYSMIS) + { + pivot_table_put3 (table, 1, sign_idx, var_idx, + pivot_value_new_number (sum / n)); + pivot_table_put3 (table, 2, sign_idx, var_idx, + pivot_value_new_number (sum)); + } +} -#include "gettext.h" -#define _(msgid) gettext (msgid) +static int +add_pair_leaf (struct pivot_dimension *dimension, variable_pair *pair) +{ + char *label = xasprintf ("%s - %s", var_to_string ((*pair)[0]), + var_to_string ((*pair)[1])); + return pivot_category_create_leaf ( + dimension->root, + pivot_value_new_user_text_nocopy (label)); +} static void show_ranks_box (const struct wilcoxon_state *ws, const struct two_sample_test *t2s, const struct dictionary *dict) { - size_t i; - - const struct fmt_spec *wfmt = dict_get_weight_format (dict); + struct pivot_table *table = pivot_table_create (N_("Ranks")); + pivot_table_set_weight_var (table, dict_get_weight (dict)); - struct tab_table *table = tab_create (5, 1 + 4 * t2s->n_pairs); - tab_set_format (table, RC_WEIGHT, wfmt); + pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Statistics"), + N_("N"), PIVOT_RC_COUNT, + N_("Mean Rank"), PIVOT_RC_OTHER, + N_("Sum of Ranks"), PIVOT_RC_OTHER); - tab_title (table, _("Ranks")); + pivot_dimension_create (table, PIVOT_AXIS_ROW, N_("Sign"), + N_("Negative Ranks"), N_("Positive Ranks"), + N_("Ties"), N_("Total")); - tab_headers (table, 2, 0, 1, 0); + struct pivot_dimension *pairs = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Pairs")); - /* Vertical lines inside the box */ - tab_box (table, 0, 0, -1, TAL_1, - 1, 0, tab_nc (table) - 1, tab_nr (table) - 1 ); - - /* Box around entire table */ - tab_box (table, TAL_2, TAL_2, -1, -1, - 0, 0, tab_nc (table) - 1, tab_nr (table) - 1 ); - - - tab_text (table, 2, 0, TAB_CENTER, _("N")); - tab_text (table, 3, 0, TAB_CENTER, _("Mean Rank")); - tab_text (table, 4, 0, TAB_CENTER, _("Sum of Ranks")); - - - for (i = 0 ; i < t2s->n_pairs; ++i) + for (size_t i = 0 ; i < t2s->n_pairs; ++i) { variable_pair *vp = &t2s->pairs[i]; - - struct string pair_name; - ds_init_cstr (&pair_name, var_to_string ((*vp)[0])); - ds_put_cstr (&pair_name, " - "); - ds_put_cstr (&pair_name, var_to_string ((*vp)[1])); - - tab_text (table, 1, 1 + i * 4, TAB_LEFT, _("Negative Ranks")); - tab_text (table, 1, 2 + i * 4, TAB_LEFT, _("Positive Ranks")); - tab_text (table, 1, 3 + i * 4, TAB_LEFT, _("Ties")); - tab_text (table, 1, 4 + i * 4, TAB_LEFT, _("Total")); - - tab_hline (table, TAL_1, 0, tab_nc (table) - 1, 1 + i * 4); - - - tab_text (table, 0, 1 + i * 4, TAB_LEFT, ds_cstr (&pair_name)); - ds_destroy (&pair_name); - - - /* N */ - tab_double (table, 2, 1 + i * 4, TAB_RIGHT, ws[i].negatives.n, NULL, RC_WEIGHT); - tab_double (table, 2, 2 + i * 4, TAB_RIGHT, ws[i].positives.n, NULL, RC_WEIGHT); - tab_double (table, 2, 3 + i * 4, TAB_RIGHT, ws[i].n_zeros, NULL, RC_WEIGHT); - - tab_double (table, 2, 4 + i * 4, TAB_RIGHT, - ws[i].n_zeros + ws[i].positives.n + ws[i].negatives.n, NULL, RC_WEIGHT); - - /* Sums */ - tab_double (table, 4, 1 + i * 4, TAB_RIGHT, ws[i].negatives.sum, NULL, RC_OTHER); - tab_double (table, 4, 2 + i * 4, TAB_RIGHT, ws[i].positives.sum, NULL, RC_OTHER); - - - /* Means */ - tab_double (table, 3, 1 + i * 4, TAB_RIGHT, - ws[i].negatives.sum / (double) ws[i].negatives.n, NULL, RC_OTHER); - - tab_double (table, 3, 2 + i * 4, TAB_RIGHT, - ws[i].positives.sum / (double) ws[i].positives.n, NULL, RC_OTHER); - + int pair_idx = add_pair_leaf (pairs, vp); + + const struct wilcoxon_state *w = &ws[i]; + put_row (table, pair_idx, 0, w->negatives.n, w->negatives.sum); + put_row (table, pair_idx, 1, w->positives.n, w->positives.sum); + put_row (table, pair_idx, 2, w->n_zeros, SYSMIS); + put_row (table, pair_idx, 3, + w->n_zeros + w->positives.n + w->negatives.n, SYSMIS); } - tab_hline (table, TAL_2, 0, tab_nc (table) - 1, 1); - tab_vline (table, TAL_2, 2, 0, tab_nr (table) - 1); - - - tab_submit (table); + pivot_table_submit (table); } @@ -298,79 +276,64 @@ show_tests_box (const struct wilcoxon_state *ws, double timer UNUSED ) { - size_t i; - struct tab_table *table = tab_create (1 + t2s->n_pairs, exact ? 5 : 3); - - tab_title (table, _("Test Statistics")); - - tab_headers (table, 1, 0, 1, 0); - - /* Vertical lines inside the box */ - tab_box (table, 0, 0, -1, TAL_1, - 0, 0, tab_nc (table) - 1, tab_nr (table) - 1 ); - - /* Box around entire table */ - tab_box (table, TAL_2, TAL_2, -1, -1, - 0, 0, tab_nc (table) - 1, tab_nr (table) - 1 ); - - - tab_text (table, 0, 1, TAB_LEFT, _("Z")); - tab_text (table, 0, 2, TAB_LEFT, _("Asymp. Sig. (2-tailed)")); - - if ( exact ) + struct pivot_table *table = pivot_table_create (N_("Test Statistics")); + + struct pivot_dimension *statistics = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Statistics"), + N_("Z"), PIVOT_RC_OTHER, + N_("Asymp. Sig. (2-tailed)"), PIVOT_RC_SIGNIFICANCE); + if (exact) + pivot_category_create_leaves ( + statistics->root, + N_("Exact Sig. (2-tailed)"), PIVOT_RC_SIGNIFICANCE, + N_("Exact Sig. (1-tailed)"), PIVOT_RC_SIGNIFICANCE); + + struct pivot_dimension *pairs = pivot_dimension_create ( + table, PIVOT_AXIS_COLUMN, N_("Pairs")); + + struct pivot_footnote *too_many_pairs = pivot_table_create_footnote ( + table, pivot_value_new_text ( + N_("Too many pairs to calculate exact significance"))); + + for (size_t i = 0 ; i < t2s->n_pairs; ++i) { - tab_text (table, 0, 3, TAB_LEFT, _("Exact Sig. (2-tailed)")); - tab_text (table, 0, 4, TAB_LEFT, _("Exact Sig. (1-tailed)")); - -#if 0 - tab_text (table, 0, 5, TAB_LEFT, _("Point Probability")); -#endif - } - - for (i = 0 ; i < t2s->n_pairs; ++i) - { - double z; - double n = ws[i].positives.n + ws[i].negatives.n; variable_pair *vp = &t2s->pairs[i]; + int pair_idx = add_pair_leaf (pairs, vp); - struct string pair_name; - ds_init_cstr (&pair_name, var_to_string ((*vp)[0])); - ds_put_cstr (&pair_name, " - "); - ds_put_cstr (&pair_name, var_to_string ((*vp)[1])); - - - tab_text (table, 1 + i, 0, TAB_CENTER, ds_cstr (&pair_name)); - ds_destroy (&pair_name); - - z = MIN (ws[i].positives.sum, ws[i].negatives.sum); + double n = ws[i].positives.n + ws[i].negatives.n; + double z = MIN (ws[i].positives.sum, ws[i].negatives.sum); z -= n * (n + 1)/ 4.0; - z /= sqrt (n * (n + 1) * (2*n + 1)/24.0 - ws[i].tiebreaker / 48.0); - tab_double (table, 1 + i, 1, TAB_RIGHT, z, NULL, RC_OTHER); - - tab_double (table, 1 + i, 2, TAB_RIGHT, - 2.0 * gsl_cdf_ugaussian_P (z), - NULL, RC_PVALUE); + double entries[4]; + int n_entries = 0; + entries[n_entries++] = z; + entries[n_entries++] = 2.0 * gsl_cdf_ugaussian_P (z); + int footnote_idx = -1; if (exact) { double p = LevelOfSignificanceWXMPSR (ws[i].positives.sum, n); if (p < 0) { - msg (MW, _("Too many pairs to calculate exact significance.")); + footnote_idx = n_entries; + entries[n_entries++] = SYSMIS; } else - { - tab_double (table, 1 + i, 3, TAB_RIGHT, p, NULL, RC_PVALUE); - tab_double (table, 1 + i, 4, TAB_RIGHT, p / 2.0, NULL, RC_PVALUE); - } - } + { + entries[n_entries++] = p; + entries[n_entries++] = p / 2.0; + } + } + + for (int j = 0; j < n_entries; j++) + { + struct pivot_value *value = pivot_value_new_number (entries[j]); + if (j == footnote_idx) + pivot_value_add_footnote (value, too_many_pairs); + pivot_table_put2 (table, j, pair_idx, value); + } } - tab_hline (table, TAL_2, 0, tab_nc (table) - 1, 1); - tab_vline (table, TAL_2, 1, 0, tab_nr (table) - 1); - - - tab_submit (table); + pivot_table_submit (table); } diff --git a/src/language/utilities/output.c b/src/language/utilities/output.c index a2e630d791..a699fdf5f5 100644 --- a/src/language/utilities/output.c +++ b/src/language/utilities/output.c @@ -26,47 +26,19 @@ #include "language/lexer/lexer.h" #include "language/lexer/format-parser.h" #include "libpspp/message.h" +#include "libpspp/string-set.h" #include "libpspp/version.h" -#include "output/tab.h" +#include "output/pivot-table.h" #include "gl/xalloc.h" #include "gettext.h" #define _(msgid) gettext (msgid) -struct thing -{ - const char *identifier; - enum result_class rc; -}; - -extern struct fmt_spec ugly [n_RC]; - -static const struct thing things[] = - { - {"SIGNIFICANCE", RC_PVALUE}, - {"COUNT" ,RC_WEIGHT} - }; - -#define N_THINGS (sizeof (things) / sizeof (struct thing)) - -struct output_spec -{ - /* An array of classes */ - enum result_class *rc; - - int n_rc; - - /* The format to be applied to these classes */ - struct fmt_spec fmt; -}; - int cmd_output (struct lexer *lexer, struct dataset *ds UNUSED) { - int j, i; - struct output_spec *output_specs = NULL; - int n_os = 0; + struct string_set rc_names = STRING_SET_INITIALIZER (rc_names); if (!lex_force_match_id (lexer, "MODIFY")) { @@ -88,12 +60,8 @@ cmd_output (struct lexer *lexer, struct dataset *ds UNUSED) } else if (lex_match_id (lexer, "TABLECELLS")) { - struct output_spec *os; - output_specs = xrealloc (output_specs, sizeof (*output_specs) * ++n_os); - os = &output_specs[n_os - 1]; - os->n_rc = 0; - os->rc = NULL; - bool format = false; + string_set_clear (&rc_names); + struct fmt_spec fmt = { 0, 0, 0 }; while (lex_token (lexer) != T_SLASH && lex_token (lexer) != T_ENDCMD) @@ -106,31 +74,17 @@ cmd_output (struct lexer *lexer, struct dataset *ds UNUSED) if (! lex_force_match (lexer, T_LBRACK)) goto error; - while (lex_token (lexer) != T_RBRACK && - lex_token (lexer) != T_ENDCMD) - { - int i; - for (i = 0 ; i < N_THINGS; ++i) - { - if (lex_match_id (lexer, things[i].identifier)) - { - os->rc = xrealloc (os->rc, sizeof (*os->rc) * ++os->n_rc); - os->rc[os->n_rc - 1] = things[i].rc; - break; - } - } - if (i >= N_THINGS) - { - lex_error (lexer, _("Unknown TABLECELLS class")); - goto error; - } - } + while (lex_token (lexer) == T_ID) + { + string_set_insert (&rc_names, lex_tokcstr (lexer)); + lex_get (lexer); + } + if (! lex_force_match (lexer, T_RBRACK)) goto error; } else if (lex_match_id (lexer, "FORMAT")) { - struct fmt_spec fmt; char type[FMT_TYPE_LEN_MAX + 1]; int width = -1; int decimals = -1; @@ -157,9 +111,6 @@ cmd_output (struct lexer *lexer, struct dataset *ds UNUSED) fmt.w = width; fmt.d = decimals; - - os->fmt = fmt; - format = true; } else { @@ -167,8 +118,15 @@ cmd_output (struct lexer *lexer, struct dataset *ds UNUSED) goto error; } } - if (!format) - goto error; + + if (fmt.w) + { + const struct string_set_node *node; + const char *s; + STRING_SET_FOR_EACH (s, node, &rc_names) + if (!pivot_result_class_change (s, &fmt)) + lex_error (lexer, _("Unknown cell class %s."), s); + } } else { @@ -177,23 +135,9 @@ cmd_output (struct lexer *lexer, struct dataset *ds UNUSED) } } - /* Populate the global table, with the values we parsed */ - for (i = 0; i < n_os; ++i) - { - for (j = 0; j < output_specs[i].n_rc; ++j) - { - ugly [output_specs[i].rc[j]] = output_specs[i].fmt; - } - } - - for (j = 0; j < n_os; ++j) - free (output_specs[j].rc); - free (output_specs); return CMD_SUCCESS; - error: - for (j = 0; j < n_os; ++j) - free (output_specs[j].rc); - free (output_specs); + error: + string_set_destroy (&rc_names); return CMD_SUCCESS; } diff --git a/src/language/utilities/set.q b/src/language/utilities/set.q index 710bc2f44e..8b06448fe4 100644 --- a/src/language/utilities/set.q +++ b/src/language/utilities/set.q @@ -346,17 +346,11 @@ stc_custom_tnumbers (struct lexer *lexer, lex_match (lexer, T_EQUALS); if (lex_match_id (lexer, "VALUES")) - { - settings_set_value_style (SETTINGS_VAL_STYLE_VALUES); - } + settings_set_show_values (SETTINGS_VALUE_SHOW_VALUE); else if (lex_match_id (lexer, "LABELS")) - { - settings_set_value_style (SETTINGS_VAL_STYLE_LABELS); - } + settings_set_show_values (SETTINGS_VALUE_SHOW_LABEL); else if (lex_match_id (lexer, "BOTH")) - { - settings_set_value_style (SETTINGS_VAL_STYLE_BOTH); - } + settings_set_show_values (SETTINGS_VALUE_SHOW_BOTH); else { lex_error_expecting (lexer, "VALUES", "LABELS", "BOTH", NULL_SENTINEL); @@ -375,17 +369,11 @@ stc_custom_tvars (struct lexer *lexer, lex_match (lexer, T_EQUALS); if (lex_match_id (lexer, "NAMES")) - { - settings_set_var_style (SETTINGS_VAR_STYLE_NAMES); - } + settings_set_show_variables (SETTINGS_VALUE_SHOW_VALUE); else if (lex_match_id (lexer, "LABELS")) - { - settings_set_var_style (SETTINGS_VAR_STYLE_LABELS); - } + settings_set_show_variables (SETTINGS_VALUE_SHOW_LABEL); else if (lex_match_id (lexer, "BOTH")) - { - settings_set_var_style (SETTINGS_VAR_STYLE_BOTH); - } + settings_set_show_variables (SETTINGS_VALUE_SHOW_BOTH); else { lex_error_expecting (lexer, "NAMES", "LABELS", "BOTH", NULL_SENTINEL); diff --git a/src/math/categoricals.c b/src/math/categoricals.c index 92bb3d1d32..30c4c567ce 100644 --- a/src/math/categoricals.c +++ b/src/math/categoricals.c @@ -59,6 +59,7 @@ struct variable_node struct hmap_node node; /* In struct categorical's 'varmap'. */ const struct variable *var; /* The variable. */ struct hmap valmap; /* Contains "struct value_node"s. */ + union value *values; /* Values in valmap, as a sorted array. */ }; static int @@ -74,10 +75,11 @@ compare_value_node_3way (const void *vn1_, const void *vn2_, const void *aux) } static struct variable_node * -lookup_variable (const struct hmap *map, const struct variable *var, unsigned int hash) +lookup_variable (const struct hmap *map, const struct variable *var) { struct variable_node *vn; - HMAP_FOR_EACH_WITH_HASH (vn, struct variable_node, node, hash, map) + HMAP_FOR_EACH_WITH_HASH (vn, struct variable_node, node, + hash_pointer (var, 0), map) if (vn->var == var) return vn; return NULL; @@ -339,14 +341,14 @@ categoricals_create (struct interaction *const *inter, size_t n_inter, for (size_t v = 0; v < inter[i]->n_vars; ++v) { const struct variable *var = inter[i]->vars[v]; - unsigned int hash = hash_pointer (var, 0); - struct variable_node *vn = lookup_variable (&cat->varmap, var, hash); + struct variable_node *vn = lookup_variable (&cat->varmap, var); if (!vn) { vn = pool_malloc (cat->pool, sizeof *vn); vn->var = var; + vn->values = NULL; hmap_init (&vn->valmap); - hmap_insert (&cat->varmap, &vn->node, hash); + hmap_insert (&cat->varmap, &vn->node, hash_pointer (var, 0)); } iap->varnodes[v] = vn; } @@ -577,6 +579,23 @@ categoricals_done (const struct categoricals *cat_) cat->sane = true; } +union value * +categoricals_get_var_values (const struct categoricals *cat, + const struct variable *var, size_t *np) +{ + struct variable_node *vn = lookup_variable (&cat->varmap, var); + *np = hmap_count (&vn->valmap); + if (!vn->values) + { + vn->values = pool_nalloc (cat->pool, *np, sizeof *vn->values); + + struct value_node *valnd; + HMAP_FOR_EACH (valnd, struct value_node, node, &vn->valmap) + vn->values[valnd->index] = valnd->val; + } + return vn->values; +} + static struct interact_params * df_to_iap (const struct categoricals *cat, int subscript) { @@ -704,6 +723,21 @@ categoricals_get_user_data_by_category_real (const struct categoricals *cat, return n < hmap_count (&iap->ivmap) ? iap->ivs[n]->user_data : NULL; } +int +categoricals_get_value_index_by_category_real (const struct categoricals *cat, + int iact_idx, int cat_idx, + int var_idx) +{ + const struct interact_params *iap = &cat->iap[iact_idx]; + const struct interaction_value *ivn = iap->ivs[cat_idx]; + const struct variable *var = iap->iact->vars[var_idx]; + const struct variable_node *vn = iap->varnodes[var_idx]; + const union value *val = case_data (ivn->ccase, var); + int width = var_get_width (var); + unsigned int hash = value_hash (val, width, 0); + return lookup_value (&vn->valmap, val, hash, width)->index; +} + /* Return a case containing the set of values corresponding to CAT_INDEX. */ const struct ccase * categoricals_get_case_by_category (const struct categoricals *cat, diff --git a/src/math/categoricals.h b/src/math/categoricals.h index 4ab17299a7..5e49b4504a 100644 --- a/src/math/categoricals.h +++ b/src/math/categoricals.h @@ -62,7 +62,7 @@ void categoricals_update (struct categoricals *, const struct ccase *); void categoricals_done (const struct categoricals *); bool categoricals_is_complete (const struct categoricals *); -/* Counting categories. +/* Categories. A variable's number of categories is the number of unique values observed in the data passed to categoricals_update(). @@ -76,6 +76,9 @@ bool categoricals_is_complete (const struct categoricals *); size_t categoricals_n_count (const struct categoricals *, size_t idx); size_t categoricals_n_total (const struct categoricals *); +union value *categoricals_get_var_values (const struct categoricals *, + const struct variable *, size_t *n); + /* Degrees of freedom. A categorical variable with N_CATS categories has N_CATS - 1 degrees of @@ -142,6 +145,9 @@ const struct ccase *categoricals_get_case_by_category_real ( void *categoricals_get_user_data_by_category_real ( const struct categoricals *, int iact, int n); +int categoricals_get_value_index_by_category_real ( + const struct categoricals *, int iact_idx, int cat_idx, int var_idx); + void *categoricals_get_user_data_by_category (const struct categoricals *, int category); const struct ccase *categoricals_get_case_by_category ( diff --git a/src/math/covariance.c b/src/math/covariance.c index 66b44c12c1..8aa652b5bd 100644 --- a/src/math/covariance.c +++ b/src/math/covariance.c @@ -754,62 +754,46 @@ covariance_dim (const struct covariance * cov) */ #include "libpspp/str.h" -#include "output/tab.h" +#include "output/pivot-table.h" #include "data/format.h" /* Create a table which can be populated with the encodings for the covariance matrix COV */ -struct tab_table * -covariance_dump_enc_header (const struct covariance *cov, int length) +struct pivot_table * +covariance_dump_enc_header (const struct covariance *cov) { - struct tab_table *t = tab_create (cov->dim, length); - int n; - int i; - - tab_title (t, "Covariance Encoding"); - - tab_box (t, - TAL_2, TAL_2, 0, 0, - 0, 0, tab_nc (t) - 1, tab_nr (t) - 1); - - tab_hline (t, TAL_2, 0, tab_nc (t) - 1, 1); - - - for (i = 0 ; i < cov->n_vars; ++i) - { - tab_text (t, i, 0, TAT_TITLE, var_get_name (cov->vars[i])); - tab_vline (t, TAL_1, i + 1, 0, tab_nr (t) - 1); - } - - n = 0; - while (i < cov->dim) + struct pivot_table *table = pivot_table_create ("Covariance Encoding"); + + struct pivot_dimension *factors = pivot_dimension_create ( + table, PIVOT_AXIS_COLUMN, "Factor"); + for (size_t i = 0 ; i < cov->n_vars; ++i) + pivot_category_create_leaf (factors->root, + pivot_value_new_variable (cov->vars[i])); + for (size_t i = 0, n = 0; i < cov->dim - cov->n_vars; n++) { - struct string str; - int idx = i - cov->n_vars; const struct interaction *iact = - categoricals_get_interaction_by_subscript (cov->categoricals, idx); - int df; + categoricals_get_interaction_by_subscript (cov->categoricals, i); - ds_init_empty (&str); + struct string str = DS_EMPTY_INITIALIZER; interaction_to_string (iact, &str); + struct pivot_category *group = pivot_category_create_group__ ( + factors->root, + pivot_value_new_user_text_nocopy (ds_steal_cstr (&str))); - df = categoricals_df (cov->categoricals, n); - - tab_joint_text (t, - i, 0, - i + df - 1, 0, - TAT_TITLE, ds_cstr (&str)); - - if (i + df < tab_nr (t) - 1) - tab_vline (t, TAL_1, i + df, 0, tab_nr (t) - 1); + int df = categoricals_df (cov->categoricals, n); + for (int j = 0; j < df; j++) + pivot_category_create_leaf_rc (group, pivot_value_new_integer (j), + PIVOT_RC_INTEGER); i += df; - n++; - ds_destroy (&str); } - return t; + struct pivot_dimension *matrix = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, "Matrix", "Matrix"); + matrix->hide_all_labels = true; + + return table; } @@ -819,14 +803,13 @@ covariance_dump_enc_header (const struct covariance *cov, int length) */ void covariance_dump_enc (const struct covariance *cov, const struct ccase *c, - struct tab_table *t) + struct pivot_table *table) { - static int row = 0; - int i; - ++row; - for (i = 0 ; i < cov->dim; ++i) - { - double v = get_val (cov, i, c); - tab_double (t, i, row, 0, v, i < cov->n_vars ? NULL : &F_8_0, RC_OTHER); - } + int row = pivot_category_create_leaf ( + table->dimensions[1]->root, + pivot_value_new_integer (table->dimensions[1]->n_leaves)); + + for (int i = 0 ; i < cov->dim; ++i) + pivot_table_put2 ( + table, i, row, pivot_value_new_number (get_val (cov, i, c))); } diff --git a/src/math/covariance.h b/src/math/covariance.h index 18f1137a79..eef6019ddf 100644 --- a/src/math/covariance.h +++ b/src/math/covariance.h @@ -49,14 +49,8 @@ const gsl_matrix *covariance_moments (const struct covariance *cov, int m); const struct categoricals * covariance_get_categoricals (const struct covariance *cov); size_t covariance_dim (const struct covariance * cov); -struct tab_table ; -void -covariance_dump_enc (const struct covariance *cov, const struct ccase *c, - struct tab_table *t); - -struct tab_table * -covariance_dump_enc_header (const struct covariance *cov, int length); - - +struct pivot_table *covariance_dump_enc_header (const struct covariance *); +void covariance_dump_enc (const struct covariance *, const struct ccase *, + struct pivot_table *); #endif diff --git a/src/math/interaction.c b/src/math/interaction.c index 5dfabe99dd..909ce0de63 100644 --- a/src/math/interaction.c +++ b/src/math/interaction.c @@ -137,7 +137,7 @@ interaction_to_string (const struct interaction *iact, struct string *str) { ds_put_cstr (str, var_to_string (iact->vars[v])); if (v + 1 < iact->n_vars) - ds_put_cstr (str, " * "); + ds_put_cstr (str, " × "); } } diff --git a/src/output/ascii.c b/src/output/ascii.c index c0218e6626..1df08c4067 100644 --- a/src/output/ascii.c +++ b/src/output/ascii.c @@ -45,7 +45,6 @@ #include "output/message-item.h" #include "output/options.h" #include "output/render.h" -#include "output/tab.h" #include "output/table-item.h" #include "output/text-item.h" @@ -909,11 +908,11 @@ ascii_test_write (struct output_driver *driver, return; struct area_style style = { + .cell_style.halign = TABLE_HALIGN_LEFT, .font_style.bold = bold, .font_style.underline = underline, }; struct table_cell cell = { - .options = TAB_LEFT, .text = CONST_CAST (char *, s), .style = &style, }; diff --git a/src/output/automake.mk b/src/output/automake.mk index 5753d59a0f..636e9a7980 100644 --- a/src/output/automake.mk +++ b/src/output/automake.mk @@ -67,11 +67,13 @@ src_output_liboutput_la_SOURCES = \ src/output/output-item.h \ src/output/page-setup-item.c \ src/output/page-setup-item.h \ + src/output/pivot-output.c \ + src/output/pivot-table.c \ + src/output/pivot-table.h \ src/output/render.c \ src/output/render.h \ src/output/tab.c \ src/output/tab.h \ - src/output/table-casereader.c \ src/output/table-item.c \ src/output/table-item.h \ src/output/table-paste.c \ diff --git a/src/output/cairo.c b/src/output/cairo.c index e7cb59f0d7..975779bfa9 100644 --- a/src/output/cairo.c +++ b/src/output/cairo.c @@ -44,7 +44,6 @@ #include "output/options.h" #include "output/page-setup-item.h" #include "output/render.h" -#include "output/tab.h" #include "output/table-item.h" #include "output/table.h" #include "output/text-item.h" @@ -1233,7 +1232,6 @@ xr_layout_cell_text (struct xr_driver *xr, const struct table_cell *cell, int R = options & TAB_ROTATE ? 0 : 1; struct xr_font *font = (options & TAB_FIX ? &xr->fonts[XR_FONT_FIXED] - : options & TAB_EMPH ? &xr->fonts[XR_FONT_EMPHASIS] : &xr->fonts[XR_FONT_PROPORTIONAL]); struct xr_font local_font; if (font_style->typeface) @@ -1485,7 +1483,7 @@ xr_layout_cell_text (struct xr_driver *xr, const struct table_cell *cell, dump_line (xr, -xr->left_margin, best, xr->width + xr->right_margin, best, RENDER_LINE_SINGLE, - &(struct cell_color) CELL_COLOR (0, 255, 0)); + &CELL_COLOR (0, 255, 0)); } } diff --git a/src/output/html.c b/src/output/html.c index 05fc08eb62..f41a984cf7 100644 --- a/src/output/html.c +++ b/src/output/html.c @@ -561,8 +561,6 @@ html_output_table (struct html_driver *html, const struct table_item *item) /* Output cell contents. */ const char *s = cell.text; - if (cell.options & TAB_EMPH) - fputs ("", html->file); if (cell.options & TAB_FIX) { fputs ("", html->file); @@ -574,8 +572,6 @@ html_output_table (struct html_driver *html, const struct table_item *item) s += strspn (s, CC_SPACES); escape_string (html->file, s, strlen (s), " ", "
"); } - if (cell.options & TAB_EMPH) - fputs ("
", html->file); html_put_footnote_markers (html, cell.footnotes, cell.n_footnotes); diff --git a/src/output/odt.c b/src/output/odt.c index 60a5b7fd4b..56b26bb1ac 100644 --- a/src/output/odt.c +++ b/src/output/odt.c @@ -40,7 +40,6 @@ #include "output/driver-provider.h" #include "output/message-item.h" #include "output/options.h" -#include "output/tab.h" #include "output/table-item.h" #include "output/table-provider.h" #include "output/text-item.h" diff --git a/src/output/pivot-output.c b/src/output/pivot-output.c new file mode 100644 index 0000000000..b1bfa31fd1 --- /dev/null +++ b/src/output/pivot-output.c @@ -0,0 +1,509 @@ +/* PSPP - a program for statistical analysis. + Copyright (C) 2018 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include + +#include + +#include "output/pivot-table.h" + +#include "data/settings.h" +#include "libpspp/assertion.h" +#include "libpspp/pool.h" +#include "output/tab.h" +#include "output/table.h" +#include "output/table-item.h" +#include "output/text-item.h" +#include "output/table-provider.h" + +#include "gl/minmax.h" +#include "gl/xalloc.h" + +#define H TABLE_HORZ +#define V TABLE_VERT + +static const struct pivot_category * +find_category (const struct pivot_dimension *d, int dim_index, + const size_t *indexes, int row_ofs) +{ + size_t index = indexes[dim_index]; + assert (index < d->n_leaves); + for (const struct pivot_category *c = d->presentation_leaves[index]; + c; c = c->parent) + { + if (!row_ofs) + return c; + + row_ofs -= 1 + c->extra_depth; + if (row_ofs < 0) + return NULL; + } + return NULL; +} + +static struct area_style * +area_style_override (struct pool *pool, + const struct area_style *in, + const struct cell_style *cell_, + const struct font_style *font_) +{ + const struct cell_style *cell = cell_ ? cell_ : &in->cell_style; + const struct font_style *font = font_ ? font_ : &in->font_style; + + struct area_style *out = (pool + ? pool_alloc (pool, sizeof *out) + : xmalloc (sizeof *out)); + *out = (struct area_style) { + .cell_style.halign = cell->halign, + .cell_style.valign = cell->valign, + .cell_style.decimal_offset = cell->decimal_offset, + .cell_style.margin[H][0] = cell->margin[H][0], + .cell_style.margin[H][1] = cell->margin[H][1], + .cell_style.margin[V][0] = cell->margin[V][0], + .cell_style.margin[V][1] = cell->margin[V][1], + .font_style.fg[0] = font->fg[0], + .font_style.fg[1] = font->fg[1], + .font_style.bg[0] = font->bg[0], + .font_style.bg[1] = font->bg[1], + .font_style.typeface = (font->typeface + ? pool_strdup (pool, font->typeface) + : NULL), + .font_style.size = font->size, + .font_style.bold = font->bold, + .font_style.italic = font->italic, + .font_style.underline = font->underline, + .font_style.markup = font->markup, + }; + return out; +} + +static void +fill_cell (struct tab_table *t, int x1, int y1, int x2, int y2, + const struct area_style *style, int style_idx, + const struct pivot_value *value, struct footnote **footnotes, + enum settings_value_show show_values, + enum settings_value_show show_variables, + bool rotate_label) +{ + + struct string s = DS_EMPTY_INITIALIZER; + int opts = style_idx << TAB_STYLE_SHIFT; + if (value) + { + bool numeric = pivot_value_format_body (value, show_values, + show_variables, &s); + if (numeric) + opts |= TAB_NUMERIC; + if (value->font_style && value->font_style->markup) + opts |= TAB_MARKUP; + if (rotate_label) + opts |= TAB_ROTATE; + } + tab_joint_text (t, x1, y1, x2, y2, opts, ds_cstr (&s)); + ds_destroy (&s); + + if (value) + { + if (value->cell_style || value->font_style) + tab_add_style (t, x1, y1, + area_style_override (t->container, style, + value->cell_style, + value->font_style)); + + for (size_t i = 0; i < value->n_footnotes; i++) + tab_add_footnote (t, x1, y1, footnotes[value->footnotes[i]->idx]); + } +} + +static struct table_item_text * +pivot_value_to_table_item_text (const struct pivot_value *value, + const struct area_style *area, + struct footnote **footnotes, + enum settings_value_show show_values, + enum settings_value_show show_variables) +{ + if (!value) + return NULL; + + struct string s = DS_EMPTY_INITIALIZER; + pivot_value_format_body (value, show_values, show_variables, &s); + + struct table_item_text *text = xmalloc (sizeof *text); + *text = (struct table_item_text) { + .content = ds_steal_cstr (&s), + .footnotes = xnmalloc (value->n_footnotes, sizeof *text->footnotes), + .n_footnotes = value->n_footnotes, + .style = area_style_override ( + NULL, area, value->cell_style, value->font_style), + }; + + for (size_t i = 0; i < value->n_footnotes; i++) + text->footnotes[i] = footnotes[value->footnotes[i]->idx]; + + return text; +} + +static int +get_table_rule (const struct table_border_style *styles, + enum pivot_border style_idx) +{ + return styles[style_idx].stroke | (style_idx << TAB_RULE_STYLE_SHIFT); +} + +static void +draw_line (struct tab_table *t, const struct table_border_style *styles, + enum pivot_border style_idx, + enum table_axis axis, int a, int b0, int b1) +{ + int rule = get_table_rule (styles, style_idx); + if (axis == H) + tab_hline (t, rule, b0, b1, a); + else + tab_vline (t, rule, a, b0, b1); +} + +static void +compose_headings (struct tab_table *t, + const struct pivot_axis *a_axis, enum table_axis a, + const struct pivot_axis *b_axis, + const struct table_border_style *borders, + enum pivot_border dim_col_horz, + enum pivot_border dim_col_vert, + enum pivot_border cat_col_horz, + enum pivot_border cat_col_vert, + const size_t *column_enumeration, size_t n_columns, + const struct area_style *label_style, int label_style_idx, + const struct area_style *corner_style, + struct footnote **footnotes, + enum settings_value_show show_values, + enum settings_value_show show_variables, + bool rotate_inner_labels, bool rotate_outer_labels) +{ + enum table_axis b = !a; + int b_size = a_axis->label_depth; + int a_ofs = b_axis->label_depth; + + if (!a_axis->n_dimensions || !n_columns || !b_size) + return; + + int bottom_row = b_size - 1; + const int stride = MAX (1, a_axis->n_dimensions); + for (int dim_index = 0; dim_index < a_axis->n_dimensions; dim_index++) + { + const struct pivot_dimension *d = a_axis->dimensions[dim_index]; + if (d->hide_all_labels) + continue; + + for (int row_ofs = 0; row_ofs < d->label_depth; row_ofs++) + { + for (size_t x1 = 0; x1 < n_columns; ) + { + const struct pivot_category *c = find_category ( + d, dim_index, column_enumeration + x1 * stride, row_ofs); + if (!c) + { + x1++; + continue; + } + + size_t x2; + for (x2 = x1 + 1; x2 < n_columns; x2++) + { + const struct pivot_category *c2 = find_category ( + d, dim_index, column_enumeration + x2 * stride, row_ofs); + if (c != c2) + break; + } + + int y1 = bottom_row - row_ofs - c->extra_depth; + int y2 = bottom_row - row_ofs + 1; + bool is_outer_row = y1 == 0; + bool is_inner_row = y2 == b_size; + if (pivot_category_is_leaf (c) || c->show_label) + { + int bb[TABLE_N_AXES][2]; + bb[a][0] = x1 + a_ofs; + bb[a][1] = x2 + a_ofs - 1; + bb[b][0] = y1; + bb[b][1] = y2 - 1; + bool rotate = ((rotate_inner_labels && is_inner_row) + || (rotate_outer_labels && is_outer_row)); + fill_cell (t, bb[H][0], bb[V][0], bb[H][1], bb[V][1], + label_style, label_style_idx, c->name, footnotes, + show_values, show_variables, rotate); + + if (pivot_category_is_leaf (c) && x2 + 1 <= n_columns) + { + enum pivot_border style + = (y1 == 0 && a_axis->label_depth > d->label_depth + ? dim_col_vert + : cat_col_vert); + draw_line (t, borders, style, b, x2 + a_ofs, y1, + t->table.n[b] - 1); + } + if (pivot_category_is_leaf (c) && x1 > 0) + { + enum pivot_border style + = (y1 == 0 && a_axis->label_depth > d->label_depth + ? dim_col_vert + : cat_col_vert); + draw_line (t, borders, style, b, x1 + a_ofs, y1, + t->table.n[b] - 1); + } + } + if (c->parent && c->parent->show_label) + draw_line (t, borders, cat_col_horz, a, y1, + x1 + a_ofs, x2 + a_ofs - 1); + + x1 = x2; + } + } + + if (d->root->show_label_in_corner && a_ofs > 0) + { + int bb[TABLE_N_AXES][2]; + bb[a][0] = a_ofs - 1; + bb[a][1] = a_ofs - 1; + bb[b][0] = bottom_row - d->label_depth + 1; + bb[b][1] = bottom_row; + fill_cell (t, bb[H][0], bb[V][0], bb[H][1], bb[V][1], + corner_style, PIVOT_AREA_CORNER, d->root->name, footnotes, + show_values, show_variables, false); + } + + if (dim_index > 1) + draw_line (t, borders, dim_col_horz, a, bottom_row + 1, a_ofs, + t->table.n[a] - 1); + + bottom_row -= d->label_depth; + } +} + +static void +pivot_table_submit_layer (const struct pivot_table *st, + const size_t *layer_indexes) +{ + const size_t *pindexes[PIVOT_N_AXES] + = { [PIVOT_AXIS_LAYER] = layer_indexes }; + + struct string layer_label = DS_EMPTY_INITIALIZER; + const struct pivot_axis *layer_axis = &st->axes[PIVOT_AXIS_LAYER]; + for (size_t i = 0; i < layer_axis->n_dimensions; i++) + { + const struct pivot_dimension *d = layer_axis->dimensions[i]; + if (d->n_leaves) + { + if (!ds_is_empty (&layer_label)) + ds_put_byte (&layer_label, '\n'); + pivot_value_format (d->root->name, st->show_values, + st->show_variables, &layer_label); + ds_put_cstr (&layer_label, ": "); + pivot_value_format (d->data_leaves[layer_indexes[i]]->name, + st->show_values, st->show_variables, + &layer_label); + } + } + + size_t body[TABLE_N_AXES]; + size_t *column_enumeration = pivot_table_enumerate_axis ( + st, PIVOT_AXIS_COLUMN, layer_indexes, st->omit_empty, &body[H]); + size_t *row_enumeration = pivot_table_enumerate_axis ( + st, PIVOT_AXIS_ROW, layer_indexes, st->omit_empty, &body[V]); + + int stub[TABLE_N_AXES] = { + [H] = st->axes[PIVOT_AXIS_ROW].label_depth, + [V] = st->axes[PIVOT_AXIS_COLUMN].label_depth, + }; + struct tab_table *table = tab_create (body[H] + stub[H], + body[V] + stub[V]); + tab_headers (table, stub[H], 0, stub[V], 0); + + for (size_t i = 0; i < PIVOT_N_AREAS; i++) + table->styles[i] = area_style_override (table->container, &st->areas[i], + NULL, NULL); + + for (size_t i = 0; i < PIVOT_N_BORDERS; i++) + { + const struct table_border_style *in = &st->borders[i]; + table->rule_colors[i] = pool_alloc (table->container, + sizeof *table->rule_colors[i]); + struct cell_color *out = table->rule_colors[i]; + out->alpha = in->color.alpha; + out->r = in->color.r; + out->g = in->color.g; + out->b = in->color.b; + } + + struct footnote **footnotes = xcalloc (st->n_footnotes, sizeof *footnotes); + for (size_t i = 0; i < st->n_footnotes; i++) + footnotes[i] = tab_create_footnote ( + table, i, + pivot_value_to_string (st->footnotes[i]->content, + st->show_values, st->show_variables), + pivot_value_to_string (st->footnotes[i]->marker, + st->show_values, st->show_variables), + area_style_override (table->container, &st->areas[PIVOT_AREA_FOOTER], + st->footnotes[i]->content->cell_style, + st->footnotes[i]->content->font_style)); + + compose_headings (table, + &st->axes[PIVOT_AXIS_COLUMN], H, &st->axes[PIVOT_AXIS_ROW], + st->borders, + PIVOT_BORDER_DIM_COL_HORZ, + PIVOT_BORDER_DIM_COL_VERT, + PIVOT_BORDER_CAT_COL_HORZ, + PIVOT_BORDER_CAT_COL_VERT, + column_enumeration, body[H], + &st->areas[PIVOT_AREA_COLUMN_LABELS], + PIVOT_AREA_COLUMN_LABELS, + &st->areas[PIVOT_AREA_CORNER], footnotes, + st->rotate_inner_column_labels, + st->show_values, st->show_variables, false); + + compose_headings (table, + &st->axes[PIVOT_AXIS_ROW], V, &st->axes[PIVOT_AXIS_COLUMN], + st->borders, + PIVOT_BORDER_DIM_ROW_VERT, + PIVOT_BORDER_DIM_ROW_HORZ, + PIVOT_BORDER_CAT_ROW_VERT, + PIVOT_BORDER_CAT_ROW_HORZ, + row_enumeration, body[V], + &st->areas[PIVOT_AREA_ROW_LABELS], + PIVOT_AREA_ROW_LABELS, + &st->areas[PIVOT_AREA_CORNER], footnotes, + false, st->show_values, st->show_variables, + st->rotate_outer_row_labels); + + size_t *dindexes = xcalloc (st->n_dimensions, sizeof *dindexes); + size_t y = 0; + PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_ROW], row_enumeration, + &st->axes[PIVOT_AXIS_ROW]) + { + size_t x = 0; + PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_COLUMN], + column_enumeration, + &st->axes[PIVOT_AXIS_COLUMN]) + { + pivot_table_convert_indexes_ptod (st, pindexes, dindexes); + const struct pivot_value *value = pivot_table_get (st, dindexes); + fill_cell (table, + x + stub[H], y + stub[V], + x + stub[H], y + stub[V], + &st->areas[PIVOT_AREA_DATA], PIVOT_AREA_DATA, + value, footnotes, + st->show_values, st->show_variables, false); + + x++; + } + + y++; + } + free (dindexes); + + if (st->corner_text && stub[H] && stub[V]) + fill_cell (table, 0, 0, stub[H] - 1, stub[V] - 1, + &st->areas[PIVOT_AREA_CORNER], PIVOT_AREA_CORNER, + st->corner_text, footnotes, + st->show_values, st->show_variables, false); + + if (tab_nc (table) && tab_nr (table)) + { + tab_hline ( + table, get_table_rule (st->borders, PIVOT_BORDER_INNER_TOP), + 0, tab_nc (table) - 1, 0); + tab_hline ( + table, get_table_rule (st->borders, PIVOT_BORDER_INNER_BOTTOM), + 0, tab_nc (table) - 1, tab_nr (table)); + tab_vline ( + table, get_table_rule (st->borders, PIVOT_BORDER_INNER_LEFT), + 0, 0, tab_nr (table) - 1); + tab_vline ( + table, get_table_rule (st->borders, PIVOT_BORDER_INNER_RIGHT), + tab_nc (table), 0, tab_nr (table) - 1); + + if (stub[V]) + tab_hline ( + table, get_table_rule (st->borders, PIVOT_BORDER_DATA_TOP), + 0, tab_nc (table) - 1, stub[V]); + if (stub[H]) + tab_vline ( + table, get_table_rule (st->borders, PIVOT_BORDER_DATA_LEFT), + stub[H], 0, tab_nr (table) - 1); + + } + free (column_enumeration); + free (row_enumeration); + + struct table_item *ti = table_item_create (&table->table, NULL, NULL); + + if (st->title) + { + struct table_item_text *title = pivot_value_to_table_item_text ( + st->title, &st->areas[PIVOT_AREA_TITLE], footnotes, + st->show_values, st->show_variables); + table_item_set_title (ti, title); + table_item_text_destroy (title); + } + + if (!ds_is_empty (&layer_label)) + { + struct table_item_text *layers = table_item_text_create ( + ds_cstr (&layer_label)); + layers->style = area_style_override (NULL, &st->areas[PIVOT_AREA_LAYERS], + NULL, NULL); + table_item_set_layers (ti, layers); + table_item_text_destroy (layers); + + ds_destroy (&layer_label); + } + + if (st->caption) + { + struct table_item_text *caption = pivot_value_to_table_item_text ( + st->caption, &st->areas[PIVOT_AREA_CAPTION], footnotes, + st->show_values, st->show_variables); + table_item_set_caption (ti, caption); + table_item_text_destroy (caption); + } + + table_item_submit (ti); +} + +void +pivot_table_submit (const struct pivot_table *st) +{ + pivot_table_assign_label_depth (CONST_CAST (struct pivot_table *, st)); + + int old_decimal = settings_get_decimal_char (FMT_COMMA); + if (st->decimal == '.' || st->decimal == ',') + settings_set_decimal_char (st->decimal); + + if (st->print_all_layers) + { + size_t *layer_indexes; + + PIVOT_AXIS_FOR_EACH (layer_indexes, &st->axes[PIVOT_AXIS_LAYER]) + { + if (st->paginate_layers) + text_item_submit (text_item_create (TEXT_ITEM_EJECT_PAGE, "")); + pivot_table_submit_layer (st, layer_indexes); + } + } + else + pivot_table_submit_layer (st, st->current_layer); + + settings_set_decimal_char (old_decimal); +} diff --git a/src/output/pivot-table.c b/src/output/pivot-table.c new file mode 100644 index 0000000000..0b4f0fb4ba --- /dev/null +++ b/src/output/pivot-table.c @@ -0,0 +1,2076 @@ +/* PSPP - a program for statistical analysis. + Copyright (C) 2017, 2018 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include + +#include "output/pivot-table.h" + +#include + +#include "data/data-out.h" +#include "data/settings.h" +#include "data/value.h" +#include "data/variable.h" +#include "libpspp/hash-functions.h" +#include "libpspp/i18n.h" + +#include "gl/c-ctype.h" +#include "gl/intprops.h" +#include "gl/minmax.h" +#include "gl/xalloc.h" +#include "gl/xmemdup0.h" +#include "gl/xsize.h" + +#include "gettext.h" +#define _(msgid) gettext (msgid) +#define N_(msgid) msgid + +static const struct fmt_spec *pivot_table_get_format ( + const struct pivot_table *, const char *s); + +/* Pivot table display styling. */ + +/* Returns the name of AREA. */ +const char * +pivot_area_to_string (enum pivot_area area) +{ + switch (area) + { + case PIVOT_AREA_TITLE: return "title"; + case PIVOT_AREA_CAPTION: return "caption"; + case PIVOT_AREA_FOOTER: return "footer"; + case PIVOT_AREA_CORNER: return "corner"; + case PIVOT_AREA_COLUMN_LABELS: return "column labels"; + case PIVOT_AREA_ROW_LABELS: return "row labels"; + case PIVOT_AREA_DATA: return "data"; + case PIVOT_AREA_LAYERS: return "layers"; + case PIVOT_N_AREAS: default: return "**error**"; + } +} + +/* Returns the name of BORDER. */ +const char * +pivot_border_to_string (enum pivot_border border) +{ + switch (border) + { + case PIVOT_BORDER_TITLE: + return "title"; + + case PIVOT_BORDER_OUTER_LEFT: + return "left outer frame"; + case PIVOT_BORDER_OUTER_TOP: + return "top outer frame"; + case PIVOT_BORDER_OUTER_RIGHT: + return "right outer frame"; + case PIVOT_BORDER_OUTER_BOTTOM: + return "bottom outer frame"; + + case PIVOT_BORDER_INNER_LEFT: + return "left inner frame"; + case PIVOT_BORDER_INNER_TOP: + return "top inner frame"; + case PIVOT_BORDER_INNER_RIGHT: + return "right inner frame"; + case PIVOT_BORDER_INNER_BOTTOM: + return "bottom inner frame"; + + case PIVOT_BORDER_DATA_LEFT: + return "data area left"; + case PIVOT_BORDER_DATA_TOP: + return "data area top"; + + case PIVOT_BORDER_DIM_ROW_HORZ: + return "row label horizontal dimension border"; + case PIVOT_BORDER_DIM_ROW_VERT: + return "row label vertical dimension border"; + case PIVOT_BORDER_DIM_COL_HORZ: + return "column label horizontal dimension border"; + case PIVOT_BORDER_DIM_COL_VERT: + return "column label vertical dimension border"; + + case PIVOT_BORDER_CAT_ROW_HORZ: + return "row label horizontal category border"; + case PIVOT_BORDER_CAT_ROW_VERT: + return "row label vertical category border"; + case PIVOT_BORDER_CAT_COL_HORZ: + return "column label horizontal category border"; + case PIVOT_BORDER_CAT_COL_VERT: + return "column label vertical category border"; + + case PIVOT_N_BORDERS: + default: + return "**error**"; + } +} + +void +pivot_table_sizing_uninit (struct pivot_table_sizing *sizing) +{ + if (sizing) + { + free (sizing->widths); + free (sizing->breaks); + free (sizing->keeps); + } +} + +/* Axes. */ + +/* Returns the name of AXIS_TYPE. */ +const char * +pivot_axis_type_to_string (enum pivot_axis_type axis_type) +{ + switch (axis_type) + { + case PIVOT_AXIS_LAYER: + return "layer"; + + case PIVOT_AXIS_ROW: + return "row"; + + case PIVOT_AXIS_COLUMN: + return "column"; + + default: + return ""; + } +} + +static enum pivot_axis_type +pivot_axis_type_transpose (enum pivot_axis_type axis_type) +{ + assert (axis_type == PIVOT_AXIS_ROW || axis_type == PIVOT_AXIS_COLUMN); + return (axis_type == PIVOT_AXIS_ROW ? PIVOT_AXIS_COLUMN : PIVOT_AXIS_ROW); +} + +/* Implementation of PIVOT_AXIS_FOR_EACH. */ +size_t * +pivot_axis_iterator_next (size_t *indexes, const struct pivot_axis *axis) +{ + if (!indexes) + { + if (axis->n_dimensions) + for (size_t i = 0; i < axis->n_dimensions; i++) + if (axis->dimensions[i]->n_leaves == 0) + return NULL; + + return xcalloc (axis->n_dimensions, sizeof *indexes); + } + + for (size_t i = 0; i < axis->n_dimensions; i++) + { + const struct pivot_dimension *d = axis->dimensions[i]; + if (++indexes[i] < d->n_leaves) + return indexes; + + indexes[i] = 0; + } + + free (indexes); + return NULL; +} + +/* Dimensions. */ + +static void +pivot_category_set_rc (struct pivot_category *category, const char *s) +{ + const struct fmt_spec *format = pivot_table_get_format ( + category->dimension->table, s); + if (format) + category->format = *format; +} + +static void +pivot_category_create_leaves_valist (struct pivot_category *parent, + va_list args) +{ + const char *s; + while ((s = va_arg (args, const char *))) + { + if (!strncmp (s, "RC_", 3)) + { + assert (parent->n_subs); + pivot_category_set_rc (parent->subs[parent->n_subs - 1], s); + } + else + pivot_category_create_leaf (parent, pivot_value_new_text (s)); + } +} + +/* Creates a new dimension with the given NAME in TABLE and returns it. The + dimension is added to axis AXIS_TYPE, becoming the outermost dimension on + that axis. + + NAME should be a translatable name, but not actually translated yet, + e.g. enclosed in N_(). To use a different kind of value for a name, use + pivot_dimension_create__() instead. + + The optional varargs parameters may be used to add an initial set of + categories to the dimension. Each string should be a translatable category + name, but not actually translated yet, e.g. enclosed in N_(). Each string + may optionally be followod by a PIVOT_RC_* string that specifies the default + numeric format for cells in this category. */ +struct pivot_dimension * SENTINEL (0) +(pivot_dimension_create) (struct pivot_table *table, + enum pivot_axis_type axis_type, + const char *name, ...) +{ + struct pivot_dimension *d = pivot_dimension_create__ ( + table, axis_type, pivot_value_new_text (name)); + + va_list args; + va_start (args, name); + pivot_category_create_leaves_valist (d->root, args); + va_end (args); + + return d; +} + +/* Creates a new dimension with the given NAME in TABLE and returns it. The + dimension is added to axis AXIS_TYPE, becoming the outermost dimension on + that axis. */ +struct pivot_dimension * +pivot_dimension_create__ (struct pivot_table *table, + enum pivot_axis_type axis_type, + struct pivot_value *name) +{ + assert (pivot_table_is_empty (table)); + + struct pivot_dimension *d = xmalloc (sizeof *d); + *d = (struct pivot_dimension) { + .table = table, + .axis_type = axis_type, + .level = table->axes[axis_type].n_dimensions, + .top_index = table->n_dimensions, + .root = xmalloc (sizeof *d->root), + }; + + struct pivot_category *root = d->root; + *root = (struct pivot_category) { + .name = name, + .parent = NULL, + .dimension = d, + .show_label = false, + .data_index = SIZE_MAX, + .presentation_index = SIZE_MAX, + }; + + table->dimensions = xrealloc ( + table->dimensions, (table->n_dimensions + 1) * sizeof *table->dimensions); + table->dimensions[table->n_dimensions++] = d; + + struct pivot_axis *axis = &table->axes[axis_type]; + axis->dimensions = xrealloc ( + axis->dimensions, (axis->n_dimensions + 1) * sizeof *axis->dimensions); + axis->dimensions[axis->n_dimensions++] = d; + + /* XXX extent and label_depth need to be calculated later. */ + + return d; +} + +void +pivot_dimension_destroy (struct pivot_dimension *d) +{ + if (!d) + return; + + pivot_category_destroy (d->root); + free (d->data_leaves); + free (d->presentation_leaves); +} + +/* Returns the first leaf node in an in-order traversal that is a child of + CAT. */ +static const struct pivot_category * UNUSED +pivot_category_first_leaf (const struct pivot_category *cat) +{ + if (pivot_category_is_leaf (cat)) + return cat; + + for (size_t i = 0; i < cat->n_subs; i++) + { + const struct pivot_category *first + = pivot_category_first_leaf (cat->subs[i]); + if (first) + return first; + } + + return NULL; +} + +/* Returns the next leaf node in an in-order traversal starting at CAT, which + must be a leaf. */ +static const struct pivot_category * UNUSED +pivot_category_next_leaf (const struct pivot_category *cat) +{ + assert (pivot_category_is_leaf (cat)); + + for (;;) + { + const struct pivot_category *parent = cat->parent; + if (!parent) + return NULL; + for (size_t i = cat->group_index + 1; i < parent->n_subs; i++) + { + const struct pivot_category *next + = pivot_category_first_leaf (parent->subs[i]); + if (next) + return next; + } + + cat = cat->parent; + } +} + +static void +pivot_category_add_child (struct pivot_category *child) +{ + struct pivot_category *parent = child->parent; + + assert (pivot_category_is_group (parent)); + if (parent->n_subs >= parent->allocated_subs) + parent->subs = x2nrealloc (parent->subs, &parent->allocated_subs, + sizeof *parent->subs); + parent->subs[parent->n_subs++] = child; +} + +/* Adds leaf categories as a child of PARENT. To create top-level categories + within dimension 'd', pass 'd->root' for PARENT. + + Each of the varargs parameters should be a string, each of which should be a + translatable category name, but not actually translated yet, e.g. enclosed + in N_(). Each string may optionally be followod by a PIVOT_RC_* string that + specifies the default numeric format for cells in this category. + + Returns the category index, which is just a 0-based array index, for the + first new category. + + Leaves have to be created in in-order, that is, don't create a group and add + some leaves, then add leaves outside the group and try to add more leaves + inside it. */ +int SENTINEL (0) +(pivot_category_create_leaves) (struct pivot_category *parent, ...) +{ + int retval = parent->dimension->n_leaves; + + va_list args; + va_start (args, parent); + pivot_category_create_leaves_valist (parent, args); + va_end (args); + + return retval; +} + +/* Creates a new leaf category with the given NAME as a child of PARENT. To + create a top-level category within dimension 'd', pass 'd->root' for PARENT. + Returns the category index, which is just a 0-based array index, for the new + category. + + Leaves have to be created in in-order, that is, don't create a group and add + some leaves, then add leaves outside the group and try to add more leaves + inside it. */ +int +pivot_category_create_leaf (struct pivot_category *parent, + struct pivot_value *name) +{ + return pivot_category_create_leaf_rc (parent, name, NULL); +} + +/* Creates a new leaf category with the given NAME as a child of PARENT. To + create a top-level category within dimension 'd', pass 'd->root' for PARENT. + Returns the category index, which is just a 0-based array index, for the new + category. + + If RC is nonnull and the name of a result category, the category is assigned + that result category. + + Leaves have to be created in in-order, that is, don't create a group and add + some leaves, then add leaves outside the group and try to add more leaves + inside it. */ +int +pivot_category_create_leaf_rc (struct pivot_category *parent, + struct pivot_value *name, const char *rc) +{ + struct pivot_dimension *d = parent->dimension; + + struct pivot_category *leaf = xmalloc (sizeof *leaf); + *leaf = (struct pivot_category) { + .name = name, + .parent = parent, + .dimension = d, + .group_index = parent->n_subs, + .data_index = d->n_leaves, + .presentation_index = d->n_leaves, + }; + + if (d->n_leaves >= d->allocated_leaves) + { + d->data_leaves = x2nrealloc (d->data_leaves, &d->allocated_leaves, + sizeof *d->data_leaves); + d->presentation_leaves = xrealloc ( + d->presentation_leaves, + d->allocated_leaves * sizeof *d->presentation_leaves); + } + + d->data_leaves[d->n_leaves] = leaf; + d->presentation_leaves[d->n_leaves] = leaf; + d->n_leaves++; + + pivot_category_add_child (leaf); + + /* Make sure that the new child is the last in in-order. */ + assert (!pivot_category_next_leaf (leaf)); + + pivot_category_set_rc (leaf, rc); + + return leaf->data_index; +} + +/* Adds a new category group named NAME as a child of PARENT. To create a + top-level group within dimension 'd', pass 'd->root' for PARENT. + + NAME should be a translatable name, but not actually translated yet, + e.g. enclosed in N_(). To use a different kind of value for a name, use + pivot_category_create_group__() instead. + + The optional varargs parameters may be used to add an initial set of + categories to the group. Each string should be a translatable category + name, but not actually translated yet, e.g. enclosed in N_(). Each string + may optionally be followod by a PIVOT_RC_* string that specifies the default + numeric format for cells in this category. + + Returns the new group. */ +struct pivot_category * SENTINEL (0) +(pivot_category_create_group) (struct pivot_category *parent, + const char *name, ...) +{ + struct pivot_category *group = pivot_category_create_group__ ( + parent, pivot_value_new_text (name)); + + va_list args; + va_start (args, name); + pivot_category_create_leaves_valist (group, args); + va_end (args); + + return group; +} + +/* Adds a new category group named NAME as a child of PARENT. To create a + top-level group within dimension 'd', pass 'd->root' for PARENT. Returns + the new group. */ +struct pivot_category * +pivot_category_create_group__ (struct pivot_category *parent, + struct pivot_value *name) +{ + struct pivot_dimension *d = parent->dimension; + + struct pivot_category *group = xmalloc (sizeof *group); + *group = (struct pivot_category) { + .name = name, + .parent = parent, + .dimension = d, + .show_label = true, + .group_index = parent->n_subs, + .data_index = SIZE_MAX, + .presentation_index = SIZE_MAX, + }; + + pivot_category_add_child (group); + + return group; +} + +void +pivot_category_destroy (struct pivot_category *c) +{ + if (!c) + return; + + pivot_value_destroy (c->name); + for (size_t i = 0; i < c->n_subs; i++) + pivot_category_destroy (c->subs[i]); + free (c); +} + +/* Result classes. + + These are usually the easiest way to control the formatting of numeric data + in a pivot table. See pivot_dimension_create() for an explanation of their + use. */ +struct result_class + { + const char *name; /* "RC_*". */ + struct fmt_spec format; + }; + +/* Formats for most of the result classes. */ +static struct result_class result_classes[] = + { + { PIVOT_RC_INTEGER, { FMT_F, 40, 0 } }, + { PIVOT_RC_PERCENT, { FMT_PCT, 40, 1 } }, + { PIVOT_RC_CORRELATION, { FMT_F, 40, 3 } }, + { PIVOT_RC_SIGNIFICANCE, { FMT_F, 40, 3 } }, + { PIVOT_RC_RESIDUAL, { FMT_F, 40, 2 } }, + { PIVOT_RC_COUNT, { 0, 0, 0 } }, + { PIVOT_RC_OTHER, { 0, 0, 0 } }, + }; + +/* Has PIVOT_RC_COUNT been overridden by the user? */ +static bool overridden_count_format; + +static struct result_class * +pivot_result_class_find (const char *s) +{ + for (size_t i = 0; i < sizeof result_classes / sizeof *result_classes; i++) + if (!strcmp (s, result_classes[i].name)) + return &result_classes[i]; + return NULL; +} + +static const struct fmt_spec * +pivot_table_get_format (const struct pivot_table *table, const char *s) +{ + if (!s) + return NULL; + else if (!strcmp (s, PIVOT_RC_OTHER)) + return settings_get_format (); + else if (!strcmp (s, PIVOT_RC_COUNT) && !overridden_count_format) + return &table->weight_format; + else + { + const struct result_class *rc = pivot_result_class_find (s); + return rc ? &rc->format : NULL; + } +} + +/* Sets the format specification for the result class named S (which should not + include the RC_ prefix) to *FORMAT. Returns true if successful, false if S + does not name a known result class. */ +bool +pivot_result_class_change (const char *s_, const struct fmt_spec *format) +{ + char *s = xasprintf ("RC_%s", s_); + struct result_class *rc = pivot_result_class_find (s); + if (rc) + { + rc->format = *format; + if (!strcmp (s, PIVOT_RC_COUNT)) + overridden_count_format = true; + } + free (s); + + return rc != NULL; +} + +/* One piece of data within a pivot table. */ +struct pivot_cell + { + struct hmap_node hmap_node; /* In struct pivot_table's 'cells' hmap. */ + struct pivot_value *value; + unsigned int idx[]; /* One index per table dimension. */ + }; + +/* Pivot tables. */ + +/* Creates and returns a new pivot table with the given TITLE. TITLE should be + a text string marked for translation but not actually translated yet, + e.g. N_("Descriptive Statistics"). + + Operations commonly performed on the new pivot_table: + + - If empty rows or columns should not be displayed, set ->omit_empty to + true. + + - Set the format to use for "count" values with pivot_table_set_weight_var() + or pivot_table_set_weight_format(). + + This function is a shortcut for pivot_table_create__() for the most common + case. Use pivot_table_create__() directly if the title should be some kind + of value other than an ordinary text string. + + See the large comment at the top of pivot-table.h for general advice on + creating pivot tables. */ +struct pivot_table * +pivot_table_create (const char *title) +{ + return pivot_table_create__ (pivot_value_new_text (title)); +} + +/* Creates and returns a new pivot table with the given TITLE. + + Operations commonly performed on the new pivot_table: + + - If empty rows or columns should not be displayed, set ->omit_empty to + true. + + - Set the format to use for "count" values with pivot_table_set_weight_var() + or pivot_table_set_weight_format(). + + See the large comment at the top of pivot-table.h for general advice on + creating pivot tables. */ +struct pivot_table * +pivot_table_create__ (struct pivot_value *title) +{ + struct pivot_table *table = xzalloc (sizeof *table); + table->weight_format = (struct fmt_spec) { FMT_F, 40, 0 }; + table->title = title; + + /* Set default area styles. */ +#define STYLE(BOLD, H, V, L, R, T, B) { \ + .cell_style = { \ + .halign = TABLE_HALIGN_##H, \ + .valign = TABLE_VALIGN_##V, \ + .margin = { [TABLE_HORZ][0] = L, [TABLE_HORZ][1] = R, \ + [TABLE_VERT][0] = T, [TABLE_VERT][1] = B }, \ + }, \ + .font_style = { \ + .bold = BOLD, \ + .fg = { [0] = CELL_COLOR_BLACK, [1] = CELL_COLOR_BLACK}, \ + .bg = { [0] = CELL_COLOR_WHITE, [1] = CELL_COLOR_WHITE}, \ + }, \ + } + static const struct area_style default_area_styles[PIVOT_N_AREAS] = { + [PIVOT_AREA_TITLE] = STYLE( true, CENTER, CENTER, 8,11,1,8), + [PIVOT_AREA_CAPTION] = STYLE(false, LEFT, TOP, 8,11,1,1), + [PIVOT_AREA_FOOTER] = STYLE(false, LEFT, TOP, 11, 8,2,3), + [PIVOT_AREA_CORNER] = STYLE(false, LEFT, BOTTOM, 8,11,1,1), + [PIVOT_AREA_COLUMN_LABELS] = STYLE(false, CENTER, BOTTOM, 8,11,1,3), + [PIVOT_AREA_ROW_LABELS] = STYLE(false, LEFT, TOP, 8,11,1,3), + [PIVOT_AREA_DATA] = STYLE(false, MIXED, TOP, 8,11,1,1), + [PIVOT_AREA_LAYERS] = STYLE(false, LEFT, BOTTOM, 8,11,1,3), + }; +#undef STYLE + for (size_t i = 0; i < PIVOT_N_AREAS; i++) + table->areas[i] = default_area_styles[i]; + + /* Set default border styles. */ + static const enum table_stroke default_strokes[PIVOT_N_BORDERS] = { + [PIVOT_BORDER_TITLE] = TABLE_STROKE_NONE, + [PIVOT_BORDER_OUTER_LEFT] = TABLE_STROKE_NONE, + [PIVOT_BORDER_OUTER_TOP] = TABLE_STROKE_NONE, + [PIVOT_BORDER_OUTER_RIGHT] = TABLE_STROKE_NONE, + [PIVOT_BORDER_OUTER_BOTTOM] = TABLE_STROKE_NONE, + [PIVOT_BORDER_INNER_LEFT] = TABLE_STROKE_THICK, + [PIVOT_BORDER_INNER_TOP] = TABLE_STROKE_THICK, + [PIVOT_BORDER_INNER_RIGHT] = TABLE_STROKE_THICK, + [PIVOT_BORDER_INNER_BOTTOM] = TABLE_STROKE_THICK, + [PIVOT_BORDER_DATA_LEFT] = TABLE_STROKE_THICK, + [PIVOT_BORDER_DATA_TOP] = TABLE_STROKE_THICK, + [PIVOT_BORDER_DIM_ROW_HORZ] = TABLE_STROKE_SOLID, + [PIVOT_BORDER_DIM_ROW_VERT] = TABLE_STROKE_NONE, + [PIVOT_BORDER_DIM_COL_HORZ] = TABLE_STROKE_SOLID, + [PIVOT_BORDER_DIM_COL_VERT] = TABLE_STROKE_SOLID, + [PIVOT_BORDER_CAT_ROW_HORZ] = TABLE_STROKE_NONE, + [PIVOT_BORDER_CAT_ROW_VERT] = TABLE_STROKE_NONE, + [PIVOT_BORDER_CAT_COL_HORZ] = TABLE_STROKE_SOLID, + [PIVOT_BORDER_CAT_COL_VERT] = TABLE_STROKE_SOLID, + }; + for (size_t i = 0; i < PIVOT_N_BORDERS; i++) + table->borders[i] = (struct table_border_style) { + .stroke = default_strokes[i], + .color = CELL_COLOR_BLACK, + }; + + table->row_labels_in_corner = true; + hmap_init (&table->cells); + + return table; +} + +/* Creates and returns a new pivot table with the given TITLE and a single cell + with the given CONTENT. + + This is really just for error handling. */ +struct pivot_table * +pivot_table_create_for_text (struct pivot_value *title, + struct pivot_value *content) +{ + struct pivot_table *table = pivot_table_create__ (title); + + struct pivot_dimension *d = pivot_dimension_create ( + table, PIVOT_AXIS_ROW, N_("Error")); + d->hide_all_labels = true; + pivot_category_create_leaf (d->root, pivot_value_new_text ("null")); + + pivot_table_put1 (table, 0, content); + + return table; +} + +/* Destroys TABLE and frees everything it points to. */ +void +pivot_table_destroy (struct pivot_table *table) +{ + if (!table) + return; + + free (table->current_layer); + free (table->table_look); + + for (int i = 0; i < TABLE_N_AXES; i++) + pivot_table_sizing_uninit (&table->sizing[i]); + + free (table->continuation); + + for (int i = 0; i < sizeof table->ccs / sizeof *table->ccs; i++) + free (table->ccs[i]); + + free (table->command_local); + free (table->command_c); + free (table->language); + free (table->locale); + + free (table->dataset); + free (table->datafile); + + for (size_t i = 0; i < table->n_footnotes; i++) + pivot_footnote_destroy (table->footnotes[i]); + free (table->footnotes); + + pivot_value_destroy (table->title); + pivot_value_destroy (table->subtype); + pivot_value_destroy (table->corner_text); + pivot_value_destroy (table->caption); + + for (size_t i = 0; i < PIVOT_N_AREAS; i++) + area_style_uninit (&table->areas[i]); + + for (size_t i = 0; i < table->n_dimensions; i++) + pivot_dimension_destroy (table->dimensions[i]); + free (table->dimensions); + + for (size_t i = 0; i < PIVOT_N_AXES; i++) + free (table->axes[i].dimensions); + + struct pivot_cell *cell, *next_cell; + HMAP_FOR_EACH_SAFE (cell, next_cell, struct pivot_cell, hmap_node, + &table->cells) + { + hmap_delete (&table->cells, &cell->hmap_node); + pivot_value_destroy (cell->value); + free (cell); + } + hmap_destroy (&table->cells); + + free (table); +} + +/* Sets the format used for PIVOT_RC_COUNT cells to the one used for variable + WV, which should be the weight variable for the dictionary whose data or + statistics are being put into TABLE. + + This has no effect if WV is NULL. */ +void +pivot_table_set_weight_var (struct pivot_table *table, + const struct variable *wv) +{ + if (wv) + pivot_table_set_weight_format (table, var_get_print_format (wv)); +} + +/* Sets the format used for PIVOT_RC_COUNT cells to WFMT, which should be the + format for the dictionary whose data or statistics are being put into TABLE. + + This has no effect if WFMT is NULL. */ +void +pivot_table_set_weight_format (struct pivot_table *table, + const struct fmt_spec *wfmt) +{ + if (wfmt) + table->weight_format = *wfmt; +} + +/* Returns true if TABLE has no cells, false otherwise. */ +bool +pivot_table_is_empty (const struct pivot_table *table) +{ + return hmap_is_empty (&table->cells); +} + +static unsigned int +pivot_cell_hash_indexes (const size_t *indexes, size_t n_idx) +{ + return hash_bytes (indexes, n_idx * sizeof *indexes, 0); +} + +static bool +equal_indexes (const size_t *a, const size_t *b, size_t n) +{ + for (size_t i = 0; i < n; i++) + if (a[i] != b[i]) + return false; + + return true; +} + +static struct pivot_cell * +pivot_table_lookup_cell__ (const struct pivot_table *table, + const size_t *dindexes, unsigned int hash) +{ + struct pivot_cell *cell; + HMAP_FOR_EACH_WITH_HASH (cell, struct pivot_cell, hmap_node, hash, + &table->cells) + if (equal_indexes (dindexes, cell->idx, table->n_dimensions)) + return cell; + return false; +} + +static struct pivot_cell * +pivot_cell_allocate (size_t n_idx) +{ + struct pivot_cell *cell UNUSED; + return xmalloc (sizeof *cell + n_idx * sizeof *cell->idx); +} + +static struct pivot_cell * +pivot_table_insert_cell (struct pivot_table *table, const size_t *dindexes) +{ + unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions); + struct pivot_cell *cell = pivot_table_lookup_cell__ (table, dindexes, hash); + if (!cell) + { + cell = pivot_cell_allocate (table->n_dimensions); + for (size_t i = 0; i < table->n_dimensions; i++) + cell->idx[i] = dindexes[i]; + cell->value = NULL; + hmap_insert (&table->cells, &cell->hmap_node, hash); + } + return cell; +} + +/* Puts VALUE in the cell in TABLE whose indexes are given by the N indexes in + DINDEXES. N must be the number of dimensions in TABLE. Takes ownership of + VALUE. + + If VALUE is a numeric value without a specified format, this function checks + each of the categories designated by DINDEXES[] and takes the format from + the first category with a result class. If none has a result class, uses + the overall default numeric format. */ +void +pivot_table_put (struct pivot_table *table, const size_t *dindexes, size_t n, + struct pivot_value *value) +{ + assert (n == table->n_dimensions); + + if (value->type == PIVOT_VALUE_NUMERIC && !value->numeric.format.w) + { + for (size_t i = 0; i < table->n_dimensions; i++) + { + const struct pivot_dimension *d = table->dimensions[i]; + if (dindexes[i] < d->n_leaves) + { + const struct pivot_category *c = d->data_leaves[dindexes[i]]; + if (c->format.w) + { + value->numeric.format = c->format; + goto done; + } + } + } + value->numeric.format = *settings_get_format (); + + done:; + } + + struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes); + pivot_value_destroy (cell->value); + cell->value = value; +} + +/* Puts VALUE in the cell in TABLE with index IDX1. TABLE must have 1 + dimension. Takes ownership of VALUE. */ +void +pivot_table_put1 (struct pivot_table *table, size_t idx1, + struct pivot_value *value) +{ + size_t dindexes[] = { idx1 }; + pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value); +} + +/* Puts VALUE in the cell in TABLE with index (IDX1, IDX2). TABLE must have 2 + dimensions. Takes ownership of VALUE. */ +void +pivot_table_put2 (struct pivot_table *table, size_t idx1, size_t idx2, + struct pivot_value *value) +{ + size_t dindexes[] = { idx1, idx2 }; + pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value); +} + +/* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3). TABLE must + have 3 dimensions. Takes ownership of VALUE. */ +void +pivot_table_put3 (struct pivot_table *table, size_t idx1, size_t idx2, + size_t idx3, struct pivot_value *value) +{ + size_t dindexes[] = { idx1, idx2, idx3 }; + pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value); +} + +/* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3, IDX4). TABLE + must have 4 dimensions. Takes ownership of VALUE. */ +void +pivot_table_put4 (struct pivot_table *table, size_t idx1, size_t idx2, + size_t idx3, size_t idx4, struct pivot_value *value) +{ + size_t dindexes[] = { idx1, idx2, idx3, idx4 }; + pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value); +} + +/* Creates and returns a new footnote in TABLE with the given CONTENT and an + automatically assigned marker. + + The footnote will only appear in output if it is referenced. Use + pivot_value_add_footnote() to add a reference to the footnote. */ +struct pivot_footnote * +pivot_table_create_footnote (struct pivot_table *table, + struct pivot_value *content) +{ + return pivot_table_create_footnote__ (table, table->n_footnotes, + NULL, content); +} + +static struct pivot_value * +pivot_make_default_footnote_marker (int idx, bool show_numeric_markers) +{ + char text[INT_BUFSIZE_BOUND (size_t)]; + if (show_numeric_markers) + snprintf (text, sizeof text, "%d", idx + 1); + else + str_format_26adic (idx + 1, false, text, sizeof text); + return pivot_value_new_user_text (text, -1); +} + +/* Creates or modifies a footnote in TABLE with 0-based number IDX. If MARKER + is nonnull, sets the footnote's marker; if CONTENT is nonnull, sets the + footnote's content. */ +struct pivot_footnote * +pivot_table_create_footnote__ (struct pivot_table *table, size_t idx, + struct pivot_value *marker, + struct pivot_value *content) +{ + if (idx >= table->n_footnotes) + { + while (idx >= table->allocated_footnotes) + table->footnotes = x2nrealloc (table->footnotes, + &table->allocated_footnotes, + sizeof *table->footnotes); + while (idx >= table->n_footnotes) + { + struct pivot_footnote *f = xmalloc (sizeof *f); + f->idx = table->n_footnotes; + f->marker = pivot_make_default_footnote_marker ( + f->idx, table->show_numeric_markers); + f->content = NULL; + + table->footnotes[table->n_footnotes++] = f; + } + } + + struct pivot_footnote *f = table->footnotes[idx]; + if (marker) + { + pivot_value_destroy (f->marker); + f->marker = marker; + } + if (content) + { + pivot_value_destroy (f->content); + f->content = content; + } + return f; +} + +/* Frees the data owned by F. */ +void +pivot_footnote_destroy (struct pivot_footnote *f) +{ + if (f) + { + pivot_value_destroy (f->content); + pivot_value_destroy (f->marker); + free (f); + } +} + +/* Converts per-axis presentation-order indexes, given in PINDEXES, into data + indexes for each dimension in TABLE in DINDEXES[]. */ +void +pivot_table_convert_indexes_ptod (const struct pivot_table *table, + const size_t *pindexes[PIVOT_N_AXES], + size_t dindexes[/* table->n_dimensions */]) +{ + for (size_t i = 0; i < PIVOT_N_AXES; i++) + { + const struct pivot_axis *axis = &table->axes[i]; + + for (size_t j = 0; j < axis->n_dimensions; j++) + { + const struct pivot_dimension *d = axis->dimensions[j]; + dindexes[d->top_index] + = d->presentation_leaves[pindexes[i][j]]->data_index; + } + } +} + +size_t * +pivot_table_enumerate_axis (const struct pivot_table *table, + enum pivot_axis_type axis_type, + const size_t *layer_indexes, bool omit_empty, + size_t *n) +{ + const struct pivot_axis *axis = &table->axes[axis_type]; + if (!axis->n_dimensions) + { + size_t *enumeration = xnmalloc (2, sizeof *enumeration); + enumeration[0] = 0; + enumeration[1] = SIZE_MAX; + if (n) + *n = 1; + return enumeration; + } + else if (!axis->extent) + { + size_t *enumeration = xmalloc (sizeof *enumeration); + *enumeration = SIZE_MAX; + if (n) + *n = 0; + return enumeration; + } + + size_t *enumeration = xnmalloc (xsum (xtimes (axis->extent, + axis->n_dimensions), 1), + sizeof *enumeration); + size_t *p = enumeration; + size_t *dindexes = xcalloc (table->n_dimensions, sizeof *dindexes); + + size_t *axis_indexes; + PIVOT_AXIS_FOR_EACH (axis_indexes, axis) + { + if (omit_empty) + { + enum pivot_axis_type axis2_type + = pivot_axis_type_transpose (axis_type); + + size_t *axis2_indexes; + PIVOT_AXIS_FOR_EACH (axis2_indexes, &table->axes[axis2_type]) + { + const size_t *pindexes[PIVOT_N_AXES]; + pindexes[PIVOT_AXIS_LAYER] = layer_indexes; + pindexes[axis_type] = axis_indexes; + pindexes[axis2_type] = axis2_indexes; + pivot_table_convert_indexes_ptod (table, pindexes, dindexes); + if (pivot_table_get (table, dindexes)) + goto found; + } + continue; + + found: + free (axis2_indexes); + } + + memcpy (p, axis_indexes, axis->n_dimensions * sizeof *p); + p += axis->n_dimensions; + } + *p = SIZE_MAX; + if (n) + *n = (p - enumeration) / axis->n_dimensions; + + free (dindexes); + return enumeration; +} + +static const struct pivot_cell * +pivot_table_lookup_cell (const struct pivot_table *table, + const size_t *dindexes) +{ + unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions); + return pivot_table_lookup_cell__ (table, dindexes, hash); +} + +const struct pivot_value * +pivot_table_get (const struct pivot_table *table, const size_t *dindexes) +{ + const struct pivot_cell *cell = pivot_table_lookup_cell (table, dindexes); + return cell ? cell->value : NULL; +} + +struct pivot_value * +pivot_table_get_rw (struct pivot_table *table, const size_t *dindexes) +{ + struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes); + if (!cell->value) + cell->value = pivot_value_new_user_text ("", -1); + return cell->value; +} + +static void +distribute_extra_depth (struct pivot_category *category, size_t extra_depth) +{ + if (pivot_category_is_group (category) && category->n_subs) + for (size_t i = 0; i < category->n_subs; i++) + distribute_extra_depth (category->subs[i], extra_depth); + else + category->extra_depth += extra_depth; +} + +static void +pivot_category_assign_label_depth (struct pivot_category *category, + bool dimension_labels_in_corner) +{ + category->extra_depth = 0; + + if (pivot_category_is_group (category)) + { + size_t depth = 0; + for (size_t i = 0; i < category->n_subs; i++) + { + pivot_category_assign_label_depth (category->subs[i], false); + depth = MAX (depth, category->subs[i]->label_depth); + } + + for (size_t i = 0; i < category->n_subs; i++) + { + struct pivot_category *sub = category->subs[i]; + + size_t extra_depth = depth - sub->label_depth; + if (extra_depth) + distribute_extra_depth (sub, extra_depth); + + sub->label_depth = depth; + } + + category->show_label_in_corner = (category->show_label + && dimension_labels_in_corner); + category->label_depth + = (category->show_label && !category->show_label_in_corner + ? depth + 1 : depth); + } + else + category->label_depth = 1; +} + +static bool +pivot_axis_assign_label_depth (struct pivot_table *table, + enum pivot_axis_type axis_type, + bool dimension_labels_in_corner) +{ + struct pivot_axis *axis = &table->axes[axis_type]; + bool any_label_shown_in_corner = false; + axis->label_depth = 0; + axis->extent = 1; + for (size_t i = 0; i < axis->n_dimensions; i++) + { + struct pivot_dimension *d = axis->dimensions[i]; + pivot_category_assign_label_depth (d->root, dimension_labels_in_corner); + d->label_depth = d->hide_all_labels ? 0 : d->root->label_depth; + axis->label_depth += d->label_depth; + axis->extent *= d->n_leaves; + + if (d->root->show_label_in_corner) + any_label_shown_in_corner = true; + } + return any_label_shown_in_corner; +} + +void +pivot_table_assign_label_depth (struct pivot_table *table) +{ + pivot_axis_assign_label_depth (table, PIVOT_AXIS_COLUMN, false); + if (pivot_axis_assign_label_depth ( + table, PIVOT_AXIS_ROW, (table->row_labels_in_corner + && !table->corner_text)) + && table->axes[PIVOT_AXIS_COLUMN].label_depth == 0) + table->axes[PIVOT_AXIS_COLUMN].label_depth = 1; + pivot_axis_assign_label_depth (table, PIVOT_AXIS_LAYER, false); +} + +/* Footnotes. */ + + + +static void +indent (int indentation) +{ + for (int i = 0; i < indentation * 2; i++) + putchar (' '); +} + +static void +pivot_value_dump (const struct pivot_value *value) +{ + char *s = pivot_value_to_string (value, SETTINGS_VALUE_SHOW_DEFAULT, + SETTINGS_VALUE_SHOW_DEFAULT); + fputs (s, stdout); + free (s); +} + +static void +pivot_table_dump_value (const struct pivot_value *value, const char *name, + int indentation) +{ + if (value) + { + indent (indentation); + printf ("%s: ", name); + pivot_value_dump (value); + putchar ('\n'); + } +} + +static void +pivot_table_dump_string (const char *string, const char *name, int indentation) +{ + if (string) + { + indent (indentation); + printf ("%s: %s\n", name, string); + } +} + +static void +pivot_category_dump (const struct pivot_category *c, int indentation) +{ + indent (indentation); + printf ("%s \"", pivot_category_is_leaf (c) ? "leaf" : "group"); + pivot_value_dump (c->name); + printf ("\" "); + + if (pivot_category_is_leaf (c)) + printf ("data_index=%zu\n", c->data_index); + else + { + printf (" (label %s)", c->show_label ? "shown" : "hidden"); + printf ("\n"); + + for (size_t i = 0; i < c->n_subs; i++) + pivot_category_dump (c->subs[i], indentation + 1); + } +} + +void +pivot_dimension_dump (const struct pivot_dimension *d, int indentation) +{ + indent (indentation); + printf ("%s dimension %zu (where 0=innermost), label_depth=%zu:\n", + pivot_axis_type_to_string (d->axis_type), d->level, d->label_depth); + + pivot_category_dump (d->root, indentation + 1); +} + +static void +area_style_dump (enum pivot_area area, const struct area_style *a, + int indentation) +{ + indent (indentation); + printf ("%s: ", pivot_area_to_string (area)); + font_style_dump (&a->font_style); + putchar (' '); + cell_style_dump (&a->cell_style); + putchar ('\n'); +} + +static void +table_border_style_dump (enum pivot_border border, + const struct table_border_style *b, int indentation) +{ + indent (indentation); + printf ("%s: %s ", pivot_border_to_string (border), + table_stroke_to_string (b->stroke)); + cell_color_dump (&b->color); + putchar ('\n'); +} + +static char *** +compose_headings (const struct pivot_axis *axis, + const size_t *column_enumeration, + enum settings_value_show show_values, + enum settings_value_show show_variables) +{ + if (!axis->n_dimensions || !axis->extent || !axis->label_depth) + return NULL; + + char ***headings = xnmalloc (axis->label_depth, sizeof *headings); + for (size_t i = 0; i < axis->label_depth; i++) + headings[i] = xcalloc (axis->extent, sizeof **headings); + + const size_t *indexes; + size_t column = 0; + PIVOT_ENUMERATION_FOR_EACH (indexes, column_enumeration, axis) + { + int row = axis->label_depth - 1; + for (int dim_index = 0; dim_index < axis->n_dimensions; dim_index++) + { + const struct pivot_dimension *d = axis->dimensions[dim_index]; + if (d->hide_all_labels) + continue; + for (const struct pivot_category *c + = d->presentation_leaves[indexes[dim_index]]; + c; + c = c->parent) + { + if (pivot_category_is_leaf (c) || (c->show_label + && !c->show_label_in_corner)) + { + headings[row][column] = pivot_value_to_string ( + c->name, show_values, show_variables); + if (!*headings[row][column]) + headings[row][column] = xstrdup (""); + row--; + } + } + } + column++; + } + + return headings; +} + +void +pivot_table_dump (const struct pivot_table *table, int indentation) +{ + if (!table) + return; + + int old_decimal = settings_get_decimal_char (FMT_COMMA); + if (table->decimal == '.' || table->decimal == ',') + settings_set_decimal_char (table->decimal); + + pivot_table_dump_value (table->title, "title", indentation); + pivot_table_dump_string (table->command_c, "command", indentation); + pivot_table_dump_string (table->dataset, "dataset", indentation); + pivot_table_dump_string (table->datafile, "datafile", indentation); + pivot_table_dump_string (table->notes, "notes", indentation); + pivot_table_dump_string (table->table_look, "table-look", indentation); + if (table->date) + { + indent (indentation); + printf ("date: %s", ctime (&table->date)); /* XXX thread unsafe */ + } + + indent (indentation); + printf ("areas:\n"); + for (enum pivot_area area = 0; area < PIVOT_N_AREAS; area++) + area_style_dump (area, &table->areas[area], indentation + 1); + + indent (indentation); + printf ("borders:\n"); + for (enum pivot_border border = 0; border < PIVOT_N_BORDERS; border++) + table_border_style_dump (border, &table->borders[border], indentation + 1); + + for (size_t i = 0; i < table->n_dimensions; i++) + pivot_dimension_dump (table->dimensions[i], indentation); + + /* Presentation and data indexes. */ + size_t *dindexes = xcalloc (table->n_dimensions, sizeof *dindexes); + + const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER]; + if (layer_axis->n_dimensions) + { + indent (indentation); + printf ("current layer:"); + + for (size_t i = 0; i < layer_axis->n_dimensions; i++) + { + const struct pivot_dimension *d = layer_axis->dimensions[i]; + char *name = pivot_value_to_string (d->root->name, + table->show_values, + table->show_variables); + char *value = pivot_value_to_string ( + d->data_leaves[table->current_layer[i]]->name, + table->show_values, table->show_variables); + printf (" %s=%s", name, value); + free (value); + free (name); + } + + putchar ('\n'); + } + + size_t *layer_indexes; + size_t layer_iteration = 0; + PIVOT_AXIS_FOR_EACH (layer_indexes, &table->axes[PIVOT_AXIS_LAYER]) + { + indent (indentation); + printf ("layer %zu:", layer_iteration++); + + const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER]; + for (size_t i = 0; i < layer_axis->n_dimensions; i++) + { + const struct pivot_dimension *d = layer_axis->dimensions[i]; + + fputs (i == 0 ? " " : ", ", stdout); + pivot_value_dump (d->root->name); + fputs (" =", stdout); + + struct pivot_value **names = xnmalloc (layer_axis->label_depth, + sizeof *names); + size_t n_names = 0; + for (const struct pivot_category *c + = d->presentation_leaves[layer_indexes[i]]; + c; + c = c->parent) + { + if (pivot_category_is_leaf (c) || c->show_label) + names[n_names++] = c->name; + } + + for (size_t i = n_names; i-- > 0; ) + { + putchar (' '); + pivot_value_dump (names[i]); + } + free (names); + } + putchar ('\n'); + + size_t *column_enumeration = pivot_table_enumerate_axis ( + table, PIVOT_AXIS_COLUMN, layer_indexes, table->omit_empty, NULL); + size_t *row_enumeration = pivot_table_enumerate_axis ( + table, PIVOT_AXIS_ROW, layer_indexes, table->omit_empty, NULL); + + char ***column_headings = compose_headings ( + &table->axes[PIVOT_AXIS_COLUMN], column_enumeration, + table->show_values, table->show_variables); + for (size_t y = 0; y < table->axes[PIVOT_AXIS_COLUMN].label_depth; y++) + { + indent (indentation + 1); + for (size_t x = 0; x < table->axes[PIVOT_AXIS_COLUMN].extent; x++) + { + if (x) + fputs ("; ", stdout); + if (column_headings[y][x]) + fputs (column_headings[y][x], stdout); + } + putchar ('\n'); + } + + indent (indentation + 1); + printf ("-----------------------------------------------\n"); + + char ***row_headings = compose_headings ( + &table->axes[PIVOT_AXIS_ROW], row_enumeration, + table->show_values, table->show_variables); + + size_t x = 0; + const size_t *pindexes[PIVOT_N_AXES] + = { [PIVOT_AXIS_LAYER] = layer_indexes }; + PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_ROW], row_enumeration, + &table->axes[PIVOT_AXIS_ROW]) + { + indent (indentation + 1); + + size_t i = 0; + for (size_t y = 0; y < table->axes[PIVOT_AXIS_ROW].label_depth; y++) + { + if (i++) + fputs ("; ", stdout); + if (row_headings[y][x]) + fputs (row_headings[y][x], stdout); + } + + printf (" | "); + + i = 0; + PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_COLUMN], + column_enumeration, + &table->axes[PIVOT_AXIS_COLUMN]) + { + if (i++) + printf ("; "); + + pivot_table_convert_indexes_ptod (table, pindexes, dindexes); + const struct pivot_value *value = pivot_table_get ( + table, dindexes); + if (value) + pivot_value_dump (value); + } + printf ("\n"); + + x++; + } + + free (column_enumeration); + free (row_enumeration); + } + + pivot_table_dump_value (table->caption, "caption", indentation); + + for (size_t i = 0; i < table->n_footnotes; i++) + { + const struct pivot_footnote *f = table->footnotes[i]; + indent (indentation); + putchar ('['); + if (f->marker) + pivot_value_dump (f->marker); + else + printf ("%d", f->idx); + putchar (']'); + pivot_value_dump (f->content); + putchar ('\n'); + } + + settings_set_decimal_char (old_decimal); +} + +static const char * +consume_int (const char *p, size_t *n) +{ + *n = 0; + while (c_isdigit (*p)) + *n = *n * 10 + (*p++ - '0'); + return p; +} + +static size_t +pivot_format_inner_template (struct string *out, const char *template, + char escape, + struct pivot_value **values, size_t n_values, + enum settings_value_show show_values, + enum settings_value_show show_variables) +{ + size_t args_consumed = 0; + while (*template && *template != ':') + { + if (*template == '\\' && template[1]) + { + ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]); + template += 2; + } + else if (*template == escape) + { + size_t index; + template = consume_int (template + 1, &index); + if (index >= 1 && index <= n_values) + { + pivot_value_format (values[index - 1], show_values, + show_variables, out); + args_consumed = MAX (args_consumed, index); + } + } + else + ds_put_byte (out, *template++); + } + return args_consumed; +} + +static const char * +pivot_extract_inner_template (const char *template, const char **p) +{ + *p = template; + + for (;;) + { + if (*template == '\\' && template[1] != '\0') + template += 2; + else if (*template == ':') + return template + 1; + else if (*template == '\0') + return template; + else + template++; + } +} + +static void +pivot_format_template (struct string *out, const char *template, + const struct pivot_argument *args, size_t n_args, + enum settings_value_show show_values, + enum settings_value_show show_variables) +{ + while (*template) + { + if (*template == '\\' && template[1] != '\0') + { + ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]); + template += 2; + } + else if (*template == '^') + { + size_t index; + template = consume_int (template + 1, &index); + if (index >= 1 && index <= n_args && args[index - 1].n > 0) + pivot_value_format (args[index - 1].values[0], + show_values, show_variables, out); + } + else if (*template == '[') + { + const char *tmpl[2]; + template = pivot_extract_inner_template (template + 1, &tmpl[0]); + template = pivot_extract_inner_template (template, &tmpl[1]); + template += *template == ']'; + + size_t index; + template = consume_int (template, &index); + if (index < 1 || index > n_args) + continue; + + const struct pivot_argument *arg = &args[index - 1]; + size_t left = arg->n; + while (left) + { + struct pivot_value **values = arg->values + (arg->n - left); + int tmpl_idx = left == arg->n && *tmpl[0] != ':' ? 0 : 1; + char escape = "%^"[tmpl_idx]; + size_t used = pivot_format_inner_template ( + out, tmpl[tmpl_idx], escape, values, left, + show_values, show_variables); + if (!used || used > left) + break; + left -= used; + } + } + else + ds_put_byte (out, *template++); + } +} + +static enum settings_value_show +interpret_show (enum settings_value_show global_show, + enum settings_value_show table_show, + enum settings_value_show value_show, + bool has_label) +{ + return (!has_label ? SETTINGS_VALUE_SHOW_VALUE + : value_show != SETTINGS_VALUE_SHOW_DEFAULT ? value_show + : table_show != SETTINGS_VALUE_SHOW_DEFAULT ? table_show + : global_show); +} + +/* Appends a text representation of the body of VALUE to OUT. SHOW_VALUES and + SHOW_VARIABLES control whether variable and value labels are included. + + The "body" omits subscripts and superscripts and footnotes. */ +bool +pivot_value_format_body (const struct pivot_value *value, + enum settings_value_show show_values, + enum settings_value_show show_variables, + struct string *out) +{ + enum settings_value_show show; + bool numeric = false; + + switch (value->type) + { + case PIVOT_VALUE_NUMERIC: + show = interpret_show (settings_get_show_values (), + show_values, + value->numeric.show, + value->numeric.value_label != NULL); + if (show & SETTINGS_VALUE_SHOW_VALUE) + { + char *s = data_out (&(union value) { .f = value->numeric.x }, + "UTF-8", &value->numeric.format); + ds_put_cstr (out, s + strspn (s, " ")); + free (s); + } + if (show & SETTINGS_VALUE_SHOW_LABEL) + { + if (show & SETTINGS_VALUE_SHOW_VALUE) + ds_put_byte (out, ' '); + ds_put_cstr (out, value->numeric.value_label); + } + numeric = !(show & SETTINGS_VALUE_SHOW_LABEL); + break; + + case PIVOT_VALUE_STRING: + show = interpret_show (settings_get_show_values (), + show_values, + value->string.show, + value->string.value_label != NULL); + if (show & SETTINGS_VALUE_SHOW_VALUE) + { + if (value->string.hex) + { + for (const uint8_t *p = CHAR_CAST (uint8_t *, value->string.s); + *p; p++) + ds_put_format (out, "%02X", *p); + } + else + ds_put_cstr (out, value->string.s); + } + if (show & SETTINGS_VALUE_SHOW_LABEL) + { + if (show & SETTINGS_VALUE_SHOW_VALUE) + ds_put_byte (out, ' '); + ds_put_cstr (out, value->string.value_label); + } + break; + + case PIVOT_VALUE_VARIABLE: + show = interpret_show (settings_get_show_variables (), + show_variables, + value->variable.show, + value->variable.var_label != NULL); + if (show & SETTINGS_VALUE_SHOW_VALUE) + ds_put_cstr (out, value->variable.var_name); + if (show & SETTINGS_VALUE_SHOW_LABEL) + { + if (show & SETTINGS_VALUE_SHOW_VALUE) + ds_put_byte (out, ' '); + ds_put_cstr (out, value->variable.var_label); + } + break; + + case PIVOT_VALUE_TEXT: + ds_put_cstr (out, value->text.local); + break; + + case PIVOT_VALUE_TEMPLATE: + pivot_format_template (out, value->template.s, value->template.args, + value->template.n_args, show_values, + show_variables); + break; + } + + return numeric; +} + +/* Appends a text representation of VALUE to OUT. SHOW_VALUES and + SHOW_VARIABLES control whether variable and value labels are included. + + Subscripts and superscripts and footnotes are included. */ +void +pivot_value_format (const struct pivot_value *value, + enum settings_value_show show_values, + enum settings_value_show show_variables, + struct string *out) +{ + pivot_value_format_body ( value, show_values, show_variables, out); + + if (value->subscript) + ds_put_format (out, "_%s", value->subscript); + + if (value->superscript) + ds_put_format (out, "^%s", value->superscript); + + for (size_t i = 0; i < value->n_footnotes; i++) + { + ds_put_byte (out, '^'); + pivot_value_format (value->footnotes[i]->marker, + show_values, show_variables, out); + } +} + +/* Returns a text representation of VALUE. The caller must free the string, + with free(). */ +char * +pivot_value_to_string (const struct pivot_value *value, + enum settings_value_show show_values, + enum settings_value_show show_variables) +{ + struct string s = DS_EMPTY_INITIALIZER; + pivot_value_format (value, show_values, show_variables, &s); + return ds_steal_cstr (&s); +} + +/* Frees the data owned by V. */ +void +pivot_value_destroy (struct pivot_value *value) +{ + if (value) + { + font_style_uninit (value->font_style); + free (value->font_style); + free (value->cell_style); + for (size_t i = 0; i < value->n_footnotes; i++) + pivot_footnote_destroy (value->footnotes[i]); + free (value->footnotes); + + switch (value->type) + { + case PIVOT_VALUE_NUMERIC: + free (value->numeric.var_name); + free (value->numeric.value_label); + break; + + case SETTINGS_VALUE_SHOW_VALUE: + free (value->string.var_name); + free (value->string.value_label); + break; + + case PIVOT_VALUE_VARIABLE: + free (value->variable.var_name); + free (value->variable.var_label); + break; + + case PIVOT_VALUE_TEXT: + free (value->text.local); + if (value->text.c != value->text.local) + free (value->text.c); + if (value->text.id != value->text.local + && value->text.id != value->text.c) + free (value->text.id); + break; + + case PIVOT_VALUE_TEMPLATE: + free (value->template.s); + for (size_t i = 0; i < value->template.n_args; i++) + pivot_argument_uninit (&value->template.args[i]); + free (value->template.args); + break; + } + free (value); + } +} + +/* Sets AREA to the style to use for VALUE, with defaults coming from + DEFAULT_STYLE for the parts of the style that VALUE doesn't override. */ +void +pivot_value_get_style (struct pivot_value *value, + const struct area_style *default_style, + struct area_style *area) +{ + font_style_copy (&area->font_style, (value->font_style + ? value->font_style + : &default_style->font_style)); + area->cell_style = (value->cell_style + ? *value->cell_style + : default_style->cell_style); +} + +/* Copies AREA into VALUE's style. */ +void +pivot_value_set_style (struct pivot_value *value, + const struct area_style *area) +{ + if (value->font_style) + font_style_uninit (value->font_style); + else + value->font_style = xmalloc (sizeof *value->font_style); + font_style_copy (value->font_style, &area->font_style); + + if (!value->cell_style) + value->cell_style = xmalloc (sizeof *value->cell_style); + *value->cell_style = area->cell_style; +} + +/* Frees the data owned by ARG (but not ARG itself). */ +void +pivot_argument_uninit (struct pivot_argument *arg) +{ + if (arg) + { + for (size_t i = 0; i < arg->n; i++) + pivot_value_destroy (arg->values[i]); + free (arg->values); + } +} + +struct pivot_value * +pivot_value_new_user_text_nocopy (char *text) +{ + struct pivot_value *value = xmalloc (sizeof *value); + *value = (struct pivot_value) { + .type = PIVOT_VALUE_TEXT, + .text = { + .local = text, + .c = text, + .id = text, + .user_provided = true, + } + }; + return value; +} + +struct pivot_value * +pivot_value_new_user_text (const char *text, size_t length) +{ + return pivot_value_new_user_text_nocopy ( + xmemdup0 (text, length != SIZE_MAX ? length : strlen (text))); +} + +/* TEXT should be a translatable string, but not actually translated yet, + e.g. enclosed in N_(). */ +struct pivot_value * +pivot_value_new_text (const char *text) +{ + char *c = xstrdup (text); + char *local = xstrdup (gettext (c)); + + struct pivot_value *value = xmalloc (sizeof *value); + *value = (struct pivot_value) { + .type = PIVOT_VALUE_TEXT, + .text = { + .local = local, + .c = c, + .id = c, + .user_provided = false, + } + }; + return value; +} + +/* FORMAT should be a translatable string, but not actually translated yet, + e.g. enclosed in N_(). */ +struct pivot_value * PRINTF_FORMAT (1, 2) +pivot_value_new_text_format (const char *format, ...) +{ + va_list args; + va_start (args, format); + char *c = xvasprintf (format, args); + va_end (args); + + va_start (args, format); + char *local = xvasprintf (gettext (format), args); + va_end (args); + + struct pivot_value *value = xmalloc (sizeof *value); + *value = (struct pivot_value) { + .type = PIVOT_VALUE_TEXT, + .text = { + .local = local, + .c = c, + .id = xstrdup (c), + .user_provided = false, + } + }; + return value; +} + +static char * +xstrdup_if_nonempty (const char *s) +{ + return s && s[0] ? xstrdup (s) : NULL; +} + +/* Returns a new pivot_value that represents X. + + The format to use for X is unspecified. Usually the easiest way to specify + a format is through assigning a result class to one of the categories that + the pivot_value will end up in. If that is not suitable, then the caller + can use pivot_value_set_rc() or assign directly to value->numeric.format. */ +struct pivot_value * +pivot_value_new_number (double x) +{ + struct pivot_value *value = xmalloc (sizeof *value); + *value = (struct pivot_value) { + .type = PIVOT_VALUE_NUMERIC, + .numeric = { .x = x, }, + }; + return value; +} + +/* Returns a new pivot_value that represents X, formatted as an integer. */ +struct pivot_value * +pivot_value_new_integer (double x) +{ + struct pivot_value *value = pivot_value_new_number (x); + value->numeric.format = (struct fmt_spec) { FMT_F, 40, 0 }; + return value; +} + +/* Returns a new pivot_value that represents VALUE, formatted as for + VARIABLE. */ +struct pivot_value * +pivot_value_new_var_value (const struct variable *variable, + const union value *value) +{ + struct pivot_value *pv = pivot_value_new_value ( + value, var_get_width (variable), var_get_print_format (variable), + var_get_encoding (variable)); + + char *var_name = xstrdup (var_get_name (variable)); + if (var_is_alpha (variable)) + pv->string.var_name = var_name; + else + pv->numeric.var_name = var_name; + + const char *label = var_lookup_value_label (variable, value); + if (label) + { + if (var_is_alpha (variable)) + pv->string.value_label = xstrdup (label); + else + pv->numeric.value_label = xstrdup (label); + } + + return pv; +} + +/* Returns a new pivot_value that represents VALUE, with the given WIDTH, + formatted with FORMAT. For a string value, ENCODING must be its character + encoding. */ +struct pivot_value * +pivot_value_new_value (const union value *value, int width, + const struct fmt_spec *format, const char *encoding) +{ + struct pivot_value *pv = xzalloc (sizeof *pv); + if (width > 0) + { + char *s = recode_string (UTF8, encoding, + CHAR_CAST (char *, value_str (value, width)), + width); + size_t n = strlen (s); + while (n > 0 && s[n - 1] == ' ') + s[--n] = '\0'; + + pv->type = PIVOT_VALUE_STRING; + pv->string.s = s; + pv->string.hex = format->type == FMT_AHEX; + } + else + { + pv->type = PIVOT_VALUE_NUMERIC; + pv->numeric.x = value->f; + pv->numeric.format = *format; + } + + return pv; +} + +/* Returns a new pivot_value for VARIABLE. */ +struct pivot_value * +pivot_value_new_variable (const struct variable *variable) +{ + struct pivot_value *value = xmalloc (sizeof *value); + *value = (struct pivot_value) { + .type = PIVOT_VALUE_VARIABLE, + .variable = { + .var_name = xstrdup (var_get_name (variable)), + .var_label = xstrdup_if_nonempty (var_get_label (variable)), + }, + }; + return value; +} + +/* Attaches a reference to FOOTNOTE to V. */ +void +pivot_value_add_footnote (struct pivot_value *v, + struct pivot_footnote *footnote) +{ + v->footnotes = xrealloc (v->footnotes, + (v->n_footnotes + 1) * sizeof *v->footnotes); + v->footnotes[v->n_footnotes++] = footnote; +} + +/* If VALUE is a numeric value, and RC is a result class such as + PIVOT_RC_COUNT, changes VALUE's format to the result class's. */ +void +pivot_value_set_rc (struct pivot_table *table, struct pivot_value *value, + const char *rc) +{ + if (value->type == PIVOT_VALUE_NUMERIC) + { + const struct fmt_spec *f = pivot_table_get_format (table, rc); + if (f) + value->numeric.format = *f; + } +} + diff --git a/src/output/pivot-table.h b/src/output/pivot-table.h new file mode 100644 index 0000000000..474b3acde2 --- /dev/null +++ b/src/output/pivot-table.h @@ -0,0 +1,703 @@ +/* PSPP - a program for statistical analysis. + Copyright (C) 2017-2018 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#ifndef OUTPUT_PIVOT_TABLE_H +#define OUTPUT_PIVOT_TABLE_H 1 + +#include +#include +#include "data/format.h" +#include "data/settings.h" +#include "libpspp/compiler.h" +#include "libpspp/hmap.h" +#include "output/table.h" + +struct pivot_value; +struct variable; +union value; + +/* Pivot tables. + + Pivot tables are PSPP's primary form of output. They are analogous to the + pivot tables you might be familiar with from spreadsheets and databases. + See https://en.wikipedia.org/wiki/Pivot_table for a brief introduction to + the overall concept of a pivot table. + + In PSPP, the most important internal pieces of a pivot table are: + + - Title. Every pivot table has a title that is displayed above it. It also + has an optional caption (displayed below it) and corner text (displayed in + the upper left corner). + + - Dimensions. A dimension consists of zero or more categories. A category + has a label, such as "df" or "Asymp. Sig." or 123 or a variable name. The + categories are the leaves of a tree whose non-leaf nodes form groups of + categories. The tree always has a root group whose label is the name of + the dimension. + + - Axes. A table has three axes: column, row, and layer. Each dimension is + assigned to an axis, and each axis has zero or more dimensions. When an + axis has more than one dimension, they are ordered from innermost to + outermost. + + - Data. A table's data consists of zero or more cells. Each cell maps from + a category for each dimension to a value, which is commonly a number but + could also be a variable name or an arbitrary text string. + + Creating a pivot table usually consists of the following steps: + + 1. Create the table with pivot_table_create(), passing in the title. + + 2. Create each dimension with pivot_dimension_create() and populate it with + categories and, possibly, with groups that contain the categories. This + call also assigns the dimension to an axis. + + In simple cases, only a call to pivot_dimension_create() is needed. + Other functions such as pivot__create_group() can be used for + hierarchies of categories. + + Sometimes it's easier to create categories in tandem with inserting data, + for example by adding a category for a variable just before inserting the + first cell for that variable. In that case, creating categories and + inserting data can be interleaved. + + 3. Insert data. For each cell, supply the category indexes, which are + assigned starting from 0 in the order in which the categories were + created in step 2, and the value to go in the cell. If the table has a + small, fixed number of dimensions, functions like, e.g. + pivot_table_put3() for 3 dimensions, can be used. The general function + pivot_table_put() works for other cases. + + 4. Output the table for user consumption. Use pivot_table_submit(). */ + +/* Pivot table display styling. */ + +/* Areas of a pivot table for styling purposes. */ +enum pivot_area + { + PIVOT_AREA_TITLE, + PIVOT_AREA_CAPTION, + PIVOT_AREA_FOOTER, /* Footnotes. */ + PIVOT_AREA_CORNER, /* Top-left corner. */ + PIVOT_AREA_COLUMN_LABELS, + PIVOT_AREA_ROW_LABELS, + PIVOT_AREA_DATA, + PIVOT_AREA_LAYERS, /* Layer indication. */ + PIVOT_N_AREAS + }; + +const char *pivot_area_to_string (enum pivot_area); + +/* Table borders for styling purposes. */ +enum pivot_border + { + PIVOT_BORDER_TITLE, + + /* Outer frame. */ + PIVOT_BORDER_OUTER_LEFT, + PIVOT_BORDER_OUTER_TOP, + PIVOT_BORDER_OUTER_RIGHT, + PIVOT_BORDER_OUTER_BOTTOM, + + /* Inner frame. */ + PIVOT_BORDER_INNER_LEFT, + PIVOT_BORDER_INNER_TOP, + PIVOT_BORDER_INNER_RIGHT, + PIVOT_BORDER_INNER_BOTTOM, + + /* Data area. */ + PIVOT_BORDER_DATA_LEFT, + PIVOT_BORDER_DATA_TOP, + + /* Dimensions. */ + PIVOT_BORDER_DIM_ROW_HORZ, + PIVOT_BORDER_DIM_ROW_VERT, + PIVOT_BORDER_DIM_COL_HORZ, + PIVOT_BORDER_DIM_COL_VERT, + + /* Categories. */ + PIVOT_BORDER_CAT_ROW_HORZ, + PIVOT_BORDER_CAT_ROW_VERT, + PIVOT_BORDER_CAT_COL_HORZ, + PIVOT_BORDER_CAT_COL_VERT, + + PIVOT_N_BORDERS + }; + +const char *pivot_border_to_string (enum pivot_border); + +/* Sizing for rows or columns of a rendered table. The comments below talk + about columns and their widths but they apply equally to rows and their + heights. */ +struct pivot_table_sizing + { + /* Minimum and maximum column width, in 1/96" units. */ + int range[2]; + + /* Specific column widths, in 1/96" units. */ + int *widths; + size_t n_widths; + + /* Specific page breaks: 0-based columns after which a page break must + occur, e.g. a value of 1 requests a break after the second column. */ + size_t *breaks; + size_t n_breaks; + + /* Keeps: columns to keep together on a page if possible. */ + struct pivot_keep *keeps; + size_t n_keeps; + }; + +void pivot_table_sizing_uninit (struct pivot_table_sizing *); + +/* A set of columns to keep together on a page if possible, e.g. ofs=1, n=10 + requests keeping together the 2nd through 11th columns. */ +struct pivot_keep + { + size_t ofs; /* 0-based first column. */ + size_t n; /* Number of columns. */ + }; + +/* Axes. */ + +enum pivot_axis_type + { + PIVOT_AXIS_LAYER, + PIVOT_AXIS_ROW, + PIVOT_AXIS_COLUMN, + + PIVOT_N_AXES + }; + +const char *pivot_axis_type_to_string (enum pivot_axis_type); + +/* An axis within a pivot table. */ +struct pivot_axis + { + /* dimensions[0] is the innermost dimension, + dimensions[1] is the next outer dimension, + ... + dimensions[n_dimensions - 1] is the outermost dimension. */ + struct pivot_dimension **dimensions; + size_t n_dimensions; + + /* The number of rows or columns along the axis, + that is, the product of dimension[*]->n_leaves. + It is 0 if any dimension has 0 leaves. */ + size_t extent; + + /* Sum of dimensions[*]->label_depth. */ + size_t label_depth; + }; + +/* Successively assigns to INDEXES (which should be a "size_t *") each of the + combinations of the categories in AXIS's dimensions, in lexicographic order + with the innermost dimension iterating most quickly. + + The value assigned to INDEXES is dynamically allocated. If the client + breaks out of the loop prematurely, it needs to free it with free(). */ +#define PIVOT_AXIS_FOR_EACH(INDEXES, AXIS) \ + for ((INDEXES) = NULL; \ + ((INDEXES) = pivot_axis_iterator_next (INDEXES, AXIS)) != NULL; ) +size_t *pivot_axis_iterator_next (size_t *indexes, const struct pivot_axis *); + +/* Dimensions. + + A pivot_dimension identifies the categories associated with a single + dimension within a multidimensional pivot table. + + A dimension contains a collection of categories, which are the leaves in a + tree of groups. + + (A dimension or a group can contain zero categories, but this is unusual. + If a dimension contains no categories, then its table cannot contain any + data.) +*/ +struct pivot_dimension + { + /* table->axes[axis_type]->dimensions[level] == dimension. */ + struct pivot_table *table; + enum pivot_axis_type axis_type; + size_t level; /* 0 for innermost dimension within axis. */ + + /* table->dimensions[top_index] == dimension. */ + size_t top_index; + + /* Hierarchy of categories within the dimension. The groups and categories + are sorted in the order that should be used for display. This might be + different from the original order produced for output if the user + adjusted it. + + The root must always be a group, although it is allowed to have no + subcategories. */ + struct pivot_category *root; + + /* All of the leaves reachable via the root. + + The indexing for presentation_leaves is presentation order, thus + presentation_leaves[i]->presentation_index == i. This order is the same + as would be produced by an in-order traversal of the groups. It is the + order into which the user reordered or sorted the categories. + + The indexing for data_leaves is that used for idx[] in struct + pivot_cell, thus data_leaves[i]->data_index == i. This might differ + from what an in-order traversal of 'root' would yield, if the user + reordered categories. */ + struct pivot_category **data_leaves; + struct pivot_category **presentation_leaves; + size_t n_leaves, allocated_leaves; + + /* Display. */ + bool hide_all_labels; + + /* Number of rows or columns needed to express the labels. */ + int label_depth; + }; + +struct pivot_dimension *pivot_dimension_create ( + struct pivot_table *, enum pivot_axis_type, const char *name, ...) + SENTINEL (0); +#define pivot_dimension_create(...) \ + pivot_dimension_create(__VA_ARGS__, NULL_SENTINEL) +struct pivot_dimension *pivot_dimension_create__ (struct pivot_table *, + enum pivot_axis_type, + struct pivot_value *name); + +void pivot_dimension_destroy (struct pivot_dimension *); + +void pivot_dimension_dump (const struct pivot_dimension *, int indentation); + +/* A pivot_category is a leaf (a category) or a group: + + - For a leaf, neither index is SIZE_MAX. + + - For a group, both indexes are SIZE_MAX. + + Do not use 'subs' or 'n_subs' to determine whether a category is a group, + because a group may (pathologically) have no leaves. */ +struct pivot_category + { + struct pivot_value *name; + struct pivot_category *parent; + struct pivot_dimension *dimension; + size_t label_depth, extra_depth; + + /* Groups only. + + If show_label is true, then the group itself has a row (or a column) + giving the group's name. Otherwise, the group's own name is not + displayed. */ + struct pivot_category **subs; /* Child categories or groups. */ + size_t n_subs, allocated_subs; + bool show_label; /* Display a label for the group itself? */ + bool show_label_in_corner; + + /* Leaf only. */ + struct fmt_spec format; + size_t group_index; /* In ->parent->subs[]. */ + size_t data_index; /* In ->dimension->data_leaves[]. */ + size_t presentation_index; /* In ->dimension->presentation_leaves[]. */ + }; + +static inline bool +pivot_category_is_group (const struct pivot_category *category) +{ + return category->data_index == SIZE_MAX; +} + +static inline bool +pivot_category_is_leaf (const struct pivot_category *category) +{ + return !pivot_category_is_group (category); +} + +/* Creating leaf categories. */ +int pivot_category_create_leaves (struct pivot_category *parent, ...) + SENTINEL (0); +#define pivot_category_create_leaves(...) \ + pivot_category_create_leaves(__VA_ARGS__, NULL_SENTINEL) + +int pivot_category_create_leaf ( + struct pivot_category *parent, struct pivot_value *name); +int pivot_category_create_leaf_rc ( + struct pivot_category *parent, struct pivot_value *name, const char *rc); + +/* Creating category groups. */ +struct pivot_category *pivot_category_create_group ( + struct pivot_category *parent, const char *name, ...) SENTINEL (0); +#define pivot_category_create_group(...) \ + pivot_category_create_group(__VA_ARGS__, NULL_SENTINEL) +struct pivot_category *pivot_category_create_group__ ( + struct pivot_category *parent, struct pivot_value *name); + +void pivot_category_destroy (struct pivot_category *); + +/* Pivot result classes. + + These are used to mark leaf categories as having particular types of data, + to set their numeric formats. The formats that actually get used for these + classes are in the result_classes[] global array in pivot-table.c, except + that PIVOT_RC_OTHER comes from settings_get_format() and PIVOT_RC_COUNT + should come from the weight variable in the dataset's dictionary. */ +#define PIVOT_RC_OTHER ("RC_OTHER") +#define PIVOT_RC_INTEGER ("RC_INTEGER") +#define PIVOT_RC_CORRELATION ("RC_CORRELATIONS") +#define PIVOT_RC_SIGNIFICANCE ("RC_SIGNIFICANCE") +#define PIVOT_RC_PERCENT ("RC_PERCENT") +#define PIVOT_RC_RESIDUAL ("RC_RESIDUAL") +#define PIVOT_RC_COUNT ("RC_COUNT") + +bool pivot_result_class_change (const char *, const struct fmt_spec *); + +/* A pivot table. See the top of this file for more information. */ +struct pivot_table + { + /* Display settings. */ + bool rotate_inner_column_labels; + bool rotate_outer_row_labels; + bool row_labels_in_corner; + bool show_grid_lines; + bool omit_empty; + size_t *current_layer; /* axis[PIVOT_AXIS_LAYER]->n_dimensions elements. */ + char *table_look; + enum settings_value_show show_values; + enum settings_value_show show_variables; + struct fmt_spec weight_format; + + /* Footnote display settings. */ + bool show_numeric_markers; + bool footnote_marker_superscripts; + + /* Column and row sizing and page breaks. + sizing[TABLE_HORZ] is for columns, sizing[TABLE_VERT] is for rows. */ + struct pivot_table_sizing sizing[TABLE_N_AXES]; + + /* Print settings. */ + bool print_all_layers; + bool paginate_layers; + bool shrink_to_fit[TABLE_N_AXES]; + bool top_continuation, bottom_continuation; + char *continuation; + size_t n_orphan_lines; + + /* Format settings. */ + int epoch; + char decimal; /* Usually ',' or '.'. */ + char grouping; /* Usually '.' or ','. */ + char *ccs[5]; /* Custom currency. */ + double small; + + /* Command information. */ + char *command_local; /* May be NULL. */ + char *command_c; /* May be NULL. */ + char *language; /* May be NULL. */ + char *locale; /* May be NULL. */ + + /* Source information. */ + char *dataset; /* May be NULL. */ + char *datafile; /* May be NULL. */ + time_t date; /* May be 0 if unknown. */ + + /* Footnotes. */ + struct pivot_footnote **footnotes; + size_t n_footnotes, allocated_footnotes; + + /* Titles. */ + struct pivot_value *title; + struct pivot_value *subtype; /* Same as pivot_item's subtype. */ + struct pivot_value *corner_text; + struct pivot_value *caption; + char *notes; + + /* Styles. */ + struct area_style areas[PIVOT_N_AREAS]; + struct table_border_style borders[PIVOT_N_BORDERS]; + + /* Dimensions. */ + struct pivot_dimension **dimensions; + size_t n_dimensions; + + /* Allocation of dimensions to rows, columns, and layers. */ + struct pivot_axis axes[PIVOT_N_AXES]; + + struct hmap cells; /* Contains "struct pivot_cell"s. */ + }; + +/* Creating and destroy pivot tables. */ +struct pivot_table *pivot_table_create (const char *title); +struct pivot_table *pivot_table_create__ (struct pivot_value *title); +struct pivot_table *pivot_table_create_for_text (struct pivot_value *title, + struct pivot_value *content); +void pivot_table_destroy (struct pivot_table *); + +/* Format of PIVOT_RC_COUNT cells. */ +void pivot_table_set_weight_var (struct pivot_table *, + const struct variable *); +void pivot_table_set_weight_format (struct pivot_table *, + const struct fmt_spec *); + +/* Query. */ +bool pivot_table_is_empty (const struct pivot_table *); + +/* Output. */ +void pivot_table_submit (const struct pivot_table *); + +/* Data cells. */ +void pivot_table_put (struct pivot_table *, const size_t *dindexes, size_t n, + struct pivot_value *); +void pivot_table_put1 (struct pivot_table *, size_t idx1, + struct pivot_value *); +void pivot_table_put2 (struct pivot_table *, size_t idx1, size_t idx2, + struct pivot_value *); +void pivot_table_put3 (struct pivot_table *, size_t idx1, size_t idx2, + size_t idx3, struct pivot_value *); +void pivot_table_put4 (struct pivot_table *, size_t idx1, size_t idx2, + size_t idx3, size_t idx4, struct pivot_value *); + +const struct pivot_value *pivot_table_get (const struct pivot_table *, + const size_t *dindexes); + +struct pivot_value *pivot_table_get_rw (struct pivot_table *, + const size_t *dindexes); + +/* Footnotes. + + Use pivot_table_create_footnote() to create a footnote. + Use pivot_value_add_footnote() to add a reference to a footnote. */ +struct pivot_footnote + { + size_t idx; + struct pivot_value *content; + struct pivot_value *marker; + }; + +struct pivot_footnote *pivot_table_create_footnote ( + struct pivot_table *, struct pivot_value *content); +struct pivot_footnote *pivot_table_create_footnote__ ( + struct pivot_table *, size_t idx, + struct pivot_value *marker, struct pivot_value *content); + +void pivot_footnote_destroy (struct pivot_footnote *); + +/* Internals. */ +void pivot_table_convert_indexes_ptod (const struct pivot_table *, + const size_t *pindexes[PIVOT_N_AXES], + size_t *dindexes); +size_t *pivot_table_enumerate_axis (const struct pivot_table *, + enum pivot_axis_type, + const size_t *layer_indexes, + bool omit_empty, size_t *n); +#define PIVOT_ENUMERATION_FOR_EACH(INDEXES, ENUMERATION, AXIS) \ + for ((INDEXES) = (ENUMERATION); *(INDEXES) != SIZE_MAX; \ + (INDEXES) += MAX (1, (AXIS)->n_dimensions)) + +void pivot_table_assign_label_depth (struct pivot_table *); + +void pivot_table_dump (const struct pivot_table *, int indentation); + +/* pivot_value. */ + +enum pivot_value_type + { + PIVOT_VALUE_NUMERIC, /* A value of a numeric variable. */ + PIVOT_VALUE_STRING, /* A value of a string variable. */ + PIVOT_VALUE_VARIABLE, /* Name of a variable. */ + PIVOT_VALUE_TEXT, /* Text. */ + PIVOT_VALUE_TEMPLATE, /* Templated text. */ + }; + +/* A pivot_value is the content of a single pivot table cell. A pivot_value is + also a pivot table's title, caption, footnote marker and contents, and so + on. + + A given pivot_value is one of: + + 1. A number resulting from a calculation (PIVOT_VALUE_NUMERIC). Use + pivot_value_new_number() to create such a pivot_value. + + A numeric pivot_value has an associated display format (usually an F or + PCT format). This format can be set directly on the pivot_value, but + that is not usually the easiest way. Instead, it is usually true that + all of the values in a single category should have the same format + (e.g. all "Significance" values might use format F40.3), so PSPP makes + it easy to set the default format for a category while creating the + category. See pivot_dimension_create() for more details. + + For numbers that should be displayed as integers, + pivot_value_new_integer() can occasionally be a useful special case. + + 2. A numeric or string value obtained from data (PIVOT_VALUE_NUMERIC or + PIVOT_VALUE_STRING). If such a value corresponds to a variable, then the + variable's name can be attached to the pivot_value. If the value has a + value label, then that can also be attached. When a label is present, + the user can control whether to show the value or the label or both. + + Use pivot_value_new_var_value() to create pivot_values of these kinds. + + 3. A variable name (PIVOT_VALUE_VARIABLE). The variable label, if any, can + be attached too, and again the user can control whether to show the value + or the label or both. + + 4. A text string (PIVOT_VALUE_TEXT). The value stores the string in English + and translated into the output language (localized). Use + pivot_value_new_text() or pivot_value_new_text_format() for those cases. + In some cases, only an English or a localized version is available for + one reason or another, although this is regrettable; in those cases, use + pivot_value_new_user_text() or pivot_value_new_user_text_nocopy(). + + (There is also a PIVOT_VALUE_TEMPLATE but PSPP does not yet create these + itself.) + + + Footnotes + ========= + + A pivot_value may reference any number of footnotes. Use + pivot_value_add_footnote() to add a footnote reference. The footnotes being + referenced must first be created with pivot_table_create_footnote(). + + + Styling + ======= + + A pivot_value can have specific font and cell styles. Only the user should + add these. +*/ +struct pivot_value + { + struct font_style *font_style; + struct cell_style *cell_style; + char *subscript; + char *superscript; + + struct pivot_footnote **footnotes; + size_t n_footnotes; + + enum pivot_value_type type; + union + { + /* PIVOT_VALUE_NUMERIC. */ + struct + { + double x; /* The numeric value. */ + struct fmt_spec format; /* Format to display 'x'. */ + char *var_name; /* May be NULL. */ + char *value_label; /* May be NULL. */ + enum settings_value_show show; /* Show value or label or both? */ + } + numeric; + + /* PIVOT_VALUE_STRING. */ + struct + { + char *s; /* The string value. */ + bool hex; /* Display in hex? */ + char *var_name; /* May be NULL. */ + char *value_label; /* May be NULL. */ + enum settings_value_show show; /* Show value or label or both? */ + } + string; + + /* PIVOT_VALUE_VARIABLE. */ + struct + { + char *var_name; + char *var_label; /* May be NULL. */ + enum settings_value_show show; /* Show name or label or both? */ + } + variable; + + /* PIVOT_VALUE_TEXT. */ + struct + { + char *local; /* Localized. */ + char *c; /* English. */ + char *id; /* Identifier. */ + bool user_provided; + } + text; + + /* PIVOT_VALUE_TEMPLATE. */ + struct + { + char *s; + struct pivot_argument *args; + size_t n_args; + } + template; + }; + }; + +/* Numbers resulting from calculations. */ +struct pivot_value *pivot_value_new_number (double); +struct pivot_value *pivot_value_new_integer (double); + +/* Values from data. */ +struct pivot_value *pivot_value_new_var_value ( + const struct variable *, const union value *); +struct pivot_value *pivot_value_new_value (const union value *, int width, + const struct fmt_spec *, + const char *encoding); + +/* Values from variable names. */ +struct pivot_value *pivot_value_new_variable (const struct variable *); + +/* Values from text strings. */ +struct pivot_value *pivot_value_new_text (const char *); +struct pivot_value *pivot_value_new_text_format (const char *, ...) + PRINTF_FORMAT (1, 2); + +struct pivot_value *pivot_value_new_user_text (const char *, size_t length); +struct pivot_value *pivot_value_new_user_text_nocopy (char *); + +/* Footnotes. */ +void pivot_value_add_footnote (struct pivot_value *, struct pivot_footnote *); + +/* Numeric formats. */ +void pivot_value_set_rc (struct pivot_table *, struct pivot_value *, + const char *rc); + +/* Converting a pivot_value to a string for display. */ +char *pivot_value_to_string (const struct pivot_value *, + enum settings_value_show show_values, + enum settings_value_show show_variables); +void pivot_value_format (const struct pivot_value *, + enum settings_value_show show_values, + enum settings_value_show show_variables, + struct string *); +bool pivot_value_format_body (const struct pivot_value *, + enum settings_value_show show_values, + enum settings_value_show show_variables, + struct string *); + +void pivot_value_destroy (struct pivot_value *); + +/* Styling. */ +void pivot_value_get_style (struct pivot_value *, + const struct area_style *default_style, + struct area_style *); +void pivot_value_set_style (struct pivot_value *, const struct area_style *); + +/* Template arguments. */ +struct pivot_argument + { + size_t n; + struct pivot_value **values; + }; + +void pivot_argument_uninit (struct pivot_argument *); + +#endif /* output/pivot-table.h */ diff --git a/src/output/tab.c b/src/output/tab.c index ec00c43222..f6f965022e 100644 --- a/src/output/tab.c +++ b/src/output/tab.c @@ -55,12 +55,7 @@ static const bool debugging = true; struct tab_joined_cell { int d[TABLE_N_AXES][2]; /* Table region, same as struct table_cell. */ - union - { - char *text; - struct table_item *subtable; - } - u; + char *text; size_t n_footnotes; const struct footnote **footnotes; @@ -70,14 +65,6 @@ struct tab_joined_cell static const struct table_class tab_table_class; -struct fmt_spec ugly[n_RC] = { - {FMT_F, 8, 0}, /* INTEGER */ - {FMT_F, 8, 3}, /* WEIGHT (ignored) */ - {FMT_F, 8, 3}, /* PVALUE */ - {FMT_F, 8, 3} /* OTHER (ignored) */ -}; - - /* Creates and returns a new table with NC columns and NR rows and initially no header rows or columns. The table's cells are initially empty. */ struct tab_table * @@ -90,8 +77,6 @@ tab_create (int nc, int nr) table_set_nc (&t->table, nc); table_set_nr (&t->table, nr); - t->title = NULL; - t->caption = NULL; t->cf = nc; t->cc = pool_calloc (t->container, nr * nc, sizeof *t->cc); t->ct = pool_calloc (t->container, nr * nc, sizeof *t->ct); @@ -102,124 +87,13 @@ tab_create (int nc, int nr) t->rv = pool_nmalloc (t->container, nr, nc + 1); memset (t->rv, TAL_0, nr * (nc + 1)); - memset (t->fmtmap, 0, sizeof (*t->fmtmap) * n_RC); - t->fmtmap[RC_PVALUE] = ugly[RC_PVALUE]; - t->fmtmap[RC_INTEGER] = ugly[RC_INTEGER]; - t->fmtmap[RC_OTHER] = *settings_get_format (); - memset (t->styles, 0, sizeof t->styles); memset (t->rule_colors, 0, sizeof t->rule_colors); - t->col_ofs = t->row_ofs = 0; - return t; } -void -tab_set_format (struct tab_table *t, enum result_class rc, - const struct fmt_spec *fmt) -{ - t->fmtmap[rc] = *fmt; -} - - -/* Sets the width and height of a table, in columns and rows, - respectively. Use only to reduce the size of a table, since it - does not change the amount of allocated memory. - - This function is obsolete. Please do not add new uses of it. (Instead, use - table_select() or one of its helper functions.) */ -void -tab_resize (struct tab_table *t, int nc, int nr) -{ - if (nc != -1) - { - assert (nc + t->col_ofs <= t->cf); - table_set_nc (&t->table, nc + t->col_ofs); - } - if (nr != -1) - { - assert (nr + t->row_ofs <= tab_nr (t)); - table_set_nr (&t->table, nr + t->row_ofs); - } -} - -/* Changes either or both dimensions of a table and reallocates memory as - necessary. - - This function is obsolete. Please do not add new uses of it. (Instead, use - table_paste() or one of its helper functions to paste multiple tables - together into a larger one.) */ -void -tab_realloc (struct tab_table *t, int nc, int nr) -{ - int ro, co; - - ro = t->row_ofs; - co = t->col_ofs; - if (ro || co) - tab_offset (t, 0, 0); - - if (nc == -1) - nc = tab_nc (t); - if (nr == -1) - nr = tab_nr (t); - - assert (nc == tab_nc (t)); - - if (nc > t->cf) - { - int mr1 = MIN (nr, tab_nr (t)); - int mc1 = MIN (nc, tab_nc (t)); - - void **new_cc; - unsigned short *new_ct; - int r; - - new_cc = pool_calloc (t->container, nr * nc, sizeof *new_cc); - new_ct = pool_malloc (t->container, nr * nc); - for (r = 0; r < mr1; r++) - { - memcpy (&new_cc[r * nc], &t->cc[r * tab_nc (t)], - mc1 * sizeof *t->cc); - memcpy (&new_ct[r * nc], &t->ct[r * tab_nc (t)], - mc1 * sizeof *t->ct); - memset (&new_ct[r * nc + tab_nc (t)], 0, nc - tab_nc (t)); - } - pool_free (t->container, t->cc); - pool_free (t->container, t->ct); - t->cc = new_cc; - t->ct = new_ct; - t->cf = nc; - } - else if (nr != tab_nr (t)) - { - t->cc = pool_nrealloc (t->container, t->cc, nr * nc, sizeof *t->cc); - t->ct = pool_nrealloc (t->container, t->ct, nr * nc, sizeof *t->ct); - - t->rh = pool_nrealloc (t->container, t->rh, nc, nr + 1); - t->rv = pool_nrealloc (t->container, t->rv, nr, nc + 1); - - if (nr > tab_nr (t)) - { - memset (&t->rh[nc * (tab_nr (t) + 1)], TAL_0, - (nr - tab_nr (t)) * nc); - memset (&t->rv[(nc + 1) * tab_nr (t)], TAL_0, - (nr - tab_nr (t)) * (nc + 1)); - } - } - - memset (&t->ct[nc * tab_nr (t)], 0, nc * (nr - tab_nr (t)) * sizeof *t->ct); - memset (&t->cc[nc * tab_nr (t)], 0, nc * (nr - tab_nr (t)) * sizeof *t->cc); - - table_set_nr (&t->table, nr); - table_set_nc (&t->table, nc); - - if (ro || co) - tab_offset (t, co, ro); -} - /* Sets the number of header rows on each side of TABLE to L on the left, R on the right, T on the top, B on the bottom. Header rows are repeated when a table is broken across multiple columns or @@ -242,23 +116,16 @@ tab_vline (struct tab_table *t, int style, int x, int y1, int y2) { if (debugging) { - if (x + t->col_ofs < 0 || x + t->col_ofs > tab_nc (t) - || y1 + t->row_ofs < 0 || y1 + t->row_ofs >= tab_nr (t) - || y2 + t->row_ofs < 0 || y2 + t->row_ofs >= tab_nr (t)) + if (x < 0 || x > tab_nc (t) + || y1 < 0 || y1 >= tab_nr (t) + || y2 < 0 || y2 >= tab_nr (t)) { - printf (_("bad vline: x=%d+%d=%d y=(%d+%d=%d,%d+%d=%d) in " - "table size (%d,%d)\n"), - x, t->col_ofs, x + t->col_ofs, - y1, t->row_ofs, y1 + t->row_ofs, - y2, t->row_ofs, y2 + t->row_ofs, tab_nc (t), tab_nr (t)); + printf (_("bad vline: x=%d y=(%d,%d) in table size (%d,%d)\n"), + x, y1, y2, tab_nc (t), tab_nr (t)); return; } } - x += t->col_ofs; - y1 += t->row_ofs; - y2 += t->row_ofs; - assert (x >= 0); assert (x <= tab_nc (t)); assert (y1 >= 0); @@ -280,23 +147,16 @@ tab_hline (struct tab_table *t, int style, int x1, int x2, int y) { if (debugging) { - if (y + t->row_ofs < 0 || y + t->row_ofs > tab_nr (t) - || x1 + t->col_ofs < 0 || x1 + t->col_ofs >= tab_nc (t) - || x2 + t->col_ofs < 0 || x2 + t->col_ofs >= tab_nc (t)) + if (y < 0 || y > tab_nr (t) + || x1 < 0 || x1 >= tab_nc (t) + || x2 < 0 || x2 >= tab_nc (t)) { - printf (_("bad hline: x=(%d+%d=%d,%d+%d=%d) y=%d+%d=%d in " - "table size (%d,%d)\n"), - x1, t->col_ofs, x1 + t->col_ofs, - x2, t->col_ofs, x2 + t->col_ofs, - y, t->row_ofs, y + t->row_ofs, tab_nc (t), tab_nr (t)); + printf (_("bad hline: x=(%d,%d) y=%d in table size (%d,%d)\n"), + x1, x2, y, tab_nc (t), tab_nr (t)); return; } } - x1 += t->col_ofs; - x2 += t->col_ofs; - y += t->row_ofs; - assert (y >= 0); assert (y <= tab_nr (t)); assert (x2 >= x1); @@ -323,26 +183,17 @@ tab_box (struct tab_table *t, int f_h, int f_v, int i_h, int i_v, { if (debugging) { - if (x1 + t->col_ofs < 0 || x1 + t->col_ofs >= tab_nc (t) - || x2 + t->col_ofs < 0 || x2 + t->col_ofs >= tab_nc (t) - || y1 + t->row_ofs < 0 || y1 + t->row_ofs >= tab_nr (t) - || y2 + t->row_ofs < 0 || y2 + t->row_ofs >= tab_nr (t)) + if (x1 < 0 || x1 >= tab_nc (t) + || x2 < 0 || x2 >= tab_nc (t) + || y1 < 0 || y1 >= tab_nr (t) + || y2 < 0 || y2 >= tab_nr (t)) { - printf (_("bad box: (%d+%d=%d,%d+%d=%d)-(%d+%d=%d,%d+%d=%d) " - "in table size (%d,%d)\n"), - x1, t->col_ofs, x1 + t->col_ofs, - y1, t->row_ofs, y1 + t->row_ofs, - x2, t->col_ofs, x2 + t->col_ofs, - y2, t->row_ofs, y2 + t->row_ofs, tab_nc (t), tab_nr (t)); + printf (_("bad box: (%d,%d)-(%d,%d) in table size (%d,%d)\n"), + x1, y1, x2, y2, tab_nc (t), tab_nr (t)); NOT_REACHED (); } } - x1 += t->col_ofs; - x2 += t->col_ofs; - y1 += t->row_ofs; - y2 += t->row_ofs; - assert (x2 >= x1); assert (y2 >= y1); assert (x1 >= 0); @@ -397,81 +248,6 @@ tab_box (struct tab_table *t, int f_h, int f_v, int i_h, int i_v, /* Cells. */ -/* Sets cell (C,R) in TABLE, with options OPT, to have a value taken - from V, displayed with format spec F. */ -void -tab_value (struct tab_table *table, int c, int r, unsigned short opt, - const union value *v, const struct variable *var, - const struct fmt_spec *f) -{ - char *contents; - - if (debugging) - { - if (c + table->col_ofs < 0 || r + table->row_ofs < 0 - || c + table->col_ofs >= tab_nc (table) - || r + table->row_ofs >= tab_nr (table)) - { - printf ("tab_value(): bad cell (%d+%d=%d,%d+%d=%d) in table size " - "(%d,%d)\n", - c, table->col_ofs, c + table->col_ofs, - r, table->row_ofs, r + table->row_ofs, - tab_nc (table), tab_nr (table)); - return; - } - } - - contents = data_out_stretchy (v, var_get_encoding (var), - f != NULL ? f : var_get_print_format (var), - table->container); - - table->cc[c + r * table->cf] = contents; - table->ct[c + r * table->cf] = opt; -} - -/* Sets cell (C,R) in TABLE, with options OPT, to have value VAL as - formatted by FMT. - If FMT is null, then the default print format will be used. -*/ -void -tab_double (struct tab_table *table, int c, int r, unsigned short opt, - double val, const struct fmt_spec *fmt, enum result_class rc) -{ - union value double_value; - char *s; - - assert (c >= 0); - assert (c < tab_nc (table)); - assert (r >= 0); - assert (r < tab_nr (table)); - - if (fmt == NULL) - fmt = &table->fmtmap[rc]; - - fmt_check_output (fmt); - - if (debugging) - { - if (c + table->col_ofs < 0 || r + table->row_ofs < 0 - || c + table->col_ofs >= tab_nc (table) - || r + table->row_ofs >= tab_nr (table)) - { - printf ("tab_double(): bad cell (%d+%d=%d,%d+%d=%d) in table size " - "(%d,%d)\n", - c, table->col_ofs, c + table->col_ofs, - r, table->row_ofs, r + table->row_ofs, - tab_nc (table), tab_nr (table)); - return; - } - } - - double_value.f = val; - s = data_out_stretchy (&double_value, C_ENCODING, fmt, table->container); - table->cc[c + r * table->cf] = s + strspn (s, " "); - table->ct[c + r * table->cf] = opt; -} - - static void do_tab_text (struct tab_table *table, int c, int r, unsigned opt, char *text) { @@ -482,15 +258,10 @@ do_tab_text (struct tab_table *table, int c, int r, unsigned opt, char *text) if (debugging) { - if (c + table->col_ofs < 0 || r + table->row_ofs < 0 - || c + table->col_ofs >= tab_nc (table) - || r + table->row_ofs >= tab_nr (table)) + if (c < 0 || r < 0 || c >= tab_nc (table) || r >= tab_nr (table)) { - printf ("tab_text(): bad cell (%d+%d=%d,%d+%d=%d) in table size " - "(%d,%d)\n", - c, table->col_ofs, c + table->col_ofs, - r, table->row_ofs, r + table->row_ofs, - tab_nc (table), tab_nr (table)); + printf ("tab_text(): bad cell (%d,%d) in table size (%d,%d)\n", + c, r, tab_nc (table), tab_nr (table)); return; } } @@ -528,27 +299,23 @@ add_joined_cell (struct tab_table *table, int x1, int y1, int x2, int y2, { struct tab_joined_cell *j; - assert (x1 + table->col_ofs >= 0); - assert (y1 + table->row_ofs >= 0); + assert (x1 >= 0); + assert (y1 >= 0); assert (y2 >= y1); assert (x2 >= x1); - assert (y2 + table->row_ofs < tab_nr (table)); - assert (x2 + table->col_ofs < tab_nc (table)); + assert (y2 < tab_nr (table)); + assert (x2 < tab_nc (table)); if (debugging) { - if (x1 + table->col_ofs < 0 || x1 + table->col_ofs >= tab_nc (table) - || y1 + table->row_ofs < 0 || y1 + table->row_ofs >= tab_nr (table) - || x2 < x1 || x2 + table->col_ofs >= tab_nc (table) - || y2 < y1 || y2 + table->row_ofs >= tab_nr (table)) + if (x1 < 0 || x1 >= tab_nc (table) + || y1 < 0 || y1 >= tab_nr (table) + || x2 < x1 || x2 >= tab_nc (table) + || y2 < y1 || y2 >= tab_nr (table)) { printf ("tab_joint_text(): bad cell " - "(%d+%d=%d,%d+%d=%d)-(%d+%d=%d,%d+%d=%d) in table size (%d,%d)\n", - x1, table->col_ofs, x1 + table->col_ofs, - y1, table->row_ofs, y1 + table->row_ofs, - x2, table->col_ofs, x2 + table->col_ofs, - y2, table->row_ofs, y2 + table->row_ofs, - tab_nc (table), tab_nr (table)); + "(%d,%d)-(%d,%d) in table size (%d,%d)\n", + x1, y1, x2, y2, tab_nc (table), tab_nr (table)); return NULL; } } @@ -556,10 +323,10 @@ add_joined_cell (struct tab_table *table, int x1, int y1, int x2, int y2, tab_box (table, -1, -1, TAL_0, TAL_0, x1, y1, x2, y2); j = pool_alloc (table->container, sizeof *j); - j->d[TABLE_HORZ][0] = x1 + table->col_ofs; - j->d[TABLE_VERT][0] = y1 + table->row_ofs; - j->d[TABLE_HORZ][1] = ++x2 + table->col_ofs; - j->d[TABLE_VERT][1] = ++y2 + table->row_ofs; + j->d[TABLE_HORZ][0] = x1; + j->d[TABLE_VERT][0] = y1; + j->d[TABLE_HORZ][1] = ++x2; + j->d[TABLE_VERT][1] = ++y2; j->n_footnotes = 0; j->footnotes = NULL; j->style = NULL; @@ -599,24 +366,7 @@ tab_joint_text (struct tab_table *table, int x1, int y1, int x2, int y2, if (x1 == x2 && y1 == y2) do_tab_text (table, x1, y1, opt, s); else - add_joined_cell (table, x1, y1, x2, y2, opt)->u.text = s; -} - -/* Joins cells (X1,X2)-(Y1,Y2) inclusive in TABLE, and sets them - with options OPT to have text value FORMAT, which is formatted - as if passed to printf. */ -void -tab_joint_text_format (struct tab_table *table, int x1, int y1, int x2, - int y2, unsigned opt, const char *format, ...) -{ - va_list args; - char *s; - - va_start (args, format); - s = pool_vasprintf (table->container, format, args); - va_end (args); - - add_joined_cell (table, x1, y1, x2, y2, opt)->u.text = s; + add_joined_cell (table, x1, y1, x2, y2, opt)->text = s; } struct footnote * @@ -646,7 +396,7 @@ tab_add_footnote (struct tab_table *table, int x, int y, char *text = table->cc[index]; j = add_joined_cell (table, x, y, x, y, table->ct[index]); - j->u.text = text ? text : xstrdup (""); + j->text = text ? text : xstrdup (""); } j->footnotes = pool_realloc (table->container, j->footnotes, @@ -670,7 +420,7 @@ tab_add_style (struct tab_table *table, int x, int y, char *text = table->cc[index]; j = add_joined_cell (table, x, y, x, y, table->ct[index]); - j->u.text = text ? text : xstrdup (""); + j->text = text ? text : xstrdup (""); } j->style = style; @@ -682,85 +432,8 @@ tab_cell_is_empty (const struct tab_table *table, int c, int r) return table->cc[c + r * table->cf] == NULL; } -/* Miscellaneous. */ - -/* Set the title of table T to TITLE, which is formatted as if - passed to printf(). */ -void -tab_title (struct tab_table *t, const char *title, ...) -{ - va_list args; - - free (t->title); - va_start (args, title); - t->title = xvasprintf (title, args); - va_end (args); -} - -/* Set the caption of table T to CAPTION, which is formatted as if - passed to printf(). */ -void -tab_caption (struct tab_table *t, const char *caption, ...) -{ - va_list args; - - free (t->caption); - va_start (args, caption); - t->caption = xvasprintf (caption, args); - va_end (args); -} - -/* Easy, type-safe way to submit a tab table to som. */ -void -tab_submit (struct tab_table *t) -{ - table_item_submit (table_item_create (&t->table, t->title, t->caption)); -} - /* Editing. */ -/* Set table row and column offsets for all functions that affect - cells or rules. */ -void -tab_offset (struct tab_table *t, int col, int row) -{ - int diff = 0; - - if (debugging) - { - if (row < -1 || row > tab_nr (t)) - { - printf ("tab_offset(): row=%d in %d-row table\n", row, tab_nr (t)); - NOT_REACHED (); - } - if (col < -1 || col > tab_nc (t)) - { - printf ("tab_offset(): col=%d in %d-column table\n", col, - tab_nc (t)); - NOT_REACHED (); - } - } - - if (row != -1) - diff += (row - t->row_ofs) * t->cf, t->row_ofs = row; - if (col != -1) - diff += (col - t->col_ofs), t->col_ofs = col; - - t->cc += diff; - t->ct += diff; -} - -/* Increment the row offset by one. If the table is too small, - increase its size. */ -void -tab_next_row (struct tab_table *t) -{ - t->cc += t->cf; - t->ct += t->cf; - if (++t->row_ofs >= tab_nr (t)) - tab_realloc (t, -1, tab_nr (t) * 4 / 3); -} - /* Writes STRING to the output. OPTIONS may be any valid combination of TAB_* bits. @@ -769,8 +442,7 @@ tab_next_row (struct tab_table *t) void tab_output_text (int options, const char *string) { - enum text_item_type type = (options & TAB_EMPH ? TEXT_ITEM_TITLE - : options & TAB_FIX ? TEXT_ITEM_LOG + enum text_item_type type = (options & TAB_FIX ? TEXT_ITEM_LOG : TEXT_ITEM_PARAGRAPH); text_item_submit (text_item_create (type, string)); } @@ -798,10 +470,6 @@ static void tab_destroy (struct table *table) { struct tab_table *t = tab_cast (table); - free (t->title); - t->title = NULL; - free (t->caption); - t->caption = NULL; pool_destroy (t->container); } @@ -854,7 +522,7 @@ tab_get_cell (const struct table *table, int x, int y, if (opt & TAB_JOIN) { const struct tab_joined_cell *jc = cc; - cell->text = jc->u.text; + cell->text = jc->text; cell->footnotes = jc->footnotes; cell->n_footnotes = jc->n_footnotes; diff --git a/src/output/tab.h b/src/output/tab.h index abd786119c..f81a010c65 100644 --- a/src/output/tab.h +++ b/src/output/tab.h @@ -21,36 +21,12 @@ This is a type of table (see output/table.h) whose content is composed manually by the code that generates it, by filling in cells one by one. - - Some of the features of this type of table are obsolete but have not yet - been removed, because some code still uses them. These features are: - - - The title and caption. These are properties of the table_item (see - output/table-item.h) in which a table is embedded, not properties of - the table itself. - - - Row and columns offsets (via tab_offset(), tab_next_row()). This - feature simply isn't used enough to justify keeping it. - - - Table resizing. The code that does use this feature is just as well - served by creating multiple tables and pasting them together with - table_paste(). Eliminating this feature would also slightly simplify - the table code here. */ #include "libpspp/compiler.h" #include "output/table.h" #include "data/format.h" -enum result_class - { - RC_INTEGER, - RC_WEIGHT, - RC_PVALUE, - RC_OTHER, - n_RC - }; - #define TAB_STYLE_MASK (7u << (TAB_FIRST_AVAILABLE + 1)) #define TAB_STYLE_SHIFT (TAB_FIRST_AVAILABLE + 1) @@ -82,7 +58,6 @@ struct tab_table struct pool *container; /* Table title and caption, or null. */ - char *title, *caption; int cf; /* Column factor for indexing purposes. */ /* Table contents. @@ -99,11 +74,6 @@ struct tab_table unsigned char *rh; /* Horiz rules; unsigned char[nr+1][nc]. */ unsigned char *rv; /* Vert rules; unsigned char[nr][nc+1]. */ struct cell_color *rule_colors[32]; - - /* X and Y offsets. */ - int col_ofs, row_ofs; - - struct fmt_spec fmtmap [n_RC]; }; struct tab_table *tab_cast (const struct table *); @@ -126,14 +96,7 @@ static inline int tab_b (const struct tab_table *table) /* Tables. */ struct tab_table *tab_create (int nc, int nr); -void tab_resize (struct tab_table *, int nc, int nr); -void tab_realloc (struct tab_table *, int nc, int nr); void tab_headers (struct tab_table *, int l, int r, int t, int b); -void tab_title (struct tab_table *, const char *, ...) - PRINTF_FORMAT (2, 3); -void tab_caption (struct tab_table *, const char *, ...) - PRINTF_FORMAT (2, 3); -void tab_submit (struct tab_table *); /* Rules. */ void tab_hline (struct tab_table *, int style, int x1, int x2, int y); @@ -141,23 +104,7 @@ void tab_vline (struct tab_table *, int style, int x, int y1, int y2); void tab_box (struct tab_table *, int f_h, int f_v, int i_h, int i_v, int x1, int y1, int x2, int y2); -/* Obsolete cell options. */ -#define TAT_TITLE TAB_EMPH /* Title attributes. */ - -void tab_set_format (struct tab_table *, enum result_class, const struct fmt_spec *); - - /* Cells. */ -struct fmt_spec; -struct dictionary; -union value; -void tab_value (struct tab_table *, int c, int r, unsigned short opt, - const union value *, const struct variable *, - const struct fmt_spec *); - -void tab_double (struct tab_table *, int c, int r, unsigned short opt, - double v, const struct fmt_spec *, enum result_class ); - void tab_text (struct tab_table *, int c, int r, unsigned opt, const char *); void tab_text_format (struct tab_table *, int c, int r, unsigned opt, const char *, ...) @@ -165,9 +112,6 @@ void tab_text_format (struct tab_table *, int c, int r, unsigned opt, void tab_joint_text (struct tab_table *, int x1, int y1, int x2, int y2, unsigned opt, const char *); -void tab_joint_text_format (struct tab_table *, int x1, int y1, int x2, int y2, - unsigned opt, const char *, ...) - PRINTF_FORMAT (7, 8); struct footnote *tab_create_footnote (struct tab_table *, size_t idx, const char *content, const char *marker, @@ -180,14 +124,6 @@ void tab_add_style (struct tab_table *, int x, int y, bool tab_cell_is_empty (const struct tab_table *, int c, int r); -/* Editing. */ -void tab_offset (struct tab_table *, int col, int row); -void tab_next_row (struct tab_table *); - -/* Current row/column offset. */ -#define tab_row(TABLE) ((TABLE)->row_ofs) -#define tab_col(TABLE) ((TABLE)->col_ofs) - /* Simple output. */ void tab_output_text (int options, const char *string); void tab_output_text_format (int options, const char *, ...) diff --git a/src/output/table-casereader.c b/src/output/table-casereader.c deleted file mode 100644 index e1b75ac5da..0000000000 --- a/src/output/table-casereader.c +++ /dev/null @@ -1,166 +0,0 @@ -/* PSPP - a program for statistical analysis. - Copyright (C) 2009, 2011, 2013, 2014 Free Software Foundation, Inc. - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . */ - -#include - -#include "output/table-provider.h" - -#include "data/casereader.h" -#include "data/data-out.h" -#include "data/format.h" -#include "libpspp/i18n.h" - -#include "gl/xalloc.h" - -struct table_casereader - { - struct table table; - struct casereader *reader; - char *heading; - struct fmt_spec format; - }; - -static const struct table_class table_casereader_class; - -static struct table_casereader * -table_casereader_cast (const struct table *table) -{ - assert (table->klass == &table_casereader_class); - return UP_CAST (table, struct table_casereader, table); -} - -/* Returns a new table that has one column and the same number of rows as - READER. Each row in the table is derived from column COLUMN in the same row - of READER by formatting with data_out() using the specified FORMAT (which - must be a valid format for the column's width). - - If HEADING is nonnull, adds an additional row above the first row of data - that contains HEADING, and sets that row as a header row. - - The returned table has no rules, except that if HEADING is nonnull, a single - line (TAL_1) separates HEADING from the first row if data. */ -struct table * -table_from_casereader (const struct casereader *reader, size_t column, - const char *heading, const struct fmt_spec *format) -{ - struct table_casereader *tc; - struct table *t; - - assert (fmt_check_width_compat (format, - caseproto_get_width ( - casereader_get_proto (reader), column))); - - tc = xmalloc (sizeof *tc); - t = &tc->table; - table_init (t, &table_casereader_class); - table_set_nc (t, 1); - table_set_nr (t, casereader_count_cases (reader)); - tc->reader = casereader_project_1 (casereader_clone (reader), column); - tc->heading = NULL; - tc->format = *format; - - if (heading != NULL) - { - tc->heading = xstrdup (heading); - table_set_nr (t, table_nr (t) + 1); - table_set_ht (t, 1); - } - - return t; -} - -static void -table_casereader_destroy (struct table *t) -{ - struct table_casereader *tc = table_casereader_cast (t); - casereader_destroy (tc->reader); - free (tc->heading); - free (t); -} - -static void -free_string (void *s_) -{ - char *s = s_; - free (s); -} - -static void -table_casereader_get_cell (const struct table *t, int x, int y, - struct table_cell *cell) -{ - struct table_casereader *tc = table_casereader_cast (t); - struct ccase *c; - char *s; - - static const struct area_style style = { - AREA_STYLE_INITIALIZER__, - .cell_style.halign = TABLE_HALIGN_RIGHT - }; - - cell->d[TABLE_HORZ][0] = x; - cell->d[TABLE_HORZ][1] = x + 1; - cell->d[TABLE_VERT][0] = y; - cell->d[TABLE_VERT][1] = y + 1; - cell->style = &style; - cell->options = 0; - cell->n_footnotes = 0; - if (tc->heading != NULL) - { - if (y == 0) - { - s = xstrdup (tc->heading); - cell->text = s; - cell->destructor = free_string; - cell->destructor_aux = s; - return; - } - y--; - } - - c = casereader_peek (tc->reader, y); - if (c == NULL) - s = xstrdup ("I/O Error"); - else - { - s = data_out (case_data_idx (c, 0), UTF8, &tc->format); - case_unref (c); - } - cell->text = s; - cell->destructor = free_string; - cell->destructor_aux = s; -} - -static int -table_casereader_get_rule (const struct table *t, enum table_axis axis, - int x UNUSED, int y, - struct cell_color *color UNUSED) -{ - struct table_casereader *tc = table_casereader_cast (t); - if (axis == TABLE_VERT) - return tc->heading != NULL && y == 1 ? TAL_1 : TAL_0; - else - return TAL_0; -} - -static const struct table_class table_casereader_class = - { - table_casereader_destroy, - table_casereader_get_cell, - table_casereader_get_rule, - NULL, /* paste */ - NULL, /* select (XXX) */ - }; diff --git a/src/output/table.c b/src/output/table.c index d94316eed2..aafc2f6db0 100644 --- a/src/output/table.c +++ b/src/output/table.c @@ -23,6 +23,7 @@ #include #include +#include "data/format.h" #include "libpspp/assertion.h" #include "libpspp/cast.h" #include "libpspp/compiler.h" diff --git a/src/output/table.h b/src/output/table.h index b2c194367f..d162a28b4a 100644 --- a/src/output/table.h +++ b/src/output/table.h @@ -171,7 +171,6 @@ void area_style_free (struct area_style *); enum { TAB_NONE = 0, - TAB_EMPH = 1 << 0, /* Emphasize cell contents. */ TAB_FIX = 1 << 1, /* Use fixed font. */ TAB_MARKUP = 1 << 2, /* Text contains Pango markup. */ TAB_NUMERIC = 1 << 3, /* Cell contents are numeric. */ @@ -271,12 +270,6 @@ void table_set_hb (struct table *, int hb); /* Simple kinds of tables. */ struct table *table_from_string (enum table_halign, const char *); -struct table *table_from_variables (unsigned int options, - struct variable **, size_t); -struct table *table_from_casereader (const struct casereader *, - size_t column, - const char *heading, - const struct fmt_spec *); /* Combining tables. */ struct table *table_paste (struct table *, struct table *, diff --git a/src/ui/gui/psppire-output-window.c b/src/ui/gui/psppire-output-window.c index 9ebc51d196..f61e8e546e 100644 --- a/src/ui/gui/psppire-output-window.c +++ b/src/ui/gui/psppire-output-window.c @@ -32,7 +32,6 @@ #include "output/driver-provider.h" #include "output/message-item.h" #include "output/output-item.h" -#include "output/tab.h" #include "output/table-item.h" #include "output/text-item.h" #include "ui/gui/help-menu.h" diff --git a/tests/automake.mk b/tests/automake.mk index 161bb1b824..116e32c217 100644 --- a/tests/automake.mk +++ b/tests/automake.mk @@ -250,7 +250,6 @@ tests_output_render_test_LDADD = \ src/libpspp-core.la \ $(CAIRO_LIBS) - check_PROGRAMS += tests/ui/syntax-gen-test tests_ui_syntax_gen_test_SOURCES = tests/ui/syntax-gen-test.c tests_ui_syntax_gen_test_LDADD = \ diff --git a/tests/data/pc+-file-reader.at b/tests/data/pc+-file-reader.at index 44de36a7b0..e78dd756a0 100644 --- a/tests/data/pc+-file-reader.at +++ b/tests/data/pc+-file-reader.at @@ -105,7 +105,8 @@ LIST. ]) AT_CHECK([pspp -o pspp.csv pc+-file.sps]) AT_CHECK([cat pspp.csv], [0], [dnl -File label: PSPP synthetic test file +Table: File Label +Label,PSPP synthetic test file Table: Variables Name,Position,Label,Measurement Level,Role,Width,Alignment,Print Format,Write Format,Missing Values @@ -122,7 +123,7 @@ STR6,10,Another string variable's label,Nominal,Input,11,Left,A11,A11, Table: Data List NUM1,NUM2,NUM3,NUM4,STR1,STR2,STR3,STR4,STR5,STR6 -0,1,2,.,abcdefgh,ijkl,mnopq,r,stuvwxyzAB ,CDEFGHIJKLM +0,1,2,.,abcdefgh,ijkl,mnopq,r,stuvwxyzAB,CDEFGHIJKLM ]) AT_CLEANUP @@ -217,7 +218,8 @@ LIST. ]) AT_CHECK([pspp -o pspp.csv pc+-file.sps]) AT_CHECK([cat pspp.csv], [0], [dnl -File label: PSPP synthetic test file +Table: File Label +Label,PSPP synthetic test file Table: Variables Name,Position,Label,Measurement Level,Role,Width,Alignment,Print Format,Write Format,Missing Values @@ -236,7 +238,7 @@ STR7,12,,Nominal,Input,7,Left,A7,A7, STR8,13,,Nominal,Input,8,Left,A8,A8, Table: Value Labels -Variable,Value,Label +Variable Value,,Label NUM1,1,one NUM2,2,two ,3,three @@ -330,7 +332,8 @@ LIST. ]) AT_CHECK([pspp -o pspp.csv pc+-file.sps]) AT_CHECK([cat pspp.csv], [0], [dnl -File label: PSPP synthetic test file +Table: File Label +Label,PSPP synthetic test file Table: Variables Name,Position,Label,Measurement Level,Role,Width,Alignment,Print Format,Write Format,Missing Values @@ -342,7 +345,7 @@ STR15,5,,Nominal,Input,15,Left,A15,A15, Table: Data List NUM1,NUM2,STR4,STR8,STR15 --5,150,abcd,efghj ,efghijklABCDEFG +-5,150,abcd,efghj,efghijklABCDEFG 1000,.,PQRS,TUVWXYZa,bcdefghijklmnop ]) AT_CLEANUP @@ -395,17 +398,18 @@ AT_DATA([pc+-file.sps], [dnl SYSFILE INFO FILE='pc+-file.sav' ENCODING='us-ascii'. ]) AT_CHECK([pspp -O format=csv pc+-file.sps], [0], [dnl -File:,pc+-file.sav -Label:,PSPP synthetic test file -Created:,11/28/14 15:11:00 by PCSPSS PSPP synthetic test product -Integer Format:,Little Endian -Real Format:,IEEE 754 LE. -Variables:,4 -Cases:,1 -Type:,SPSS/PC+ System File -Weight:,NUM3 -Compression:,None -Encoding:,us-ascii +Table: File Information +File,pc+-file.sav +Label,PSPP synthetic test file +Created,11/28/14 15:11:00 by PCSPSS PSPP synthetic test product +Integer Format,Little Endian +Real Format,IEEE 754 LE. +Variables,4 +Cases,1 +Type,SPSS/PC+ System File +Weight,NUM3 +Compression,None +Encoding,us-ascii Table: Variables Name,Position,Label,Measurement Level,Role,Width,Alignment,Print Format,Write Format,Missing Values @@ -474,7 +478,8 @@ AT_CHECK([pspp -O format=csv pc+-file.sps], [0], [stdout], []) AT_CHECK([sed 's/default encoding.*For/default encoding. For/' stdout], [0], [dnl "warning: `pc+-file.sav': Using default encoding. For best results, specify an encoding explicitly. Use SYSFILE INFO with ENCODING=""DETECT"" to analyze the possible encodings." -File label: PSPP synthetic test file +Table: File Label +Label,PSPP synthetic test file Table: Variables Name,Position,Label,Measurement Level,Role,Width,Alignment,Print Format,Write Format,Missing Values @@ -487,17 +492,18 @@ Table: Data List NUM1,NUM2,NUM3,NUM4 2,3,4,5 -File:,pc+-file.sav -Label:,PSPP synthetic test file -Created:,11/28/14 15:11:00 by PCSPSS PSPP synthetic test product -Integer Format:,Little Endian -Real Format:,IEEE 754 LE. -Variables:,4 -Cases:,1 -Type:,SPSS/PC+ System File -Weight:,Not weighted. -Compression:,None -Encoding:,us-ascii +Table: File Information +File,pc+-file.sav +Label,PSPP synthetic test file +Created,11/28/14 15:11:00 by PCSPSS PSPP synthetic test product +Integer Format,Little Endian +Real Format,IEEE 754 LE. +Variables,4 +Cases,1 +Type,SPSS/PC+ System File +Weight,Not weighted +Compression,None +Encoding,us-ascii Table: Variables Name,Position,Label,Measurement Level,Role,Width,Alignment,Print Format,Write Format,Missing Values @@ -1240,7 +1246,8 @@ DISPLAY DICTIONARY. LIST. ]) AT_CHECK([pspp -O format=csv pc+-file.sps], [0], [dnl -File label: PSPP synthetic test file +Table: File Label +Label,PSPP synthetic test file Table: Variables Name,Position,Label,Measurement Level,Role,Width,Alignment,Print Format,Write Format,Missing Values @@ -1254,7 +1261,7 @@ warning: `pc+-file.sav' near offset 0x308: Possible compressed data corruption: Table: Data List NUM1,NUM2,STR4,STR8,STR15 --5,150,abcd,efghj ,efghijklABCDEFG +-5,150,abcd,efghj,efghijklABCDEFG 1000,.,PQRS,TUVWXYZa,bcdefghijklmnop ]) AT_CLEANUP diff --git a/tests/data/por-file.at b/tests/data/por-file.at index 3139bbf490..1b5fc21174 100644 --- a/tests/data/por-file.at +++ b/tests/data/por-file.at @@ -113,7 +113,7 @@ VAR4,4,,Scale,Input,8,Right,F1.0,F1.0, VAR5,5,,Scale,Input,8,Right,F1.0,F1.0, Table: Value Labels -Variable,Value,Label +Variable Value,,Label VAR1,1,one VAR2,2,two VAR3,3,three @@ -132,13 +132,14 @@ AT_CHECK([pspp -O format=csv sys-file-info.sps | sed '/Encoding/d /Created/d /Product/d '], [0], [dnl -File:,data.por -Label:,No label. -Variables:,5 -Cases:,Unknown -Type:,SPSS Portable File -Weight:,Not weighted. -Compression:,None +Table: File Information +File,data.por +Label, +Variables,5 +Cases,Unknown +Type,SPSS Portable File +Weight,Not weighted +Compression,None Table: Variables Name,Position,Label,Measurement Level,Role,Width,Alignment,Print Format,Write Format,Missing Values @@ -149,7 +150,7 @@ VAR4,4,,Scale,Input,8,Right,F1.0,F1.0, VAR5,5,,Scale,Input,8,Right,F1.0,F1.0, Table: Value Labels -Variable,Value,Label +Variable Value,,Label VAR1,1,one VAR2,2,two VAR3,3,three diff --git a/tests/data/sys-file-reader.at b/tests/data/sys-file-reader.at index afe3bff3b5..a22ecfa56b 100644 --- a/tests/data/sys-file-reader.at +++ b/tests/data/sys-file-reader.at @@ -147,7 +147,8 @@ LIST. ]) AT_CHECK([pspp -o pspp.csv sys-file.sps]) AT_CHECK([cat pspp.csv], [0], [dnl -File label: PSPP synthetic test file: ôõöø +Table: File Label +Label,PSPP synthetic test file: ôõöø Table: Variables Name,Position,Label,Measurement Level,Role,Width,Alignment,Print Format,Write Format,Missing Values @@ -427,7 +428,7 @@ str16,16,,Nominal,Input,16,Left,A16,A16, str17,17,,Nominal,Input,17,Left,A17,A17, Table: Value Labels -Variable,Value,Label +Variable Value,,Label num1,1,один (in Russian) num2,1,one ,2,two @@ -515,17 +516,12 @@ LIST. ]) AT_CHECK([pspp -o pspp.csv sys-file.sps]) AT_CHECK([cat pspp.csv], [0], [dnl -Documents in the active dataset: - -First line of documents - +Table: Documents +"First line of documents Second line of documents - abbé appliqué attaché blasé café canapé cliché consommé - - -Last line of documents +Last line of documents" Table: Data List num1 @@ -651,47 +647,23 @@ MRSETS /DISPLAY NAME=ALL. AT_CHECK([pspp -o pspp.csv sys-file.sps]) AT_CHECK([cat pspp.csv], [0], [dnl Table: Multiple Response Sets -Name,Variables,Details -$a,"あ +Name,Label,Encoding,Counted Value,Member Variables +$a,my mcgroup,Categories,,"あ b -c -","Multiple category set -Label: my mcgroup -" -$b,"g +c" +$b,,Dichotomies,55,"g e f -d -","Multiple dichotomy set -Counted value: 55 -Category label source: Variable labels -" -$c,"h +d" +$c,mdgroup #2,Dichotomies,はい,"h i -j -","Multiple dichotomy set -Label: mdgroup #2 -Label source: Provided by user -Counted value: `はい' -Category label source: Variable labels -" -$d,"k +j" +$d,third mdgroup,Dichotomies,34,"k l -m -","Multiple dichotomy set -Label: third mdgroup -Label source: Provided by user -Counted value: 34 -Category label source: Value labels of counted value -" -$e,"n +m" +$e,,Dichotomies,choice,"n o -p -","Multiple dichotomy set -Label source: First variable label among variables -Counted value: `choice' -Category label source: Value labels of counted value -" +p" ]) done AT_CLEANUP @@ -733,12 +705,13 @@ for variant in be le; do SYSFILE INFO FILE='sys-file.sav'. ]) AT_CHECK([pspp -o pspp.csv sys-file.sps]) - AT_CHECK([sed 7q pspp.csv], [0], [dnl -File:,sys-file.sav -Label:,"PSPP synthetic + AT_CHECK([sed 8q pspp.csv], [0], [dnl +Table: File Information +File,sys-file.sav +Label,"PSPP synthetic test file" -Created:,01 Jan 11 20:53:52 by $(@%:@) SPSS DATA FILE PSPP synthetic test file -Product:,"Extra product info +Created,01 Jan 11 20:53:52 by $(@%:@) SPSS DATA FILE PSPP synthetic test file +Product,"Extra product info another line blah" ]) @@ -1112,7 +1085,7 @@ DISPLAY @ATTRIBUTES. AT_CHECK([pspp -o pspp.csv sys-file.sps]) AT_CHECK([cat pspp.csv], [0], [[Table: Variable and Dataset Attributes -Variable,Name,Value +Variable and Name,,Value (dataset),Attr1[1],Value1 ,Attr1[2],'déclaration' ,SécondAttr[1],123 @@ -1263,8 +1236,8 @@ str15,5,,Nominal,Input,15,Left,A15,A15, Table: Data List num1,num2,str4,str8,str15 --99,0,,abcdefgh,0123 @&t@ -.,151,jklm,nopqrstu,vwxyzABC @&t@ +-99,0,,abcdefgh,0123 +.,151,jklm,nopqrstu,vwxyzABC 1,2,DEFG,HIJKLMNO,PQRSTUV ]) done @@ -1326,8 +1299,8 @@ str15,5,,Nominal,Input,15,Left,A15,A15, Table: Data List num1,num2,str4,str8,str15 -1,100,,abcdefgh,0123 @&t@ -.,251,jklm,nopqrstu,vwxyzABC @&t@ +1,100,,abcdefgh,0123 +.,251,jklm,nopqrstu,vwxyzABC 101,102,DEFG,HIJKLMNO,PQRSTUV ]) done @@ -1393,8 +1366,8 @@ str15,5,,Nominal,Input,15,Left,A15,A15, Table: Data List num1,num2,str4,str8,str15 --49,50,,abcdefgh,0123 @&t@ -.,201,jklm,nopqrstu,vwxyzABC @&t@ +-49,50,,abcdefgh,0123 +.,201,jklm,nopqrstu,vwxyzABC 51,52,DEFG,HIJKLMNO,PQRSTUV ]) done @@ -1491,8 +1464,8 @@ str15,5,,Nominal,Input,15,Left,A15,A15, Table: Data List num1,num2,str4,str8,str15 --99,0,,abcdefgh,0123 @&t@ -.,151,jklm,nopqrstu,vwxyzABC @&t@ +-99,0,,abcdefgh,0123 +.,151,jklm,nopqrstu,vwxyzABC 1,2,DEFG,HIJKLMNO,PQRSTUV ]) done @@ -2414,31 +2387,16 @@ warning: `sys-file.sav': Invalid multiple response set name `b'. warning: `sys-file.sav': Invalid multiple response set name `e'. Table: Multiple Response Sets -Name,Variables,Details -$a,"あ +Name,Label,Encoding,Counted Value,Member Variables +$a,my mcgroup,Categories,,"あ b -c -","Multiple category set -Label: my mcgroup -" -$c,"h +c" +$c,mdgroup #2,Dichotomies,はい,"h i -j -","Multiple dichotomy set -Label: mdgroup #2 -Label source: Provided by user -Counted value: `はい' -Category label source: Variable labels -" -$d,"k +j" +$d,third mdgroup,Dichotomies,34,"k l -m -","Multiple dichotomy set -Label: third mdgroup -Label source: Provided by user -Counted value: 34 -Category label source: Value labels of counted value -" +m" ]) done AT_CLEANUP @@ -3569,7 +3527,7 @@ LIST. Table: Data List str14 -one data item @&t@ +one data item ]) done AT_CLEANUP @@ -3617,7 +3575,7 @@ LIST. Table: Data List num1,num2,str4,str8,str15 --99,0,,abcdefgh,0123 @&t@ +-99,0,,abcdefgh,0123 ]) done AT_CLEANUP diff --git a/tests/data/sys-file.at b/tests/data/sys-file.at index b6c17b35fa..e260f0eada 100644 --- a/tests/data/sys-file.at +++ b/tests/data/sys-file.at @@ -96,12 +96,12 @@ s2,2,,Nominal,Input,9,Left,A9,A9,"""12 ""; ""123 """ s3,3,,Nominal,Input,9,Left,A9,A9,"""1234 ""; ""12345 ""; ""12345678""" Table: Value Labels -Variable,Value,Label -s1,abc ,First value label -,abcdefgh ,Second value label +Variable Value,,Label +s1,abc,First value label +,abcdefgh,Second value label ,abcdefghi,Third value label -s2,0 ,Fourth value label -,01234567 ,Fifth value label +s2,0,Fourth value label +,01234567,Fifth value label ,012345678,Sixth value label ]) AT_CHECK_UNQUOTED([dd if=foo.sav bs=1 count=4; echo], [0], [$magic @@ -276,13 +276,13 @@ count,4,number of countries Table: Data List cont,size,pop,count -Asia ,44579000,3.7E+009,44.00 -Africa ,30065000,7.8E+008,53.00 -North America ,24256000,4.8E+008,23.00 -South America ,17819000,3.4E+008,12.00 -Antarctica ,13209000,.00,.00 -Europe ,9938000,7.3E+008,46.00 -Australia/Oceania ,7687000,31000000,14.00 +Asia,44579000,3.7E+009,44.00 +Africa,30065000,7.8E+008,53.00 +North America,24256000,4.8E+008,23.00 +South America,17819000,3.4E+008,12.00 +Antarctica,13209000,.00,.00 +Europe,9938000,7.3E+008,46.00 +Australia/Oceania,7687000,31000000,14.00 ]) AT_CLEANUP @@ -459,17 +459,14 @@ DISPLAY ATTRIBUTES. ]) AT_CHECK([pspp -o pspp.csv get.sps]) AT_CHECK([[sed 's/(Entered [^)]*)/(Entered )/' pspp.csv]], [0], [dnl -File label: clientèle confrère cortège crèche - -Documents in the active dataset: - -DOCUMENT coördinate smörgåsbord +Table: File Label +Label,clientèle confrère cortège crèche +Table: Documents +"DOCUMENT coördinate smörgåsbord épée séance soufflé soirée - jalapeño vicuña. - -(Entered ) + (Entered )" Table: Variables Name,Position,Label,Measurement Level,Role,Width,Alignment,Print Format,Write Format,Missing Values @@ -478,12 +475,12 @@ roué,2,Provençal soupçon,Nominal,Input,9,Left,A9,A9, croûton,3,,Nominal,Input,32,Left,A1000,A1000, Table: Value Labels -Variable,Value,Label +Variable Value,,Label àéîöçxyzabc,1.00,éclair élan -roué,abcdefghi,sauté précis +Provençal soupçon,abcdefghi,sauté précis Table: Variable and Dataset Attributes -Variable,Name,Value +Variable and Name,,Value (dataset),Furtwängler,kindergärtner àéîöçxyzabc,Atatürk,Düsseldorf Gewürztraminer ]) diff --git a/tests/language/data-io/data-list.at b/tests/language/data-io/data-list.at index 5bfdb497b1..a1f599cba9 100644 --- a/tests/language/data-io/data-list.at +++ b/tests/language/data-io/data-list.at @@ -349,8 +349,8 @@ data-list.sps:4: warning: Missing delimiter following quoted string. Table: Data List s -y @&t@ -z @&t@ +y +z ]) AT_CLEANUP diff --git a/tests/language/data-io/dataset.at b/tests/language/data-io/dataset.at index 64139f9360..32ff5e140a 100644 --- a/tests/language/data-io/dataset.at +++ b/tests/language/data-io/dataset.at @@ -66,13 +66,11 @@ y 7 8 -Table: Open datasets. -Dataset +Table: Datasets clone initial (active dataset) -Table: Open datasets. -Dataset +Table: Datasets clone (active dataset) initial @@ -84,8 +82,7 @@ x 5 6 -Table: Open datasets. -Dataset +Table: Datasets clone initial (active dataset) @@ -101,13 +98,11 @@ y,z 7,7.00 8,8.00 -Table: Open datasets. -Dataset +Table: Datasets unnamed dataset (active dataset) initial -Table: Open datasets. -Dataset +Table: Datasets unnamed dataset (active dataset) ]) AT_CLEANUP @@ -126,8 +121,7 @@ DATASET DISPLAY. LIST. ]) AT_CHECK([pspp -O format=csv dataset.pspp], [1], [dnl -Table: Open datasets. -Dataset +Table: Datasets unnamed dataset (active dataset) second @@ -135,8 +129,7 @@ Table: Data List x 1 -Table: Open datasets. -Dataset +Table: Datasets second (active dataset) dataset.pspp:10: error: LIST: LIST is allowed only after the active dataset has been defined. @@ -155,14 +148,12 @@ DATASET NAME c. DATASET DISPLAY. ]) AT_CHECK([pspp -O format=csv dataset.pspp], [0], [dnl -Table: Open datasets. -Dataset +Table: Datasets a (active dataset) b c -Table: Open datasets. -Dataset +Table: Datasets c (active dataset) ]) AT_CLEANUP @@ -176,13 +167,11 @@ DATASET ACTIVATE x. DATASET DISPLAY. ]) AT_CHECK([pspp -O format=csv dataset.pspp], [0], [dnl -Table: Open datasets. -Dataset +Table: Datasets unnamed dataset (active dataset) x -Table: Open datasets. -Dataset +Table: Datasets x (active dataset) ]) AT_CLEANUP @@ -210,8 +199,7 @@ DATASET ACTIVATE one. LIST. ]) AT_CHECK([pspp -O format=csv dataset.pspp], [1], [dnl -Table: Open datasets. -Dataset +Table: Datasets another one (active dataset) @@ -269,50 +257,40 @@ DATASET CLOSE ALL. DATASET DISPLAY. ]) AT_CHECK([pspp -O format=csv dataset.pspp], [0], [dnl -Table: Open datasets. -Dataset +Table: Datasets unnamed dataset (active dataset) -Table: Open datasets. -Dataset +Table: Datasets unnamed dataset (active dataset) -Table: Open datasets. -Dataset +Table: Datasets this (active dataset) -Table: Open datasets. -Dataset +Table: Datasets unnamed dataset (active dataset) -Table: Open datasets. -Dataset +Table: Datasets this (active dataset) -Table: Open datasets. -Dataset +Table: Datasets unnamed dataset (active dataset) -Table: Open datasets. -Dataset +Table: Datasets unnamed dataset (active dataset) that theother yetanother -Table: Open datasets. -Dataset +Table: Datasets unnamed dataset (active dataset) -Table: Open datasets. -Dataset +Table: Datasets that theother this (active dataset) yetanother -Table: Open datasets. -Dataset +Table: Datasets unnamed dataset (active dataset) ]) AT_CLEANUP diff --git a/tests/language/data-io/get-data-psql.at b/tests/language/data-io/get-data-psql.at index b6bfc8f2cd..923c9bd3c7 100644 --- a/tests/language/data-io/get-data-psql.at +++ b/tests/language/data-io/get-data-psql.at @@ -189,9 +189,9 @@ timetz_zone,22,,Scale,Input,8,Right,F8.2,F8.2, Table: Data List bool,bytea,char,int8,int2,int4,numeric,text,oid,float4,float8,money,pbchar,varchar,date,time,timestamp,timestamptz,interval,interval_months,timetz,timetz_zone -.00,30,a ,.00,.00,.00,-2.560980E+002,this-long-text ,.00,.00,.00,$.01,a ,A ,01-JAN-2000,0:00:00,08-JAN-1999 04:05:06,08-JAN-1999 12:05:06,0 00:01:00,0,10:09:00,4.00 -. ,20,,. ,. ,. ,. ,,. ,. ,. ,. ,,,.,.,.,.,.,.,.,. @&t@ -1.00,31,b ,1.00,1.00,1.00,6.553500E+004,that-long-text ,.00,1.00,1.00,$1.23,b ,B ,10-JAN-1963,1:05:02,10-JAN-1963 23:58:00,10-JAN-1963 22:58:00,12 01:03:04,25,1:05:02,-7.00 +.00,30,a,.00,.00,.00,-2.560980E+002,this-long-text,.00,.00,.00,$.01,a,A,01-JAN-2000,0:00:00,08-JAN-1999 04:05:06,08-JAN-1999 12:05:06,0 00:01:00,0,10:09:00,4.00 +. ,,,. ,. ,. ,. ,,. ,. ,. ,. ,,,.,.,.,.,.,.,.,. @&t@ +1.00,31,b,1.00,1.00,1.00,6.553500E+004,that-long-text,.00,1.00,1.00,$1.23,b,B,10-JAN-1963,1:05:02,10-JAN-1963 23:58:00,10-JAN-1963 22:58:00,12 01:03:04,25,1:05:02,-7.00 ]) dnl Test query with empty result set. diff --git a/tests/language/data-io/get-data-spreadsheet.at b/tests/language/data-io/get-data-spreadsheet.at index 86ca455462..2bac423367 100644 --- a/tests/language/data-io/get-data-spreadsheet.at +++ b/tests/language/data-io/get-data-spreadsheet.at @@ -44,11 +44,11 @@ VAR003,3,F8.2,F8.2, Table: Data List VAR001,VAR002,VAR003 -.00,fred ,20.00 -1.00,11 ,21.00 -2.00,twelve ,22.00 -3.00,13 ,23.00 -4.00,14 ,24.00 +.00,fred,20.00 +1.00,11,21.00 +2.00,twelve,22.00 +3.00,13,23.00 +4.00,14,24.00 ]) AT_CLEANUP @@ -69,11 +69,11 @@ VAR001,3,F8.2,F8.2, Table: Data List V1,V2,VAR001 -.00,fred ,20.00 -1.00,11 ,21.00 -2.00,twelve ,22.00 -3.00,13 ,23.00 -4.00,14 ,24.00 +.00,fred,20.00 +1.00,11,21.00 +2.00,twelve,22.00 +3.00,13,23.00 +4.00,14,24.00 ]) AT_CLEANUP @@ -95,10 +95,10 @@ warning: Cannot convert the value in the spreadsheet cell C4 to format (F8.2): F Table: Data List name,id,height -fred ,.00,23.40 -bert ,1.00,.56 -charlie ,2.00,. @&t@ -dick ,3.00,-34.09 +fred,.00,23.40 +bert,1.00,.56 +charlie,2.00,. @&t@ +dick,3.00,-34.09 ]) AT_CLEANUP @@ -309,9 +309,9 @@ LIST. AT_CHECK([pspp -O format=csv gnum.sps], [0], [dnl Table: Data List VAR001,VAR002,VAR003 -3 ,4.00,5.00 -6 ,7.00,8.00 -9 ,10.00,11.00 +3,4.00,5.00 +6,7.00,8.00 +9,10.00,11.00 ]) diff --git a/tests/language/data-io/get-data-txt.at b/tests/language/data-io/get-data-txt.at index 25d7d6b93d..f1cd7615ec 100644 --- a/tests/language/data-io/get-data-txt.at +++ b/tests/language/data-io/get-data-txt.at @@ -213,10 +213,10 @@ AT_CHECK([pspp -o pspp.csv passwd.sps]) AT_CHECK([cat pspp.csv], [0], [dnl Table: Data List username,password,uid,gid,gecos,home,shell -root ,$1$nyeSP5gD$pDq/ ,0,0,",,, ",/root ,/bin/bash @&t@ -blp ,$1$BrP/pFg4$g7OG ,1000,1000,"Ben Pfaff,,, ",/home/blp ,/bin/bash @&t@ -john ,$1$JBuq/Fioq$g4A ,1001,1001,"John Darrington,,, ",/home/john ,/bin/bash @&t@ -jhs ,$1$D3li4hPL$88X1 ,1002,1002,"Jason Stover,,, ",/home/jhs ,/bin/csh @&t@ +root,$1$nyeSP5gD$pDq/,0,0,",,,",/root,/bin/bash +blp,$1$BrP/pFg4$g7OG,1000,1000,"Ben Pfaff,,,",/home/blp,/bin/bash +john,$1$JBuq/Fioq$g4A,1001,1001,"John Darrington,,,",/home/john,/bin/bash +jhs,$1$D3li4hPL$88X1,1002,1002,"Jason Stover,,,",/home/jhs,/bin/csh ]) AT_CLEANUP @@ -253,17 +253,17 @@ AT_CHECK([pspp -o pspp.csv cars.sps]) AT_CHECK([cat pspp.csv], [0], [dnl Table: Data List model,year,mileage,price,type,age -Civic ,2002,29883,15900,Si ,2 -Civic ,2003,13415,15900,EX ,1 -Civic ,1992,107000,3800,n/a ,12 -Accord ,2002,26613,17900,EX ,1 +Civic,2002,29883,15900,Si,2 +Civic,2003,13415,15900,EX,1 +Civic,1992,107000,3800,n/a,12 +Accord,2002,26613,17900,EX,1 Table: Data List model,year,mileage,price,type,age -Civic ,2002,29883,15900,Si ,2 -Civic ,2003,13415,15900,EX ,1 -Civic ,1992,107000,3800,n/a ,12 -Accord ,2002,26613,17900,EX ,1 +Civic,2002,29883,15900,Si,2 +Civic,2003,13415,15900,EX,1 +Civic,1992,107000,3800,n/a,12 +Accord,2002,26613,17900,EX,1 ]) AT_CLEANUP @@ -294,10 +294,10 @@ AT_CHECK([pspp -o pspp.csv pets.sps]) AT_CHECK([cat pspp.csv], [0], [dnl Table: Data List name,age,color,received,price,height,type -Rover ,4.5,Brown,12.02.2004,80.00,"1'4"" ",Dog @&t@ -Charlie ,. ,Gold ,05.04.2007,12.30,"3"" ",Fish @&t@ -Molly ,2.0,Black,12.12.2006,25.00,"5"" ",Cat @&t@ -Gilly ,. ,White,10.04.2007,10.00,"3"" ",Guinea Pig +Rover,4.5,Brown,12.02.2004,80.00,"1'4""",Dog +Charlie,. ,Gold,05.04.2007,12.30,"3""",Fish +Molly,2.0,Black,12.12.2006,25.00,"5""",Cat +Gilly,. ,White,10.04.2007,10.00,"3""",Guinea Pig ]) AT_CLEANUP dnl " (fixes Emacs highlighting) @@ -342,7 +342,7 @@ AT_CHECK([pspp -o pspp.csv get-data.sps]) AT_CHECK([cat pspp.csv], [0], [dnl Table: Data List s -é @&t@ +é ]) AT_CLEANUP @@ -388,9 +388,9 @@ list. AT_CHECK([pspp -O format=csv x.sps], [0], [dnl Table: Data List foo,title,last -1,this ,1 -2,that ,2 -3,other ,3 +1,this,1 +2,that,2 +3,other,3 ]) AT_CLEANUP diff --git a/tests/language/data-io/list.at b/tests/language/data-io/list.at index d495ddc515..c93437ae9b 100644 --- a/tests/language/data-io/list.at +++ b/tests/language/data-io/list.at @@ -118,8 +118,9 @@ LIST n. ]) AT_CHECK([pspp -o pspp.csv list.sps]) AT_CHECK([cat pspp.csv], [0], [dnl -Variable,Value,Label -s,a, +Table: Split Values +Variable,Value +s,a Table: Data List n @@ -127,15 +128,17 @@ n 2.00 3.00 -Variable,Value,Label -s,b, +Table: Split Values +Variable,Value +s,b Table: Data List n 1.00 -Variable,Value,Label -s,c, +Table: Split Values +Variable,Value +s,c Table: Data List n @@ -283,3 +286,34 @@ LIST. AT_CHECK([pspp -o pspp.csv list.sps], [1], [ignore]) AT_CLEANUP + +dnl This is an example from doc/tutorial.texi +dnl So if the results of this have to be changed in any way, +dnl make sure to update that file. +AT_SETUP([LIST tutorial example]) +AT_DATA([list.sps], [dnl +data list list /forename (A12) height. +begin data. +Ahmed 188 +Bertram 167 +Catherine 134.231 +David 109.1 +end data + +list /format=numbered. +]) +AT_CHECK([pspp -o pspp.csv -o pspp.txt list.sps]) +AT_CHECK([cat pspp.csv], [0], [dnl +Table: Reading free-form data from INLINE. +Variable,Format +forename,A12 +height,F8.0 + +Table: Data List +Case Number,forename,height +1,Ahmed,188.00 +2,Bertram,167.00 +3,Catherine,134.23 +4,David,109.10 +]) +AT_CLEANUP diff --git a/tests/language/data-io/matrix-data.at b/tests/language/data-io/matrix-data.at index 7d4c0f39fa..b590061efb 100644 --- a/tests/language/data-io/matrix-data.at +++ b/tests/language/data-io/matrix-data.at @@ -47,17 +47,17 @@ corr .17 .29 -.05 .20 .27 .20 .04 1.00 AT_CHECK([pspp -O format=csv matrix-data.pspp], [0], [dnl Table: Data List ROWTYPE_,VARNAME_,var01,var02,var03,var04,var05,var06,var07,var08 -mean ,,24.3000,5.4000,69.7000,20.1000,13.4000,2.7000,27.9000,3.7000 -STDDEV ,,5.7000,1.5000,23.5000,5.8000,2.8000,4.5000,5.4000,1.5000 -n ,,92.0000,92.0000,92.0000,92.0000,92.0000,92.0000,92.0000,92.0000 -corr ,var01,1.0000,.1800,-.2200,.3600,.2700,.3300,.5000,.1700 -corr ,var02,.1800,1.0000,-.1700,.3100,.1600,.1500,.2900,.2900 -corr ,var03,-.2200,-.1700,1.0000,-.1400,-.1200,-.1700,-.2000,-.0500 -corr ,var04,.3600,.3100,-.1400,1.0000,.2200,.2400,.3200,.2000 -corr ,var05,.2700,.1600,-.1200,.2200,1.0000,.2100,.1200,.2700 -corr ,var06,.3300,.1500,-.1700,.2400,.2100,1.0000,.3800,.2000 -corr ,var07,.5000,.2900,-.2000,.3200,.1200,.3800,1.0000,.0400 -corr ,var08,.1700,.2900,-.0500,.2000,.2700,.2000,.0400,1.0000 +mean,,24.3000,5.4000,69.7000,20.1000,13.4000,2.7000,27.9000,3.7000 +STDDEV,,5.7000,1.5000,23.5000,5.8000,2.8000,4.5000,5.4000,1.5000 +n,,92.0000,92.0000,92.0000,92.0000,92.0000,92.0000,92.0000,92.0000 +corr,var01,1.0000,.1800,-.2200,.3600,.2700,.3300,.5000,.1700 +corr,var02,.1800,1.0000,-.1700,.3100,.1600,.1500,.2900,.2900 +corr,var03,-.2200,-.1700,1.0000,-.1400,-.1200,-.1700,-.2000,-.0500 +corr,var04,.3600,.3100,-.1400,1.0000,.2200,.2400,.3200,.2000 +corr,var05,.2700,.1600,-.1200,.2200,1.0000,.2100,.1200,.2700 +corr,var06,.3300,.1500,-.1700,.2400,.2100,1.0000,.3800,.2000 +corr,var07,.5000,.2900,-.2000,.3200,.1200,.3800,1.0000,.0400 +corr,var08,.1700,.2900,-.0500,.2000,.2700,.2000,.0400,1.0000 ]) AT_CLEANUP @@ -86,13 +86,13 @@ list. AT_CHECK([pspp -O format=csv matrix-data.pspp], [0], [dnl Table: Data List ROWTYPE_,VARNAME_,var01,var02,var03,var04 -mean ,,34.0000,35.0000,36.0000,37.0000 -STDDEV ,,22.0000,11.0000,55.0000,66.0000 -N ,,100.0000,101.0000,102.0000,103.0000 -corr ,var01,1.0000,9.0000,8.0000,7.0000 -corr ,var02,9.0000,1.0000,6.0000,5.0000 -corr ,var03,8.0000,6.0000,1.0000,4.0000 -corr ,var04,7.0000,5.0000,4.0000,1.0000 +mean,,34.0000,35.0000,36.0000,37.0000 +STDDEV,,22.0000,11.0000,55.0000,66.0000 +N,,100.0000,101.0000,102.0000,103.0000 +corr,var01,1.0000,9.0000,8.0000,7.0000 +corr,var02,9.0000,1.0000,6.0000,5.0000 +corr,var03,8.0000,6.0000,1.0000,4.0000 +corr,var04,7.0000,5.0000,4.0000,1.0000 ]) AT_CLEANUP @@ -122,13 +122,13 @@ list. AT_CHECK([pspp -O format=csv matrix-data.pspp], [0], [dnl Table: Data List ROWTYPE_,VARNAME_,var01,var02,var03,var04 -MEAN ,,34.0000,35.0000,36.0000,37.0000 -STDDEV ,,22.0000,11.0000,55.0000,66.0000 -N ,,100.0000,101.0000,102.0000,103.0000 -CORR ,var01,1.0000,9.0000,8.0000,7.0000 -CORR ,var02,9.0000,1.0000,6.0000,5.0000 -CORR ,var03,8.0000,6.0000,1.0000,4.0000 -CORR ,var04,7.0000,5.0000,4.0000,1.0000 +MEAN,,34.0000,35.0000,36.0000,37.0000 +STDDEV,,22.0000,11.0000,55.0000,66.0000 +N,,100.0000,101.0000,102.0000,103.0000 +CORR,var01,1.0000,9.0000,8.0000,7.0000 +CORR,var02,9.0000,1.0000,6.0000,5.0000 +CORR,var03,8.0000,6.0000,1.0000,4.0000 +CORR,var04,7.0000,5.0000,4.0000,1.0000 ]) AT_CLEANUP @@ -156,13 +156,13 @@ list. AT_CHECK([pspp -O format=csv matrix-data.pspp], [0], [dnl Table: Data List ROWTYPE_,VARNAME_,var01,var02,var03,var04 -mean ,,34.0000,35.0000,36.0000,37.0000 -STDDEV ,,22.0000,11.0000,55.0000,66.0000 -n ,,100.0000,101.0000,102.0000,103.0000 -corr ,var01,1.0000,9.0000,8.0000,7.0000 -corr ,var02,9.0000,1.0000,6.0000,5.0000 -corr ,var03,8.0000,6.0000,1.0000,4.0000 -corr ,var04,7.0000,5.0000,4.0000,1.0000 +mean,,34.0000,35.0000,36.0000,37.0000 +STDDEV,,22.0000,11.0000,55.0000,66.0000 +n,,100.0000,101.0000,102.0000,103.0000 +corr,var01,1.0000,9.0000,8.0000,7.0000 +corr,var02,9.0000,1.0000,6.0000,5.0000 +corr,var03,8.0000,6.0000,1.0000,4.0000 +corr,var04,7.0000,5.0000,4.0000,1.0000 ]) AT_CLEANUP @@ -190,13 +190,13 @@ list. AT_CHECK([pspp -O format=csv matrix-data.pspp], [0], [dnl Table: Data List ROWTYPE_,VARNAME_,var01,var02,var03,var04 -mean ,,34.0000,35.0000,36.0000,37.0000 -STDDEV ,,22.0000,11.0000,55.0000,66.0000 -n ,,100.0000,101.0000,102.0000,103.0000 -corr ,var01,1.0000,9.0000,8.0000,7.0000 -corr ,var02,9.0000,1.0000,6.0000,5.0000 -corr ,var03,8.0000,6.0000,1.0000,4.0000 -corr ,var04,7.0000,5.0000,4.0000,1.0000 +mean,,34.0000,35.0000,36.0000,37.0000 +STDDEV,,22.0000,11.0000,55.0000,66.0000 +n,,100.0000,101.0000,102.0000,103.0000 +corr,var01,1.0000,9.0000,8.0000,7.0000 +corr,var02,9.0000,1.0000,6.0000,5.0000 +corr,var03,8.0000,6.0000,1.0000,4.0000 +corr,var04,7.0000,5.0000,4.0000,1.0000 ]) AT_CLEANUP @@ -244,18 +244,18 @@ var03,7,,Scale,Input,8,Right,F10.4,F10.4, Table: Data List s1,s2,ROWTYPE_,VARNAME_,var01,var02,var03 -8,0,mean ,,21.4000,5.0000,72.9000 -8,0,STDDEV ,,6.5000,1.6000,22.8000 -8,0,n ,,106.0000,106.0000,106.0000 -8,0,corr ,var01,1.0000,.4100,-.1600 -8,0,corr ,var02,.4100,1.0000,-.2200 -8,0,corr ,var03,-.1600,-.2200,1.0000 -8,1,mean ,,11.4000,1.0000,52.9000 -8,1,STDDEV ,,9.5000,8.6000,12.8000 -8,1,n ,,10.0000,11.0000,12.0000 -8,1,corr ,var01,1.0000,.5100,.3600 -8,1,corr ,var02,.5100,1.0000,-.4100 -8,1,corr ,var03,.3600,-.4100,1.0000 +8,0,mean,,21.4000,5.0000,72.9000 +8,0,STDDEV,,6.5000,1.6000,22.8000 +8,0,n,,106.0000,106.0000,106.0000 +8,0,corr,var01,1.0000,.4100,-.1600 +8,0,corr,var02,.4100,1.0000,-.2200 +8,0,corr,var03,-.1600,-.2200,1.0000 +8,1,mean,,11.4000,1.0000,52.9000 +8,1,STDDEV,,9.5000,8.6000,12.8000 +8,1,n,,10.0000,11.0000,12.0000 +8,1,corr,var01,1.0000,.5100,.3600 +8,1,corr,var02,.5100,1.0000,-.4100 +8,1,corr,var03,.3600,-.4100,1.0000 ]) AT_CLEANUP @@ -318,13 +318,13 @@ list. AT_CHECK([pspp -O format=csv matrix-data.pspp], [0], [dnl Table: Data List ROWTYPE_,VARNAME_,var01,var_two,variable_number_three,variableFour -mean ,,34.0000,35.0000,36.0000,37.0000 -STDDEV ,,22.0000,11.0000,55.0000,66.0000 -N ,,100.0000,101.0000,102.0000,103.0000 -corr ,var01,1.0000,9.0000,8.0000,7.0000 -corr ,var_two,9.0000,1.0000,6.0000,5.0000 -corr ,variable_number_three,8.0000,6.0000,1.0000,4.0000 -corr ,variableFour,7.0000,5.0000,4.0000,1.0000 +mean,,34.0000,35.0000,36.0000,37.0000 +STDDEV,,22.0000,11.0000,55.0000,66.0000 +N,,100.0000,101.0000,102.0000,103.0000 +corr,var01,1.0000,9.0000,8.0000,7.0000 +corr,var_two,9.0000,1.0000,6.0000,5.0000 +corr,variable_number_three,8.0000,6.0000,1.0000,4.0000 +corr,variableFour,7.0000,5.0000,4.0000,1.0000 ]) AT_CLEANUP @@ -366,9 +366,9 @@ factor /matrix = in (corr = *) AT_CHECK([pspp -O format=csv matrix-reader.pspp], [0], [dnl Table: Correlation Matrix ,,var02,var04,var06 -Correlations,var02,22.00,24.00,26.00 -,var04,42.00,44.00,46.00 -,var06,62.00,64.00,66.00 +Correlation,var02,22.000,24.000,26.000 +,var04,42.000,44.000,46.000 +,var06,62.000,64.000,66.000 Table: Component Matrix ,Component, @@ -472,13 +472,13 @@ AT_CHECK([pspp -O format=csv matrix-data.pspp], [0], [dnl Table: Data List ROWTYPE_,VARNAME_,var01,var02,var03,var04 -N ,,99.0000,99.0000,99.0000,99.0000 -mean ,,34.0000,35.0000,36.0000,37.0000 -STDDEV ,,22.0000,11.0000,55.0000,66.0000 -corr ,var01,1.0000,9.0000,8.0000,7.0000 -corr ,var02,9.0000,1.0000,6.0000,5.0000 -corr ,var03,8.0000,6.0000,1.0000,4.0000 -corr ,var04,7.0000,5.0000,4.0000,1.0000 +N,,99.0000,99.0000,99.0000,99.0000 +mean,,34.0000,35.0000,36.0000,37.0000 +STDDEV,,22.0000,11.0000,55.0000,66.0000 +corr,var01,1.0000,9.0000,8.0000,7.0000 +corr,var02,9.0000,1.0000,6.0000,5.0000 +corr,var03,8.0000,6.0000,1.0000,4.0000 +corr,var04,7.0000,5.0000,4.0000,1.0000 ]) AT_CLEANUP diff --git a/tests/language/data-io/save.at b/tests/language/data-io/save.at index a2c005a93d..fd907d7a84 100644 --- a/tests/language/data-io/save.at +++ b/tests/language/data-io/save.at @@ -67,7 +67,7 @@ AT_CHECK([pspp -O format=csv save.pspp]) AT_CHECK([pspp -O format=csv get.pspp], [0], [dnl Table: Data List number,time,date,datetime,string,filter -. ,-0 05:17,10/31/2010,09-APR-2008 09:29:00,xxx ,1 -1.625,0 12:00:00,.,.,xyzzy ,1 +. ,-0 05:17,10/31/2010,09-APR-2008 09:29:00,xxx,1 +1.625,0 12:00:00,.,.,xyzzy,1 ]) AT_CLEANUP diff --git a/tests/language/dictionary/attributes.at b/tests/language/dictionary/attributes.at index e3d63657d6..f0407b6369 100644 --- a/tests/language/dictionary/attributes.at +++ b/tests/language/dictionary/attributes.at @@ -52,7 +52,7 @@ DISPLAY ATTRIBUTES. ]]) AT_CHECK([pspp -O format=csv save-attrs.pspp], [0], [[Table: Variable and Dataset Attributes -Variable,Name,Value +Variable and Name,,Value (dataset),array[1],array element 1 ,array[2],array element 2 ,key,value @@ -64,7 +64,7 @@ c,QuestionWording,X or Y? ]]) AT_CHECK([pspp -O format=csv get-attrs.pspp], [0], [dnl Table: Variable and Dataset Attributes -Variable,Name,Value +Variable and Name,,Value (dataset),array,array element 2 ,key,value b,ValidationRule,a * b > 3 diff --git a/tests/language/dictionary/mrsets.at b/tests/language/dictionary/mrsets.at index 49d9c7b215..a520a41370 100644 --- a/tests/language/dictionary/mrsets.at +++ b/tests/language/dictionary/mrsets.at @@ -82,56 +82,31 @@ mrsets.sps:38: warning: MRSETS: MDGROUP subcommand for group $d specifies LABELS "mrsets.sps:42: warning: MRSETS: Variables specified on MCGROUP should have the same categories, but a and c (and possibly others) in multiple category group $f have different value labels for value b." ]) -m4_define([MRSETS_DISPLAY_OUTPUT], - [Table: Multiple Response Sets -Name,Variables,Details -$a,"w +m4_define([MRSETS_DISPLAY_OUTPUT], [dnl +Table: Multiple Response Sets +Name,Label,Encoding,Counted Value,Member Variables +$a,First multiple dichotomy group,Dichotomies,5,"w x y -z -","Multiple dichotomy set -Label: First multiple dichotomy group -Label source: Provided by user -Counted value: 5 -Category label source: Variable labels -" -$b,"z -y -","Multiple dichotomy set -Counted value: 123 -Category label source: Value labels of counted value -" -$c,"w +z" +$b,,Dichotomies,123,"z +y" +$c,duplicate variable label,Dichotomies,1,"w x y -z -","Multiple dichotomy set -Label: duplicate variable label -Label source: First variable label among variables -Counted value: 1 -Category label source: Value labels of counted value -" -$d,"a +z" +$d,,Dichotomies,c,"a b c -d -","Multiple dichotomy set -Counted value: `c' -Category label source: Variable labels -" -$e,"w +d" +$e,First multiple category group,Categories,,"w x y -z -","Multiple category set -Label: First multiple category group -" -$f,"a +z" +$f,,Categories,,"a b c -d -","Multiple category set -" +d" ]) AT_SETUP([MRSETS add, display, delete]) @@ -145,61 +120,60 @@ AT_DATA([mrsets.sps], /DELETE NAME=ALL /DISPLAY NAME=ALL. ]]) -AT_CHECK([pspp -O format=csv mrsets.sps], [0], +AT_CHECK([pspp -o - -O format=csv -o mrsets.csv -o mrsets.txt -o mrsets.pdf mrsets.sps], [0], [DEFINE_MRSETS_OUTPUT Table: Multiple Response Sets -Name,Variables,Details -$a,"w +Name,Label,Encoding,Counted Value,Member Variables +$a,First multiple dichotomy group,Dichotomies,5,"w x y -z -","Multiple dichotomy set -Label: First multiple dichotomy group -Label source: Provided by user -Counted value: 5 -Category label source: Variable labels -" +z" -MRSETS_DISPLAY_OUTPUT Table: Multiple Response Sets -Name,Variables,Details -$a,"w +Name,Label,Encoding,Counted Value,Member Variables +$a,First multiple dichotomy group,Dichotomies,5,"w +x +y +z" +$b,,Dichotomies,123,"z +y" +$c,duplicate variable label,Dichotomies,1,"w +x +y +z" +$d,,Dichotomies,c,"a +b +c +d" +$e,First multiple category group,Categories,,"w x y -z -","Multiple dichotomy set -Label: First multiple dichotomy group -Label source: Provided by user -Counted value: 5 -Category label source: Variable labels -" -$b,"z +z" +$f,,Categories,,"a +b +c +d" + +Table: Multiple Response Sets +Name,Label,Encoding,Counted Value,Member Variables +$a,First multiple dichotomy group,Dichotomies,5,"w +x y -","Multiple dichotomy set -Counted value: 123 -Category label source: Value labels of counted value -" -$d,"a +z" +$b,,Dichotomies,123,"z +y" +$d,,Dichotomies,c,"a b c -d -","Multiple dichotomy set -Counted value: `c' -Category label source: Variable labels -" -$e,"w +d" +$e,First multiple category group,Categories,,"w x y -z -","Multiple category set -Label: First multiple category group -" -$f,"a +z" +$f,,Categories,,"a b c -d -","Multiple category set -" +d" mrsets.sps:50: note: MRSETS: The active dataset dictionary does not contain any multiple response sets. ]) diff --git a/tests/language/dictionary/split-file.at b/tests/language/dictionary/split-file.at index 2dc9a2e506..427bf2d993 100644 --- a/tests/language/dictionary/split-file.at +++ b/tests/language/dictionary/split-file.at @@ -41,8 +41,9 @@ list. ]) AT_CHECK([pspp -o pspp.csv split-file.sps]) AT_CHECK([cat pspp.csv], [0], [dnl -Variable,Value,Label -X,1, +Table: Split Values +Variable,Value +X,1 Table: Data List X,Y @@ -53,8 +54,9 @@ X,Y 1,5 1,4 -Variable,Value,Label -X,2, +Table: Split Values +Variable,Value +X,2 Table: Data List X,Y diff --git a/tests/language/dictionary/sys-file-info.at b/tests/language/dictionary/sys-file-info.at index d71e813743..11f5d4e9f8 100644 --- a/tests/language/dictionary/sys-file-info.at +++ b/tests/language/dictionary/sys-file-info.at @@ -30,24 +30,25 @@ sysfile info file='pro.sav'. ]) AT_CHECK([pspp -o pspp.csv sysfile-info.sps]) AT_CHECK( - [sed -e '/^Created:,/d' \ - -e '/^Endian:,/d' \ - -e '/^Integer Format:,/d' \ - -e '/^Real Format:,/d' \ - -e '/^Encoding:,/d' pspp.csv], + [sed -e '/^Created,/d' \ + -e '/^Endian,/d' \ + -e '/^Integer Format,/d' \ + -e '/^Real Format,/d' \ + -e '/^Encoding,/d' pspp.csv], [0], [dnl Table: Reading free-form data from INLINE. Variable,Format x,F8.0 name,A10 -File:,pro.sav -Label:,No label. -Variables:,2 -Cases:,3 -Type:,SPSS System File -Weight:,Not weighted. -Compression:,SAV +Table: File Information +File,pro.sav +Label, +Variables,2 +Cases,3 +Type,SPSS System File +Weight,Not weighted +Compression,SAV Table: Variables Name,Position,Label,Measurement Level,Role,Width,Alignment,Print Format,Write Format,Missing Values @@ -70,9 +71,11 @@ FILE LABEL 'foo bar baz quux'. DISPLAY FILE LABEL. ]) AT_CHECK([pspp -O format=csv display.sps], [0], [dnl -The active dataset does not have a file label. +Table: File Label +Label,(none) -File label: foo bar baz quux +Table: File Label +Label,foo bar baz quux ]) AT_CLEANUP diff --git a/tests/language/dictionary/value-labels.at b/tests/language/dictionary/value-labels.at index b7e6eaf8d7..1ddabf972a 100644 --- a/tests/language/dictionary/value-labels.at +++ b/tests/language/dictionary/value-labels.at @@ -32,7 +32,7 @@ ad,1,,Scale,Input,8,Right,ADATE10,ADATE10, dt,2,,Scale,Input,8,Right,DATETIME20.0,DATETIME20.0, Table: Value Labels -Variable,Value,Label +Variable Value,,Label ad,07/10/1982,label 1 ,01/02/1993,label 2 ,05/04/2003,label 3 @@ -52,24 +52,25 @@ END DATA. DISPLAY DICTIONARY. FREQUENCIES x/STAT=NONE. ]) -AT_CHECK([pspp -O format=csv value-labels.sps], [0], [dnl +AT_CHECK([pspp -o pspp.csv -o pspp.txt value-labels.sps]) +AT_CHECK([cat pspp.csv], [0], [dnl Table: Variables Name,Position,Label,Measurement Level,Role,Width,Alignment,Print Format,Write Format,Missing Values x,1,,Scale,Input,8,Right,F8.2,F8.2, Table: Value Labels -Variable,Value,Label +Variable Value,,Label x,1.00,one ,2.00,first line\nsecond line ,3.00,three Table: x -Value Label,Value,Frequency,Percent,Valid Percent,Cum Percent -one,1.00,1,33.33,33.33,33.33 -"first line -second line",2.00,1,33.33,33.33,66.67 -three,3.00,1,33.33,33.33,100.00 -Total,,3,100.0,100.0, +,,Frequency,Percent,Valid Percent,Cumulative Percent +Valid,one,1,33.3%,33.3%,33.3% +,"first line +second line",1,33.3%,33.3%,66.7% +,three,1,33.3%,33.3%,100.0% +Total,,3,100.0%,, ]) AT_CLEANUP @@ -90,24 +91,25 @@ GET FILE='value-labels.sav'. DISPLAY DICTIONARY. FREQUENCIES x/STAT=NONE. ]) -AT_CHECK([pspp -O format=csv get.sps], [0], [dnl +AT_CHECK([pspp -o pspp.csv -o pspp.txt get.sps]) +AT_CHECK([cat pspp.csv], [0], [dnl Table: Variables Name,Position,Label,Measurement Level,Role,Width,Alignment,Print Format,Write Format,Missing Values x,1,,Scale,Input,8,Right,F8.2,F8.2, Table: Value Labels -Variable,Value,Label +Variable Value,,Label x,1.00,one ,2.00,first line\nsecond line ,3.00,three Table: x -Value Label,Value,Frequency,Percent,Valid Percent,Cum Percent -one,1.00,1,33.33,33.33,33.33 -"first line -second line",2.00,1,33.33,33.33,66.67 -three,3.00,1,33.33,33.33,100.00 -Total,,3,100.0,100.0, +,,Frequency,Percent,Valid Percent,Cumulative Percent +Valid,one,1,33.3%,33.3%,33.3% +,"first line +second line",1,33.3%,33.3%,66.7% +,three,1,33.3%,33.3%,100.0% +Total,,3,100.0%,, ]) AT_CLEANUP diff --git a/tests/language/dictionary/variable-display.at b/tests/language/dictionary/variable-display.at index 5daa3c1bbf..b586f64d56 100644 --- a/tests/language/dictionary/variable-display.at +++ b/tests/language/dictionary/variable-display.at @@ -75,36 +75,49 @@ SET TVARS=BOTH. DESCRIPTIVES ALL. ]) -AT_CHECK([pspp -O format=csv var-labels.sps], [0],[dnl -Table: Valid cases = 4; cases with missing value(s) = 0. -Variable,N,Mean,Std Dev,Minimum,Maximum +AT_CHECK([pspp -o pspp.csv -o pspp.txt var-labels.sps]) +AT_CHECK([cat pspp.csv], [0],[dnl +Table: Descriptive Statistics +,N,Mean,Std Dev,Minimum,Maximum x,4,2.50,1.29,1.00,4.00 y,4,250.00,129.10,100.00,400.00 +Valid N (listwise),4,,,, +Missing N (listwise),0,,,, -Table: Valid cases = 4; cases with missing value(s) = 0. -Variable,N,Mean,Std Dev,Minimum,Maximum +Table: Descriptive Statistics +,N,Mean,Std Dev,Minimum,Maximum x,4,2.50,1.29,1.00,4.00 y,4,250.00,129.10,100.00,400.00 +Valid N (listwise),4,,,, +Missing N (listwise),0,,,, -Table: Valid cases = 4; cases with missing value(s) = 0. -Variable,N,Mean,Std Dev,Minimum,Maximum +Table: Descriptive Statistics +,N,Mean,Std Dev,Minimum,Maximum x,4,2.50,1.29,1.00,4.00 y,4,250.00,129.10,100.00,400.00 +Valid N (listwise),4,,,, +Missing N (listwise),0,,,, -Table: Valid cases = 4; cases with missing value(s) = 0. -Variable,N,Mean,Std Dev,Minimum,Maximum +Table: Descriptive Statistics +,N,Mean,Std Dev,Minimum,Maximum x,4,2.50,1.29,1.00,4.00 y,4,250.00,129.10,100.00,400.00 +Valid N (listwise),4,,,, +Missing N (listwise),0,,,, -Table: Valid cases = 4; cases with missing value(s) = 0. -Variable,N,Mean,Std Dev,Minimum,Maximum +Table: Descriptive Statistics +,N,Mean,Std Dev,Minimum,Maximum foo,4,2.50,1.29,1.00,4.00 bar,4,250.00,129.10,100.00,400.00 - -Table: Valid cases = 4; cases with missing value(s) = 0. -Variable,N,Mean,Std Dev,Minimum,Maximum -foo (x),4,2.50,1.29,1.00,4.00 -bar (y),4,250.00,129.10,100.00,400.00 +Valid N (listwise),4,,,, +Missing N (listwise),0,,,, + +Table: Descriptive Statistics +,N,Mean,Std Dev,Minimum,Maximum +x foo,4,2.50,1.29,1.00,4.00 +y bar,4,250.00,129.10,100.00,400.00 +Valid N (listwise),4,,,, +Missing N (listwise),0,,,, ]) AT_CLEANUP diff --git a/tests/language/dictionary/vector.at b/tests/language/dictionary/vector.at index 67fdee495f..1c274402cd 100644 --- a/tests/language/dictionary/vector.at +++ b/tests/language/dictionary/vector.at @@ -24,7 +24,8 @@ display vector. ]) AT_CHECK([pspp -o pspp.csv vector.sps]) AT_CHECK([cat pspp.csv], [0], [dnl -Vector,Position,Variable,Print Format +Table: Vectors +Vector and Position,,Variable,Print Format v,1,v1,F8.2 ,2,v2,F8.2 ,3,v3,F8.2 @@ -41,7 +42,8 @@ display vector. ]) AT_CHECK([pspp -o pspp.csv vector.sps]) AT_CHECK([cat pspp.csv], [0], [dnl -Vector,Position,Variable,Print Format +Table: Vectors +Vector and Position,,Variable,Print Format #vec,1,#vec1,COMMA10.2 ,2,#vec2,COMMA10.2 ,3,#vec3,COMMA10.2 @@ -62,7 +64,8 @@ display vector. ]) AT_CHECK([pspp -o pspp.csv vector.sps]) AT_CHECK([cat pspp.csv], [0], [dnl -Vector,Position,Variable,Print Format +Table: Vectors +Vector and Position,,Variable,Print Format x,1,x1,F8.2 ,2,x2,F8.2 ,3,x3,F8.2 @@ -81,7 +84,8 @@ display vector. ]) AT_CHECK([pspp -o pspp.csv vector.sps]) AT_CHECK([cat pspp.csv], [0], [dnl -Vector,Position,Variable,Print Format +Table: Vectors +Vector and Position,,Variable,Print Format a,1,u,F1.0 ,2,w,F1.0 ,3,x,F1.0 diff --git a/tests/language/dictionary/weight.at b/tests/language/dictionary/weight.at index a0f3c53cd6..92de2177b2 100644 --- a/tests/language/dictionary/weight.at +++ b/tests/language/dictionary/weight.at @@ -79,79 +79,27 @@ weight by BVAR. descriptives AVAR /statistics all /format serial. frequencies AVAR /statistics all. ]) -AT_CHECK([pspp -o pspp.csv weight.sps]) +AT_CHECK([pspp -o pspp.csv -o pspp.txt weight.sps]) AT_CHECK([cat pspp.csv], [0], [dnl Table: Reading 1 record from `weight.txt'. Variable,Record,Columns,Format AVAR,1,1- 5,F5.0 BVAR,1,6- 10,F5.0 -Table: Valid cases = 730; cases with missing value(s) = 0. -Variable,Valid N,Missing N,Mean,S.E. Mean,Std Dev,Variance,Kurtosis,S.E. Kurt,Skewness,S.E. Skew,Range,Minimum,Maximum,Sum -AVAR,730,0,31.515,.405,10.937,119.608,2.411,.181,1.345,.090,76.000,18.000,94.000,23006.000 +Table: Descriptive Statistics +,N,Mean,S.E. Mean,Std Dev,Variance,Kurtosis,S.E. Kurt,Skewness,S.E. Skew,Range,Minimum,Maximum,Sum +AVAR,730,31.515,.405,10.937,119.608,2.411,.181,1.345,.090,76.000,18,94,23006.00 +Valid N (listwise),730,,,,,,,,,,,, +Missing N (listwise),0,,,,,,,,,,,, -Table: AVAR -Value Label,Value,Frequency,Percent,Valid Percent,Cum Percent -,18,1,.137,.137,.137 -,19,7,.959,.959,1.096 -,20,26,3.562,3.562,4.658 -,21,76,10.411,10.411,15.068 -,22,57,7.808,7.808,22.877 -,23,58,7.945,7.945,30.822 -,24,38,5.205,5.205,36.027 -,25,38,5.205,5.205,41.233 -,26,30,4.110,4.110,45.342 -,27,21,2.877,2.877,48.219 -,28,23,3.151,3.151,51.370 -,29,24,3.288,3.288,54.658 -,30,23,3.151,3.151,57.808 -,31,14,1.918,1.918,59.726 -,32,21,2.877,2.877,62.603 -,33,21,2.877,2.877,65.479 -,34,14,1.918,1.918,67.397 -,35,14,1.918,1.918,69.315 -,36,17,2.329,2.329,71.644 -,37,11,1.507,1.507,73.151 -,38,16,2.192,2.192,75.342 -,39,14,1.918,1.918,77.260 -,40,15,2.055,2.055,79.315 -,41,14,1.918,1.918,81.233 -,42,14,1.918,1.918,83.151 -,43,8,1.096,1.096,84.247 -,44,15,2.055,2.055,86.301 -,45,10,1.370,1.370,87.671 -,46,12,1.644,1.644,89.315 -,47,13,1.781,1.781,91.096 -,48,13,1.781,1.781,92.877 -,49,5,.685,.685,93.562 -,50,5,.685,.685,94.247 -,51,3,.411,.411,94.658 -,52,7,.959,.959,95.616 -,53,6,.822,.822,96.438 -,54,2,.274,.274,96.712 -,55,2,.274,.274,96.986 -,56,2,.274,.274,97.260 -,57,3,.411,.411,97.671 -,58,1,.137,.137,97.808 -,59,3,.411,.411,98.219 -,61,1,.137,.137,98.356 -,62,3,.411,.411,98.767 -,63,1,.137,.137,98.904 -,64,1,.137,.137,99.041 -,65,2,.274,.274,99.315 -,70,1,.137,.137,99.452 -,78,1,.137,.137,99.589 -,79,1,.137,.137,99.726 -,80,1,.137,.137,99.863 -,94,1,.137,.137,100.000 -Total,,730,100.0,100.0, - -Table: AVAR +Table: Statistics +,,AVAR N,Valid,730 ,Missing,0 Mean,,31.515 S.E. Mean,,.405 -Mode,,21.000 +Median,,28.000 +Mode,,21 Std Dev,,10.937 Variance,,119.608 Kurtosis,,2.411 @@ -159,9 +107,64 @@ S.E. Kurt,,.181 Skewness,,1.345 S.E. Skew,,.090 Range,,76.000 -Minimum,,18.000 -Maximum,,94.000 -Sum,,23006.000 -Percentiles,50 (Median),28 +Minimum,,18 +Maximum,,94 +Sum,,23006.00 + +Table: AVAR +,,Frequency,Percent,Valid Percent,Cumulative Percent +Valid,18,1,.1%,.1%,.1% +,19,7,1.0%,1.0%,1.1% +,20,26,3.6%,3.6%,4.7% +,21,76,10.4%,10.4%,15.1% +,22,57,7.8%,7.8%,22.9% +,23,58,7.9%,7.9%,30.8% +,24,38,5.2%,5.2%,36.0% +,25,38,5.2%,5.2%,41.2% +,26,30,4.1%,4.1%,45.3% +,27,21,2.9%,2.9%,48.2% +,28,23,3.2%,3.2%,51.4% +,29,24,3.3%,3.3%,54.7% +,30,23,3.2%,3.2%,57.8% +,31,14,1.9%,1.9%,59.7% +,32,21,2.9%,2.9%,62.6% +,33,21,2.9%,2.9%,65.5% +,34,14,1.9%,1.9%,67.4% +,35,14,1.9%,1.9%,69.3% +,36,17,2.3%,2.3%,71.6% +,37,11,1.5%,1.5%,73.2% +,38,16,2.2%,2.2%,75.3% +,39,14,1.9%,1.9%,77.3% +,40,15,2.1%,2.1%,79.3% +,41,14,1.9%,1.9%,81.2% +,42,14,1.9%,1.9%,83.2% +,43,8,1.1%,1.1%,84.2% +,44,15,2.1%,2.1%,86.3% +,45,10,1.4%,1.4%,87.7% +,46,12,1.6%,1.6%,89.3% +,47,13,1.8%,1.8%,91.1% +,48,13,1.8%,1.8%,92.9% +,49,5,.7%,.7%,93.6% +,50,5,.7%,.7%,94.2% +,51,3,.4%,.4%,94.7% +,52,7,1.0%,1.0%,95.6% +,53,6,.8%,.8%,96.4% +,54,2,.3%,.3%,96.7% +,55,2,.3%,.3%,97.0% +,56,2,.3%,.3%,97.3% +,57,3,.4%,.4%,97.7% +,58,1,.1%,.1%,97.8% +,59,3,.4%,.4%,98.2% +,61,1,.1%,.1%,98.4% +,62,3,.4%,.4%,98.8% +,63,1,.1%,.1%,98.9% +,64,1,.1%,.1%,99.0% +,65,2,.3%,.3%,99.3% +,70,1,.1%,.1%,99.5% +,78,1,.1%,.1%,99.6% +,79,1,.1%,.1%,99.7% +,80,1,.1%,.1%,99.9% +,94,1,.1%,.1%,100.0% +Total,,730,100.0%,, ]) AT_CLEANUP diff --git a/tests/language/expressions/evaluate.at b/tests/language/expressions/evaluate.at index e2f70e09d3..76e11d885e 100644 --- a/tests/language/expressions/evaluate.at +++ b/tests/language/expressions/evaluate.at @@ -2120,10 +2120,10 @@ Table: Data List n,s,nlabel,slabel .,,, 0,a,Very dissa,Wouldn't b -1,b,Dissatisfi,Unhappy @&t@ -2,c,Neutral ,Bored @&t@ -3,d,Satisfied ,Satiated @&t@ -4,e,Very satis,Elated @&t@ +1,b,Dissatisfi,Unhappy +2,c,Neutral,Bored +3,d,Satisfied,Satiated +4,e,Very satis,Elated 5,f,, 6,g,, ]) diff --git a/tests/language/lexer/variable-parser.at b/tests/language/lexer/variable-parser.at index a7f792fb2e..a1682a9083 100644 --- a/tests/language/lexer/variable-parser.at +++ b/tests/language/lexer/variable-parser.at @@ -45,22 +45,22 @@ Table: Data List AlphaBetaGamma,B,X,Yabbadabbadoo 2.00,3.00,4.00,5.00 -Table: Summary. +Table: Summary ,Cases,,,,, ,Valid,,Missing,,Total, ,N,Percent,N,Percent,N,Percent -X * Yabbadabbadoo,1,100.0%,0,0.0%,1,100.0% +X × Yabbadabbadoo,1,100.0%,0,.0%,1,100.0% -Table: X * Yabbadabbadoo [[count]]. -,Yabbadabbadoo,,,,,,, -X,1.00,2.00,3.00,4.00,5.00,6.00,7.00,Total -1.00,.00,.00,.00,.00,.00,.00,.00,.00 -2.00,.00,.00,.00,.00,.00,.00,.00,.00 -3.00,.00,.00,.00,.00,.00,.00,.00,.00 -4.00,.00,.00,.00,.00,1.00,.00,.00,1.00 -5.00,.00,.00,.00,.00,.00,.00,.00,.00 -6.00,.00,.00,.00,.00,.00,.00,.00,.00 -7.00,.00,.00,.00,.00,.00,.00,.00,.00 -Total,.00,.00,.00,.00,1.00,.00,.00,1.00 +Table: X × Yabbadabbadoo +,,,Yabbadabbadoo,,,,,,,Total +,,,1.00,2.00,3.00,4.00,5.00,6.00,7.00, +X,1.00,Count,0,0,0,0,0,0,0,0 +,2.00,,0,0,0,0,0,0,0,0 +,3.00,,0,0,0,0,0,0,0,0 +,4.00,,0,0,0,0,1,0,0,1 +,5.00,,0,0,0,0,0,0,0,0 +,6.00,,0,0,0,0,0,0,0,0 +,7.00,,0,0,0,0,0,0,0,0 +Total,,,0,0,0,0,1,0,0,1 ]) AT_CLEANUP diff --git a/tests/language/stats/aggregate.at b/tests/language/stats/aggregate.at index 976899b233..590a63f200 100644 --- a/tests/language/stats/aggregate.at +++ b/tests/language/stats/aggregate.at @@ -208,8 +208,8 @@ Y,A25 Table: Data List X,Y -87.34,bar @&t@ -87.50,foo @&t@ +87.34,bar +87.50,foo ]) AT_CLEANUP diff --git a/tests/language/stats/autorecode.at b/tests/language/stats/autorecode.at index fdd7c33e6b..33a1fd26de 100644 --- a/tests/language/stats/autorecode.at +++ b/tests/language/stats/autorecode.at @@ -95,13 +95,13 @@ display dictionary. AT_CHECK([pspp -O format=csv ar.sps], [0], [Table: Data List s,x,new -widgets ,1.00,4.00 -thingummies ,2.00,3.00 -oojars ,3.00,1.00 -widgets ,4.00,4.00 -oojars ,5.00,1.00 -thingummies ,6.00,3.00 -oojimiflips ,7.00,2.00 +widgets,1.00,4.00 +thingummies,2.00,3.00 +oojars,3.00,1.00 +widgets,4.00,4.00 +oojars,5.00,1.00 +thingummies,6.00,3.00 +oojimiflips,7.00,2.00 Table: Variables Name,Position,Label,Measurement Level,Role,Width,Alignment,Print Format,Write Format,Missing Values @@ -110,7 +110,7 @@ x,2,,Scale,Input,8,Right,F8.2,F8.2, new,3,,Scale,Input,8,Right,F8.2,F8.2, Table: Value Labels -Variable,Value,Label +Variable Value,,Label new,1.00,oojars ,2.00,oojimiflips ,3.00,thingummies @@ -210,10 +210,10 @@ AT_CHECK([pspp -O format=csv ar-strings.sps], [0], [dnl Table: Data List a,b,x,y -one ,nine ,5.00,3.00 -two ,ten ,8.00,6.00 -three ,eleven,7.00,1.00 -four ,nought,2.00,4.00 +one,nine,5.00,3.00 +two,ten,8.00,6.00 +three,eleven,7.00,1.00 +four,nought,2.00,4.00 ]) AT_CLEANUP diff --git a/tests/language/stats/correlations.at b/tests/language/stats/correlations.at index 12819835d3..df00e67723 100644 --- a/tests/language/stats/correlations.at +++ b/tests/language/stats/correlations.at @@ -49,19 +49,22 @@ correlations /missing = pairwise . ]) -AT_CHECK([pspp -o pspp.csv correlations.sps]) -AT_CHECK([cat pspp.csv], [0], [dnl -Table: Correlations +AT_CHECK([pspp -o pspp.csv -o pspp.txt correlations.sps]) +AT_CHECK([cat pspp.csv], [0], +[[Table: Correlations ,,foo,bar,wiz,bang -foo,Pearson Correlation,1.000,.802,.890,-.308 +foo,Pearson Correlation,1.000,.802,.890[a],-.308 ,Sig. (2-tailed),,.055,.017,.553 bar,Pearson Correlation,.802,1.000,.519,.118 ,Sig. (2-tailed),.055,,.291,.824 -wiz,Pearson Correlation,.890,.519,1.000,-.344 +wiz,Pearson Correlation,.890[a],.519,1.000,-.344 ,Sig. (2-tailed),.017,.291,,.505 bang,Pearson Correlation,-.308,.118,-.344,1.000 ,Sig. (2-tailed),.553,.824,.505, +Footnotes: +a,Significant at .05 level + Table: Correlations ,,bar,wiz bar,Pearson Correlation,1.000,.497 @@ -71,19 +74,22 @@ wiz,Pearson Correlation,.497,1.000 Table: Correlations ,,foo,bar,wiz,bang -foo,Pearson Correlation,1.000,.805,.883,-.308 +foo,Pearson Correlation,1.000,.805[a],.883[a],-.308 ,Sig. (2-tailed),,.029,.008,.553 ,N,7,7,7,6 -bar,Pearson Correlation,.805,1.000,.497,.164 +bar,Pearson Correlation,.805[a],1.000,.497,.164 ,Sig. (2-tailed),.029,,.210,.725 ,N,7,8,8,7 -wiz,Pearson Correlation,.883,.497,1.000,-.337 +wiz,Pearson Correlation,.883[a],.497,1.000,-.337 ,Sig. (2-tailed),.008,.210,,.460 ,N,7,8,8,7 bang,Pearson Correlation,-.308,.164,-.337,1.000 ,Sig. (2-tailed),.553,.725,.460, ,N,6,7,7,7 -]) + +Footnotes: +a,Significant at .05 level +]]) AT_CLEANUP AT_SETUP([CORRELATIONS -- weighted]) @@ -192,15 +198,15 @@ AT_CHECK([pspp -o pspp.csv correlations.sps]) AT_CHECK([sed '/a,Pearson/,$s/,\([[^,]]*\),.*/,\1,.../' pspp.csv], [0], [dnl Table: Descriptive Statistics ,Mean,Std. Deviation,N -a,24.00,8.93,14.00 -f,4.73,.85,12.00 -b,14.50,6.41,14.00 -c,21.71,4.98,14.00 -g,24.86,6.09,14.00 -h,23.57,6.30,14.00 -i,27.79,6.73,14.00 -e,27.21,4.95,14.00 -d,27.93,5.23,14.00 +a,24.00,8.93,14 +f,4.73,.85,12 +b,14.50,6.41,14 +c,21.71,4.98,14 +g,24.86,6.09,14 +h,23.57,6.30,14 +i,27.79,6.73,14 +e,27.21,4.95,14 +d,27.93,5.23,14 Table: Correlations ,,c,g,h,i,e,d @@ -222,6 +228,7 @@ dnl Checks for bug #40661 AT_SETUP([CORRELATIONS -- incorrect subtable selection]) AT_DATA([correlations.sps], [dnl set format = F12.4. +OUTPUT MODIFY /SELECT TABLES /TABLECELLS SELECT = [[CORRELATIONS]] FORMAT=F12.4. set decimal = dot. data list notable list /var1 var2 var3 var4 var5 *. begin data. @@ -337,31 +344,38 @@ CORRELATION ]) -AT_CHECK([pspp -O format=csv correlations.sps], [0], -[Table: Correlations +AT_CHECK([pspp -o pspp.csv -o pspp.txt correlations.sps]) +AT_CHECK([cat pspp.csv], [0], +[[Table: Correlations ,,var4,var5 -var1,Pearson Correlation,.5693,-.0519 +var1,Pearson Correlation,.5693[a],-.0519 ,Sig. (2-tailed),.000,.623 ,N,93,92 -var2,Pearson Correlation,.3792,-.0407 +var2,Pearson Correlation,.3792[a],-.0407 ,Sig. (2-tailed),.000,.698 ,N,95,93 -var3,Pearson Correlation,.3699,-.0543 +var3,Pearson Correlation,.3699[a],-.0543 ,Sig. (2-tailed),.000,.603 ,N,95,94 +Footnotes: +a,Significant at .05 level + Table: Correlations ,,var1,var2 -var3,Pearson Correlation,.6964,.5615 +var3,Pearson Correlation,.6964[a],.5615[a] ,Sig. (2-tailed),.000,.000 ,N,96,97 -var4,Pearson Correlation,.5693,.3792 +var4,Pearson Correlation,.5693[a],.3792[a] ,Sig. (2-tailed),.000,.000 ,N,93,95 var5,Pearson Correlation,-.0519,-.0407 ,Sig. (2-tailed),.623,.698 ,N,92,93 -]) + +Footnotes: +a,Significant at .05 level +]]) AT_CLEANUP diff --git a/tests/language/stats/crosstabs.at b/tests/language/stats/crosstabs.at index 6c34c68a43..3208e0e2b2 100644 --- a/tests/language/stats/crosstabs.at +++ b/tests/language/stats/crosstabs.at @@ -25,7 +25,8 @@ END DATA. CROSSTABS VARIABLES X (1,7) Y (1,7) /TABLES X BY Y. ]) -AT_CHECK([pspp -O format=csv crosstabs.sps], [0], +AT_CHECK([pspp -o pspp.csv -o pspp.txt crosstabs.sps]) +AT_CHECK([cat pspp.csv], [0], [[Table: Reading free-form data from INLINE. Variable,Format A,F8.0 @@ -33,23 +34,23 @@ B,F8.0 X,F8.0 Y,F8.0 -Table: Summary. +Table: Summary ,Cases,,,,, ,Valid,,Missing,,Total, ,N,Percent,N,Percent,N,Percent -X * Y,1,100.0%,0,0.0%,1,100.0% - -Table: X * Y [count]. -,Y,,,,,,, -X,1.00,2.00,3.00,4.00,5.00,6.00,7.00,Total -1.00,.00,.00,.00,.00,.00,.00,.00,.00 -2.00,.00,.00,.00,.00,.00,.00,.00,.00 -3.00,.00,.00,.00,.00,.00,.00,.00,.00 -4.00,.00,.00,.00,.00,1.00,.00,.00,1.00 -5.00,.00,.00,.00,.00,.00,.00,.00,.00 -6.00,.00,.00,.00,.00,.00,.00,.00,.00 -7.00,.00,.00,.00,.00,.00,.00,.00,.00 -Total,.00,.00,.00,.00,1.00,.00,.00,1.00 +X × Y,1,100.0%,0,.0%,1,100.0% + +Table: X × Y +,,,Y,,,,,,,Total +,,,1.00,2.00,3.00,4.00,5.00,6.00,7.00, +X,1.00,Count,0,0,0,0,0,0,0,0 +,2.00,,0,0,0,0,0,0,0,0 +,3.00,,0,0,0,0,0,0,0,0 +,4.00,,0,0,0,0,1,0,0,1 +,5.00,,0,0,0,0,0,0,0,0 +,6.00,,0,0,0,0,0,0,0,0 +,7.00,,0,0,0,0,0,0,0,0 +Total,,,0,0,0,0,1,0,0,1 ]]) AT_CLEANUP @@ -71,11 +72,15 @@ Variable,Format x,F8.0 y,F8.0 -Table: Summary. +Table: Summary ,Cases,,,,, ,Valid,,Missing,,Total, ,N,Percent,N,Percent,N,Percent -x * y,0,0.0%,1,100.0%,1,100.0% +x × y,0,.0%,1,100.0%,1,100.0% + +Table: x × y +,, +,, ]]) AT_CLEANUP @@ -95,7 +100,7 @@ end data. CROSSTABS /TABLES = x BY y. ]) -AT_CHECK([pspp -o - -O format=csv crosstabs.sps], [0], +AT_CHECK([pspp -o - -O format=csv -o pspp.txt crosstabs.sps], [0], [[Table: Reading free-form data from INLINE. Variable,Format x,F8.0 @@ -105,19 +110,19 @@ y,A18 "crosstabs.sps:6: warning: Missing value(s) for all variables from x onward. These will be filled with the system-missing value or blanks, as appropriate." -Table: Summary. +Table: Summary ,Cases,,,,, ,Valid,,Missing,,Total, ,N,Percent,N,Percent,N,Percent -x * y,4,66.7%,2,33.3%,6,100.0% - -Table: x * y [count]. -,y,,,, -x,one unity ,three lots ,two duality ,zero none ,Total -1.00,1.00,.00,.00,1.00,2.00 -2.00,.00,.00,1.00,.00,1.00 -3.00,.00,1.00,.00,.00,1.00 -Total,1.00,1.00,1.00,1.00,4.00 +x × y,4,66.7%,2,33.3%,6,100.0% + +Table: x × y +,,,y,,,,Total +,,,one unity,three lots,two duality,zero none, +x,1.00,Count,1,0,0,1,2 +,2.00,,0,0,1,0,1 +,3.00,,0,1,0,0,1 +Total,,,1,1,1,1,4 ]]) AT_CLEANUP @@ -145,8 +150,8 @@ LIST. CROSSTABS TABLES y by z. ]]) -AT_CHECK([pspp -O format=csv crosstabs.sps], [0], - [[Table: Reading 1 record from INLINE. +AT_CHECK([pspp -o - -O format=csv -o pspp.txt crosstabs.sps], [0], + [Table: Reading 1 record from INLINE. Variable,Record,Columns,Format x,1,1- 2,F2.0 y,1,3- 3,F1.0 @@ -164,19 +169,19 @@ x,y,z 8,1,1 9,1,2 -Table: Summary. +Table: Summary ,Cases,,,,, ,Valid,,Missing,,Total, ,N,Percent,N,Percent,N,Percent -y * z,9,100.0%,0,0.0%,9,100.0% - -Table: y * z [count]. -,z,, -y,1,2,Total -1,4.00,3.00,7.00 -2,1.00,1.00,2.00 -Total,5.00,4.00,9.00 -]]) +y × z,9,100.0%,0,.0%,9,100.0% + +Table: y × z +,,,z,,Total +,,,1,2, +y,1,Count,4,3,7 +,2,,1,1,2 +Total,,,5,4,9 +]) AT_CLEANUP # Bug #26739, which caused CROSSTABS to crash or to fail to output @@ -201,22 +206,22 @@ Variable,Format x,F8.0 y,F8.0 -Table: Summary. +Table: Summary ,Cases,,,,, ,Valid,,Missing,,Total, ,N,Percent,N,Percent,N,Percent -x * y,4,100.0%,0,0.0%,4,100.0% - -Table: x * y [count]. -,y,, -x,1.00,2.00,Total -2.00,.00,1.00,1.00 -3.00,1.00,.00,1.00 -4.00,1.00,1.00,2.00 -Total,2.00,2.00,4.00 - -Table: Chi-square tests. -Statistic,Value,df,Asymp. Sig. (2-tailed) +x × y,4,100.0%,0,.0%,4,100.0% + +Table: x × y +,,,y,,Total +,,,1.00,2.00, +x,2.00,Count,0,1,1 +,3.00,,1,0,1 +,4.00,,1,1,2 +Total,,,2,2,4 + +Table: Chi-Square Tests +,Value,df,Asymptotic Sig. (2-tailed) Pearson Chi-Square,2.00,2,.368 Likelihood Ratio,2.77,2,.250 Linear-by-Linear Association,.27,1,.602 @@ -250,73 +255,76 @@ CROSSTABS /CELLS=COUNT ROW COLUMN TOTAL. ]) -AT_CHECK([pspp -O format=csv crosstabs.sps], [0], - [[Variable,Value,Label -v0,a , +AT_CHECK([pspp -o pspp.csv -o pspp.txt crosstabs.sps]) +AT_CHECK([cat pspp.csv], [0], [dnl +Table: Split Values +Variable,Value +v0,a -Table: Summary. +Table: Summary ,Cases,,,,, ,Valid,,Missing,,Total, ,N,Percent,N,Percent,N,Percent -v1 * v2,6,100.0%,0,0.0%,6,100.0% - -"Table: v1 * v2 [count, row %, column %, total %]." -,v2,, -v1,e ,f ,Total -c ,3.00,1.00,4.00 -,75.00%,25.00%,100.00% -,75.00%,50.00%,66.67% -,50.00%,16.67%,66.67% -d ,1.00,1.00,2.00 -,50.00%,50.00%,100.00% -,25.00%,50.00%,33.33% -,16.67%,16.67%,33.33% -Total,4.00,2.00,6.00 -,66.67%,33.33%,100.00% -,100.00%,100.00%,100.00% -,66.67%,33.33%,100.00% - -Table: Chi-square tests. -Statistic,Value,df,Asymp. Sig. (2-tailed),Exact Sig. (2-tailed),Exact Sig. (1-tailed) +v1 × v2,6,100.0%,0,.0%,6,100.0% + +Table: v1 × v2 +,,,v2,,Total +,,,e,f, +v1,c,Count,3,1,4 +,,Row %,75.0%,25.0%,100.0% +,,Column %,75.0%,50.0%,66.7% +,,Total %,50.0%,16.7%,66.7% +,d,Count,1,1,2 +,,Row %,50.0%,50.0%,100.0% +,,Column %,25.0%,50.0%,33.3% +,,Total %,16.7%,16.7%,33.3% +Total,,Count,4,2,6 +,,Row %,66.7%,33.3%,100.0% +,,Column %,100.0%,100.0%,100.0% +,,Total %,66.7%,33.3%,100.0% + +Table: Chi-Square Tests +,Value,df,Asymptotic Sig. (2-tailed),Exact Sig. (2-tailed),Exact Sig. (1-tailed) Pearson Chi-Square,.38,1,.540,, Likelihood Ratio,.37,1,.545,, Fisher's Exact Test,,,,1.000,.600 Continuity Correction,.00,1,1.000,, N of Valid Cases,6,,,, -Variable,Value,Label -v0,b , +Table: Split Values +Variable,Value +v0,b -Table: Summary. +Table: Summary ,Cases,,,,, ,Valid,,Missing,,Total, ,N,Percent,N,Percent,N,Percent -v1 * v2,4,100.0%,0,0.0%,4,100.0% - -"Table: v1 * v2 [count, row %, column %, total %]." -,v2,, -v1,e ,f ,Total -c ,.00,1.00,1.00 -,.00%,100.00%,100.00% -,.00%,33.33%,25.00% -,.00%,25.00%,25.00% -d ,1.00,2.00,3.00 -,33.33%,66.67%,100.00% -,100.00%,66.67%,75.00% -,25.00%,50.00%,75.00% -Total,1.00,3.00,4.00 -,25.00%,75.00%,100.00% -,100.00%,100.00%,100.00% -,25.00%,75.00%,100.00% - -Table: Chi-square tests. -Statistic,Value,df,Asymp. Sig. (2-tailed),Exact Sig. (2-tailed),Exact Sig. (1-tailed) +v1 × v2,4,100.0%,0,.0%,4,100.0% + +Table: v1 × v2 +,,,v2,,Total +,,,e,f, +v1,c,Count,0,1,1 +,,Row %,.0%,100.0%,100.0% +,,Column %,.0%,33.3%,25.0% +,,Total %,.0%,25.0%,25.0% +,d,Count,1,2,3 +,,Row %,33.3%,66.7%,100.0% +,,Column %,100.0%,66.7%,75.0% +,,Total %,25.0%,50.0%,75.0% +Total,,Count,1,3,4 +,,Row %,25.0%,75.0%,100.0% +,,Column %,100.0%,100.0%,100.0% +,,Total %,25.0%,75.0%,100.0% + +Table: Chi-Square Tests +,Value,df,Asymptotic Sig. (2-tailed),Exact Sig. (2-tailed),Exact Sig. (1-tailed) Pearson Chi-Square,.44,1,.505,, Likelihood Ratio,.68,1,.410,, Fisher's Exact Test,,,,1.000,.750 Continuity Correction,.00,1,1.000,, N of Valid Cases,4,,,, -]]) +]) AT_CLEANUP # Bug #24752. @@ -344,8 +352,8 @@ LIST. CROSSTABS TABLES x BY y BY z/STATISTICS=ALL. ]]) -AT_CHECK([pspp -O format=csv crosstabs.sps], [0], - [[Table: Reading 1 record from INLINE. +AT_CHECK([pspp -o - -O format=csv -o pspp.csv -o pspp.txt crosstabs.sps], [0], + [Table: Reading 1 record from INLINE. Variable,Record,Columns,Format x,1,1- 2,F2.0 y,1,3- 3,F1.0 @@ -363,88 +371,88 @@ x,y,z 8,1,1 9,1,2 -Table: Summary. +Table: Summary ,Cases,,,,, ,Valid,,Missing,,Total, ,N,Percent,N,Percent,N,Percent -x * y * z,9,100.0%,0,0.0%,9,100.0% - -Table: x * y * z [count]. -z,,y,, -,x,1,2,Total -1,1,1.00,.00,1.00 -,3,1.00,.00,1.00 -,5,.00,1.00,1.00 -,7,1.00,.00,1.00 -,8,1.00,.00,1.00 -Total,,4.00,1.00,5.00 -2,2,.00,1.00,1.00 -,4,1.00,.00,1.00 -,6,1.00,.00,1.00 -,9,1.00,.00,1.00 -Total,,3.00,1.00,4.00 - -Table: Chi-square tests. -z,Statistic,Value,df,Asymp. Sig. (2-tailed) -1,Pearson Chi-Square,5.00,4,.287 -,Likelihood Ratio,5.00,4,.287 -,Linear-by-Linear Association,.01,1,.938 -,N of Valid Cases,5,, -2,Pearson Chi-Square,4.00,3,.261 -,Likelihood Ratio,4.50,3,.212 -,Linear-by-Linear Association,1.58,1,.209 -,N of Valid Cases,4,, - -Table: Symmetric measures. -z,Category,Statistic,Value,Asymp. Std. Error,Approx. T,Approx. Sig. -1,Nominal by Nominal,Phi,1.00,,, -,,Cramer's V,1.00,,, -,,Contingency Coefficient,.71,,, -,Ordinal by Ordinal,Kendall's tau-b,.00,.32,.00, -,,Kendall's tau-c,.00,.32,.00, -,,Gamma,.00,.50,.00, -,,Spearman Correlation,.00,.22,.00, -,Interval by Interval,Pearson's R,.04,.22,.07, -,N of Valid Cases,,5,,, -2,Nominal by Nominal,Phi,1.00,,, -,,Cramer's V,1.00,,, -,,Contingency Coefficient,.71,,, -,Ordinal by Ordinal,Kendall's tau-b,-.71,.20,-1.73, -,,Kendall's tau-c,-.75,.43,-1.73, -,,Gamma,-1.00,.00,-1.73, -,,Spearman Correlation,-.77,.17,-1.73, -,Interval by Interval,Pearson's R,-.73,.18,-1.49, -,N of Valid Cases,,4,,, - -Table: Directional measures. -z,Category,Statistic,Type,Value,Asymp. Std. Error,Approx. T,Approx. Sig. -1,Nominal by Nominal,Lambda,Symmetric,.40,.28,1.12,.264 -,,,x Dependent,.25,.22,1.12,.264 -,,,y Dependent,1.00,.00,1.12,.264 -,,Goodman and Kruskal tau,x Dependent,.25,,,. @&t@ -,,,y Dependent,1.00,,,. @&t@ -,,Uncertainty Coefficient,Symmetric,.47,.18,,. @&t@ -,,,x Dependent,.31,.15,2.02,. @&t@ -,,,y Dependent,1.00,.00,2.02,. @&t@ -,Ordinal by Ordinal,Somers' d,Symmetric,.00,,.00,1.000 -,,,x Dependent,.00,.50,.00,1.000 -,,,y Dependent,.00,.20,.00,1.000 -,Nominal by Interval,Eta,x Dependent,.04,,,. @&t@ -,,,y Dependent,1.00,,,. @&t@ -2,Nominal by Nominal,Lambda,Symmetric,.50,.25,2.00,.046 -,,,x Dependent,.33,.27,1.15,.248 -,,,y Dependent,1.00,.00,1.15,.248 -,,Goodman and Kruskal tau,x Dependent,.33,,,. @&t@ -,,,y Dependent,1.00,,,. @&t@ -,,Uncertainty Coefficient,Symmetric,.58,.17,,. @&t@ -,,,x Dependent,.41,.17,2.36,. @&t@ -,,,y Dependent,1.00,.00,2.36,. @&t@ -,Ordinal by Ordinal,Somers' d,Symmetric,-.67,,-1.73,.083 -,,,x Dependent,-1.00,.00,-1.73,.083 -,,,y Dependent,-.50,.29,-1.73,.083 -,Nominal by Interval,Eta,x Dependent,.73,,,. @&t@ -,,,y Dependent,1.00,,,. @&t@ -]]) +x × y × z,9,100.0%,0,.0%,9,100.0% + +Table: x × y × z +,,,,,y,,Total +,,,,,1,2, +z,1,x,1,Count,1,0,1 +,,,3,,0,0,1 +,,,5,,1,0,1 +,,,7,,0,0,1 +,,,8,,0,1,1 +,,Total,,,4,1,5 +,2,x,2,,0,0,1 +,,,4,,0,1,1 +,,,6,,0,0,1 +,,,9,,1,0,1 +,,Total,,,3,1,4 + +Table: Chi-Square Tests +,,,Value,df,Asymptotic Sig. (2-tailed) +z,1,Pearson Chi-Square,5.00,4,.287 +,,Likelihood Ratio,5.00,4,.287 +,,Linear-by-Linear Association,.01,1,.938 +,,N of Valid Cases,5,, +,2,Pearson Chi-Square,4.00,3,.261 +,,Likelihood Ratio,4.50,3,.212 +,,Linear-by-Linear Association,1.58,1,.209 +,,N of Valid Cases,4,, + +Table: Symmetric Measures +,,,,Value,Asymp. Std. Error,Approx. T +z,1,Nominal by Nominal,Phi,1.00,, +,,,Cramer's V,1.00,, +,,,Contingency Coefficient,.71,, +,,Ordinal by Ordinal,Kendall's tau-b,.00,.32,.00 +,,,Kendall's tau-c,.00,.32,.00 +,,,Gamma,.00,.50,.00 +,,,Spearman Correlation,.00,.22,.00 +,,Interval by Interval,Pearson's R,.04,.22,.07 +,,N of Valid Cases,,5,, +,2,Nominal by Nominal,Phi,1.00,, +,,,Cramer's V,1.00,, +,,,Contingency Coefficient,.71,, +,,Ordinal by Ordinal,Kendall's tau-b,-.71,.20,-1.73 +,,,Kendall's tau-c,-.75,.43,-1.73 +,,,Gamma,-1.00,.00,-1.73 +,,,Spearman Correlation,-.77,.17,-1.73 +,,Interval by Interval,Pearson's R,-.73,.18,-1.49 +,,N of Valid Cases,,4,, + +Table: Directional Measures +,,,,,Value,Asymp. Std. Error,Approx. T,Approx Sig. +z,1,Nominal by Nominal,Lambda,Symmetric,.40,.28,1.12,.264 +,,,,x Dependent,.25,.22,1.12,.264 +,,,,y Dependent,1.00,.00,1.12,.264 +,,,Goodman and Kruskal tau,x Dependent,.25,,, +,,,,y Dependent,1.00,,, +,,,Uncertainty Coefficient,Symmetric,.47,.18,, +,,,,x Dependent,.31,.15,2.02, +,,,,y Dependent,1.00,.00,2.02, +,,Ordinal by Ordinal,Somers' d,Symmetric,.00,,.00,1.000 +,,,,x Dependent,.00,.50,.00,1.000 +,,,,y Dependent,.00,.20,.00,1.000 +,,Nominal by Interval,Eta,x Dependent,.04,,, +,,,,y Dependent,1.00,,, +,2,Nominal by Nominal,Lambda,Symmetric,.50,.25,2.00,.046 +,,,,x Dependent,.33,.27,1.15,.248 +,,,,y Dependent,1.00,.00,1.15,.248 +,,,Goodman and Kruskal tau,x Dependent,.33,,, +,,,,y Dependent,1.00,,, +,,,Uncertainty Coefficient,Symmetric,.58,.17,, +,,,,x Dependent,.41,.17,2.36, +,,,,y Dependent,1.00,.00,2.36, +,,Ordinal by Ordinal,Somers' d,Symmetric,-.67,,-1.73,.083 +,,,,x Dependent,-1.00,.00,-1.73,.083 +,,,,y Dependent,-.50,.29,-1.73,.083 +,,Nominal by Interval,Eta,x Dependent,.73,,, +,,,,y Dependent,1.00,,, +]) AT_CLEANUP AT_SETUP([CROSSTABS rounding weights with COUNT]) @@ -473,85 +481,86 @@ CROSSTABS /TABLES x BY y /COUNT. CROSSTABS /TABLES x BY y /COUNT TRUNCATE. ]]) -AT_CHECK([pspp -O format=csv crosstabs.sps], [0], - [[Table: Summary. +AT_CHECK([pspp -o pspp.csv -o pspp.txt crosstabs.sps]) +AT_CHECK([cat pspp.csv], [0], + [Table: Summary ,Cases,,,,, ,Valid,,Missing,,Total, ,N,Percent,N,Percent,N,Percent -x * y,9.00,100.0%,.00,0.0%,9.00,100.0% +x × y,9.00,100.0%,.00,.0%,9.00,100.0% -Table: x * y [count]. -,y,, -x,1.00,2.00,Total -1.00,2.80,3.20,6.00 -2.00,1.00,2.00,3.00 -Total,3.80,5.20,9.00 +Table: x × y +,,,y,,Total +,,,1.00,2.00, +x,1.00,Count,2.80,3.20,6.00 +,2.00,,1.00,2.00,3.00 +Total,,,3.80,5.20,9.00 -Table: Summary. +Table: Summary ,Cases,,,,, ,Valid,,Missing,,Total, ,N,Percent,N,Percent,N,Percent -x * y,9.00,100.0%,.00,0.0%,9.00,100.0% +x × y,9.00,100.0%,.00,.0%,9.00,100.0% -Table: x * y [count]. -,y,, -x,1.00,2.00,Total -1.00,2.80,3.20,6.00 -2.00,1.00,2.00,3.00 -Total,3.80,5.20,9.00 +Table: x × y +,,,y,,Total +,,,1.00,2.00, +x,1.00,Count,2.80,3.20,6.00 +,2.00,,1.00,2.00,3.00 +Total,,,3.80,5.20,9.00 -Table: Summary. +Table: Summary ,Cases,,,,, ,Valid,,Missing,,Total, ,N,Percent,N,Percent,N,Percent -x * y,9.00,100.0%,.00,0.0%,9.00,100.0% +x × y,9.00,100.0%,.00,.0%,9.00,100.0% -Table: x * y [count]. -,y,, -x,1.00,2.00,Total -1.00,2.00,4.00,6.00 -2.00,1.00,2.00,3.00 -Total,3.00,6.00,9.00 +Table: x × y +,,,y,,Total +,,,1.00,2.00, +x,1.00,Count,2.00,4.00,6.00 +,2.00,,1.00,2.00,3.00 +Total,,,3.00,6.00,9.00 -Table: Summary. +Table: Summary ,Cases,,,,, ,Valid,,Missing,,Total, ,N,Percent,N,Percent,N,Percent -x * y,7.00,100.0%,.00,0.0%,7.00,100.0% +x × y,7.00,100.0%,.00,.0%,7.00,100.0% -Table: x * y [count]. -,y,, -x,1.00,2.00,Total -1.00,2.00,2.00,4.00 -2.00,1.00,2.00,3.00 -Total,3.00,4.00,7.00 +Table: x × y +,,,y,,Total +,,,1.00,2.00, +x,1.00,Count,2.00,2.00,4.00 +,2.00,,1.00,2.00,3.00 +Total,,,3.00,4.00,7.00 -Table: Summary. +Table: Summary ,Cases,,,,, ,Valid,,Missing,,Total, ,N,Percent,N,Percent,N,Percent -x * y,9.00,100.0%,.00,0.0%,9.00,100.0% +x × y,9.00,100.0%,.00,.0%,9.00,100.0% -Table: x * y [count]. -,y,, -x,1.00,2.00,Total -1.00,3.00,3.00,6.00 -2.00,1.00,2.00,3.00 -Total,4.00,5.00,9.00 +Table: x × y +,,,y,,Total +,,,1.00,2.00, +x,1.00,Count,3.00,3.00,6.00 +,2.00,,1.00,2.00,3.00 +Total,,,4.00,5.00,9.00 -Table: Summary. +Table: Summary ,Cases,,,,, ,Valid,,Missing,,Total, ,N,Percent,N,Percent,N,Percent -x * y,8.00,100.0%,.00,0.0%,8.00,100.0% - -Table: x * y [count]. -,y,, -x,1.00,2.00,Total -1.00,2.00,3.00,5.00 -2.00,1.00,2.00,3.00 -Total,3.00,5.00,8.00 -]]) +x × y,8.00,100.0%,.00,.0%,8.00,100.0% + +Table: x × y +,,,y,,Total +,,,1.00,2.00, +x,1.00,Count,2.00,3.00,5.00 +,2.00,,1.00,2.00,3.00 +Total,,,3.00,5.00,8.00 +]) AT_CLEANUP AT_SETUP([CROSSTABS descending sort order]) @@ -571,21 +580,22 @@ CROSSTABS /FORMAT = DVALUE. ]]) -AT_CHECK([pspp -O format=csv crosstabs-descending.sps], [0], - [[Table: Summary. +AT_CHECK([pspp -o pspp.csv -o pspp.txt crosstabs-descending.sps]) +AT_CHECK([cat pspp.csv], [0], + [Table: Summary ,Cases,,,,, ,Valid,,Missing,,Total, ,N,Percent,N,Percent,N,Percent -x * y,6,100.0%,0,0.0%,6,100.0% - -Table: x * y [count]. -,y,, -x,2.00,1.00,Total -4.00,.00,1.00,1.00 -3.00,2.00,1.00,3.00 -2.00,2.00,.00,2.00 -Total,4.00,2.00,6.00 -]]) +x × y,6,100.0%,0,.0%,6,100.0% + +Table: x × y +,,,y,,Total +,,,2.00,1.00, +x,4.00,Count,0,1,1 +,3.00,,2,1,3 +,2.00,,2,0,2 +Total,,,4,2,6 +]) AT_CLEANUP # Bug #31260. @@ -601,13 +611,13 @@ MISSING VALUES x2 (1). CROSSTABS /TABLES= X1 by X2. ]) AT_CHECK([pspp -O format=csv crosstabs.sps], [0], [dnl -Table: Summary. +Table: Summary ,Cases,,,,, ,Valid,,Missing,,Total, ,N,Percent,N,Percent,N,Percent -X1 * X2,0,0.0%,1,100.0%,1,100.0% +X1 × X2,0,.0%,1,100.0%,1,100.0% -crosstabs.sps:8: warning: CROSSTABS: Crosstabulation X1 * X2 contained no non-missing cases. +crosstabs.sps:8: warning: CROSSTABS: Crosstabulation X1 × X2 contained no non-missing cases. ]) AT_CLEANUP @@ -833,22 +843,22 @@ crosstabs /tables = schtyp by female /statistic = chisq. crosstabs /tables = female by ses /statistic = chisq. ]) -AT_CHECK([pspp -O format=csv fisher-exact.sps], [0], [dnl -Table: Summary. +AT_CHECK([pspp -o pspp.csv -o pspp.txt fisher-exact.sps]) +AT_CHECK([cat pspp.csv], [0], [Table: Summary ,Cases,,,,, ,Valid,,Missing,,Total, ,N,Percent,N,Percent,N,Percent -type of school * female,200,100.0%,0,0.0%,200,100.0% +type of school × female,200,100.0%,0,.0%,200,100.0% -Table: type of school * female [[count]]. -,female,, -type of school,male,female,Total -public,77.000,91.000,168.000 -private,14.000,18.000,32.000 -Total,91.000,109.000,200.000 +Table: type of school × female +,,,female,,Total +,,,male,female, +type of school,public,Count,77,91,168 +,private,,14,18,32 +Total,,,91,109,200 -Table: Chi-square tests. -Statistic,Value,df,Asymp. Sig. (2-tailed),Exact Sig. (2-tailed),Exact Sig. (1-tailed) +Table: Chi-Square Tests +,Value,df,Asymptotic Sig. (2-tailed),Exact Sig. (2-tailed),Exact Sig. (1-tailed) Pearson Chi-Square,.047,1,.828,, Likelihood Ratio,.047,1,.828,, Fisher's Exact Test,,,,.849,.492 @@ -856,21 +866,21 @@ Continuity Correction,.001,1,.981,, Linear-by-Linear Association,.047,1,.829,, N of Valid Cases,200,,,, -Table: Summary. +Table: Summary ,Cases,,,,, ,Valid,,Missing,,Total, ,N,Percent,N,Percent,N,Percent -female * ses,200,100.0%,0,0.0%,200,100.0% +female × ses,200,100.0%,0,.0%,200,100.0% -Table: female * ses [[count]]. -,ses,,, -female,low,middle,high,Total -male,15.000,47.000,29.000,91.000 -female,32.000,48.000,29.000,109.000 -Total,47.000,95.000,58.000,200.000 +Table: female × ses +,,,ses,,,Total +,,,low,middle,high, +female,male,Count,15,47,29,91 +,female,,32,48,29,109 +Total,,,47,95,58,200 -Table: Chi-square tests. -Statistic,Value,df,Asymp. Sig. (2-tailed) +Table: Chi-Square Tests +,Value,df,Asymptotic Sig. (2-tailed) Pearson Chi-Square,4.577,2,.101 Likelihood Ratio,4.679,2,.096 Linear-by-Linear Association,3.110,1,.078 @@ -879,8 +889,7 @@ N of Valid Cases,200,, AT_CLEANUP -AT_SETUP([CROSSTABS Pearson's R]) -# Test 1. +AT_SETUP([CROSSTABS Pearson's R - 1]) AT_DATA([pearson.sps], [dnl SET FORMAT F8.3. @@ -895,30 +904,32 @@ BEGIN DATA. END DATA. CROSSTABS x BY y/STATISTICS=CORR. ]) -AT_CHECK([pspp -O format=csv pearson.sps], [0], [dnl -Table: Summary. +AT_CHECK([pspp -o pspp.csv -o pspp.txt pearson.sps]) +AT_CHECK([cat pspp.csv], [0], [dnl +Table: Summary ,Cases,,,,, ,Valid,,Missing,,Total, ,N,Percent,N,Percent,N,Percent -x * y,5,100.0%,0,0.0%,5,100.0% - -Table: x * y [[count]]. -,y,,,,, -x,4.000,6.000,10.000,12.000,13.000,Total -1.000,1.000,.000,.000,.000,.000,1.000 -3.000,.000,1.000,.000,.000,.000,1.000 -5.000,.000,.000,1.000,1.000,.000,2.000 -6.000,.000,.000,.000,.000,1.000,1.000 -Total,1.000,1.000,1.000,1.000,1.000,5.000 - -Table: Symmetric measures. -Category,Statistic,Value,Asymp. Std. Error,Approx. T,Approx. Sig. -Ordinal by Ordinal,Spearman Correlation,.975,.022,7.550, -Interval by Interval,Pearson's R,.968,.017,6.708, -N of Valid Cases,,5,,, +x × y,5,100.0%,0,.0%,5,100.0% + +Table: x × y +,,,y,,,,,Total +,,,4.000,6.000,10.000,12.000,13.000, +x,1.000,Count,1,0,0,0,0,1 +,3.000,,0,1,0,0,0,1 +,5.000,,0,0,1,1,0,2 +,6.000,,0,0,0,0,1,1 +Total,,,1,1,1,1,1,5 + +Table: Symmetric Measures +,,Value,Asymp. Std. Error,Approx. T +Ordinal by Ordinal,Spearman Correlation,.975,.022,7.550 +Interval by Interval,Pearson's R,.968,.017,6.708 +N of Valid Cases,,5,, ]) +AT_CLEANUP -# Test 2. +AT_SETUP([CROSSTABS Pearson's R - 2]) AT_DATA([pearson2.sps], [dnl SET FORMAT F8.3. @@ -938,36 +949,38 @@ BEGIN DATA. END DATA. CROSSTABS x BY y/STATISTICS=CORR. ]) -AT_CHECK([pspp -O format=csv pearson2.sps], [0], [dnl -Table: Summary. +AT_CHECK([pspp -o pspp.csv -o pspp.txt pearson2.sps]) +AT_CHECK([cat pspp.csv], [0], [dnl +Table: Summary ,Cases,,,,, ,Valid,,Missing,,Total, ,N,Percent,N,Percent,N,Percent -x * y,10,100.0%,0,0.0%,10,100.0% - -Table: x * y [[count]]. -,y,,,,,,,,, -x,1.500,4.000,5.000,6.000,6.500,7.000,9.000,10.500,11.000,Total -1.000,1.000,.000,.000,.000,.000,.000,.000,.000,.000,1.000 -2.000,1.000,.000,.000,.000,.000,.000,.000,.000,.000,1.000 -3.000,.000,1.000,.000,.000,.000,.000,.000,.000,.000,1.000 -4.000,.000,.000,.000,1.000,.000,.000,.000,.000,.000,1.000 -5.000,.000,.000,1.000,.000,.000,.000,.000,.000,.000,1.000 -6.000,.000,.000,.000,.000,.000,1.000,.000,.000,.000,1.000 -7.000,.000,.000,.000,.000,1.000,.000,.000,.000,.000,1.000 -8.000,.000,.000,.000,.000,.000,.000,1.000,.000,.000,1.000 -9.000,.000,.000,.000,.000,.000,.000,.000,1.000,.000,1.000 -10.000,.000,.000,.000,.000,.000,.000,.000,.000,1.000,1.000 -Total,2.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,10.000 - -Table: Symmetric measures. -Category,Statistic,Value,Asymp. Std. Error,Approx. T,Approx. Sig. -Ordinal by Ordinal,Spearman Correlation,.973,.015,11.844, -Interval by Interval,Pearson's R,.971,.017,11.580, -N of Valid Cases,,10,,, +x × y,10,100.0%,0,.0%,10,100.0% + +Table: x × y +,,,y,,,,,,,,,Total +,,,1.500,4.000,5.000,6.000,6.500,7.000,9.000,10.500,11.000, +x,1.000,Count,1,0,0,0,0,0,0,0,0,1 +,2.000,,1,0,0,0,0,0,0,0,0,1 +,3.000,,0,1,0,0,0,0,0,0,0,1 +,4.000,,0,0,0,1,0,0,0,0,0,1 +,5.000,,0,0,1,0,0,0,0,0,0,1 +,6.000,,0,0,0,0,0,1,0,0,0,1 +,7.000,,0,0,0,0,1,0,0,0,0,1 +,8.000,,0,0,0,0,0,0,1,0,0,1 +,9.000,,0,0,0,0,0,0,0,1,0,1 +,10.000,,0,0,0,0,0,0,0,0,1,1 +Total,,,2,1,1,1,1,1,1,1,1,10 + +Table: Symmetric Measures +,,Value,Asymp. Std. Error,Approx. T +Ordinal by Ordinal,Spearman Correlation,.973,.015,11.844 +Interval by Interval,Pearson's R,.971,.017,11.580 +N of Valid Cases,,10,, ]) +AT_CLEANUP -# Test 3. +AT_SETUP([CROSSTABS Pearson's R - 3]) AT_DATA([pearson3.sps], [dnl SET FORMAT F8.3. @@ -986,33 +999,35 @@ BEGIN DATA. END DATA. CROSSTABS x BY y/STATISTICS=CORR. ]) -AT_CHECK([pspp -O format=csv pearson3.sps], [0], [dnl -Table: Summary. +AT_CHECK([pspp -o pspp.csv -o pspp.txt pearson3.sps]) +AT_CHECK([cat pspp.csv], [0], [dnl +Table: Summary ,Cases,,,,, ,Valid,,Missing,,Total, ,N,Percent,N,Percent,N,Percent -x * y,9,100.0%,0,0.0%,9,100.0% - -Table: x * y [[count]]. -,y,,,,,,,, -x,28.000,58.000,66.000,75.000,85.000,87.000,91.000,122.000,Total -25.000,1.000,.000,.000,.000,.000,.000,.000,.000,1.000 -35.000,.000,1.000,.000,.000,.000,.000,.000,.000,1.000 -44.000,.000,.000,1.000,.000,.000,.000,.000,.000,1.000 -50.000,.000,.000,.000,1.000,.000,.000,.000,.000,1.000 -56.000,.000,.000,.000,.000,.000,1.000,1.000,.000,2.000 -65.000,.000,.000,.000,.000,1.000,.000,1.000,.000,2.000 -87.000,.000,.000,.000,.000,.000,.000,.000,1.000,1.000 -Total,1.000,1.000,1.000,1.000,1.000,1.000,2.000,1.000,9.000 - -Table: Symmetric measures. -Category,Statistic,Value,Asymp. Std. Error,Approx. T,Approx. Sig. -Ordinal by Ordinal,Spearman Correlation,.911,.068,5.860, -Interval by Interval,Pearson's R,.966,.017,9.915, -N of Valid Cases,,9,,, +x × y,9,100.0%,0,.0%,9,100.0% + +Table: x × y +,,,y,,,,,,,,Total +,,,28.000,58.000,66.000,75.000,85.000,87.000,91.000,122.000, +x,25.000,Count,1,0,0,0,0,0,0,0,1 +,35.000,,0,1,0,0,0,0,0,0,1 +,44.000,,0,0,1,0,0,0,0,0,1 +,50.000,,0,0,0,1,0,0,0,0,1 +,56.000,,0,0,0,0,0,1,1,0,2 +,65.000,,0,0,0,0,1,0,1,0,2 +,87.000,,0,0,0,0,0,0,0,1,1 +Total,,,1,1,1,1,1,1,2,1,9 + +Table: Symmetric Measures +,,Value,Asymp. Std. Error,Approx. T +Ordinal by Ordinal,Spearman Correlation,.911,.068,5.860 +Interval by Interval,Pearson's R,.966,.017,9.915 +N of Valid Cases,,9,, ]) +AT_CLEANUP -# Test 4. +AT_SETUP([CROSSTABS Pearson's R - 4]) AT_DATA([pearson4.sps], [dnl SET FORMAT F8.3. @@ -1034,35 +1049,37 @@ BEGIN DATA. END DATA. CROSSTABS x BY y/STATISTICS=CORR. ]) -AT_CHECK([pspp -O format=csv pearson4.sps], [0], [dnl -Table: Summary. +AT_CHECK([pspp -o pspp.csv -o pspp.txt pearson4.sps]) +AT_CHECK([cat pspp.csv], [0], [dnl +Table: Summary ,Cases,,,,, ,Valid,,Missing,,Total, ,N,Percent,N,Percent,N,Percent -x * y,12,100.0%,0,0.0%,12,100.0% - -Table: x * y [[count]]. -,y,,,,,,,,,,,, -x,2.000,4.000,5.000,7.000,9.000,11.000,12.000,14.000,15.000,17.000,18.000,20.000,Total -2.000,.000,.000,.000,1.000,.000,.000,.000,.000,.000,.000,.000,.000,1.000 -3.000,.000,.000,.000,.000,.000,.000,1.000,.000,.000,.000,.000,.000,1.000 -4.000,.000,.000,.000,.000,1.000,1.000,.000,.000,.000,.000,.000,.000,2.000 -5.000,.000,.000,1.000,.000,.000,.000,.000,.000,.000,.000,.000,.000,1.000 -6.000,1.000,1.000,.000,.000,.000,.000,.000,.000,.000,.000,.000,.000,2.000 -7.000,.000,.000,.000,.000,.000,.000,.000,1.000,.000,.000,.000,.000,1.000 -8.000,.000,.000,.000,.000,.000,.000,.000,.000,1.000,.000,.000,.000,1.000 -9.000,.000,.000,.000,.000,.000,.000,.000,.000,.000,1.000,.000,.000,1.000 -10.000,.000,.000,.000,.000,.000,.000,.000,.000,.000,.000,1.000,1.000,2.000 -Total,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,12.000 - -Table: Symmetric measures. -Category,Statistic,Value,Asymp. Std. Error,Approx. T,Approx. Sig. -Ordinal by Ordinal,Spearman Correlation,.657,.140,2.758, -Interval by Interval,Pearson's R,.667,.132,2.830, -N of Valid Cases,,12,,, +x × y,12,100.0%,0,.0%,12,100.0% + +Table: x × y +,,,y,,,,,,,,,,,,Total +,,,2.000,4.000,5.000,7.000,9.000,11.000,12.000,14.000,15.000,17.000,18.000,20.000, +x,2.000,Count,0,0,0,1,0,0,0,0,0,0,0,0,1 +,3.000,,0,0,0,0,0,0,1,0,0,0,0,0,1 +,4.000,,0,0,0,0,1,1,0,0,0,0,0,0,2 +,5.000,,0,0,1,0,0,0,0,0,0,0,0,0,1 +,6.000,,1,1,0,0,0,0,0,0,0,0,0,0,2 +,7.000,,0,0,0,0,0,0,0,1,0,0,0,0,1 +,8.000,,0,0,0,0,0,0,0,0,1,0,0,0,1 +,9.000,,0,0,0,0,0,0,0,0,0,1,0,0,1 +,10.000,,0,0,0,0,0,0,0,0,0,0,1,1,2 +Total,,,1,1,1,1,1,1,1,1,1,1,1,1,12 + +Table: Symmetric Measures +,,Value,Asymp. Std. Error,Approx. T +Ordinal by Ordinal,Spearman Correlation,.657,.140,2.758 +Interval by Interval,Pearson's R,.667,.132,2.830 +N of Valid Cases,,12,, ]) +AT_CLEANUP -# Test 5. +AT_SETUP([CROSSTABS Pearson's R - 5]) AT_DATA([pearson5.sps], [dnl SET FORMAT F8.3. @@ -1082,37 +1099,38 @@ BEGIN DATA. END DATA. CROSSTABS x BY y/STATISTICS=CORR. ]) -AT_CHECK([pspp -O format=csv pearson5.sps], [0], [dnl -Table: Summary. +AT_CHECK([pspp -o pspp.csv -o pspp.txt pearson5.sps]) +AT_CHECK([cat pspp.csv], [0], [dnl +Table: Summary ,Cases,,,,, ,Valid,,Missing,,Total, ,N,Percent,N,Percent,N,Percent -x * y,10,100.0%,0,0.0%,10,100.0% - -Table: x * y [[count]]. -,y,,,,,,,,,, -x,15000.000,26000.000,29000.000,32000.000,33000.000,41000.000,45000.000,52000.000,68000.000,80000.000,Total -18.000,1.000,.000,.000,.000,.000,.000,.000,.000,.000,.000,1.000 -24.000,.000,1.000,.000,.000,.000,.000,.000,.000,.000,.000,1.000 -25.000,.000,.000,1.000,.000,.000,.000,.000,.000,.000,.000,1.000 -26.000,.000,.000,.000,1.000,.000,.000,.000,.000,.000,.000,1.000 -33.000,.000,.000,.000,.000,1.000,.000,.000,.000,.000,.000,1.000 -37.000,.000,.000,.000,.000,.000,1.000,.000,.000,.000,.000,1.000 -40.000,.000,.000,.000,.000,.000,.000,1.000,.000,.000,.000,1.000 -45.000,.000,.000,.000,.000,.000,.000,.000,1.000,.000,.000,1.000 -57.000,.000,.000,.000,.000,.000,.000,.000,.000,1.000,.000,1.000 -64.000,.000,.000,.000,.000,.000,.000,.000,.000,.000,1.000,1.000 -Total,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,10.000 - -Table: Symmetric measures. -Category,Statistic,Value,Asymp. Std. Error,Approx. T,Approx. Sig. -Ordinal by Ordinal,Spearman Correlation,1.000,.000,+Infinity, -Interval by Interval,Pearson's R,.992,.004,22.638, -N of Valid Cases,,10,,, +x × y,10,100.0%,0,.0%,10,100.0% + +Table: x × y +,,,y,,,,,,,,,,Total +,,,15000.00,26000.00,29000.00,32000.00,33000.00,41000.00,45000.00,52000.00,68000.00,80000.00, +x,18.000,Count,1,0,0,0,0,0,0,0,0,0,1 +,24.000,,0,1,0,0,0,0,0,0,0,0,1 +,25.000,,0,0,1,0,0,0,0,0,0,0,1 +,26.000,,0,0,0,1,0,0,0,0,0,0,1 +,33.000,,0,0,0,0,1,0,0,0,0,0,1 +,37.000,,0,0,0,0,0,1,0,0,0,0,1 +,40.000,,0,0,0,0,0,0,1,0,0,0,1 +,45.000,,0,0,0,0,0,0,0,1,0,0,1 +,57.000,,0,0,0,0,0,0,0,0,1,0,1 +,64.000,,0,0,0,0,0,0,0,0,0,1,1 +Total,,,1,1,1,1,1,1,1,1,1,1,10 + +Table: Symmetric Measures +,,Value,Asymp. Std. Error,Approx. T +Ordinal by Ordinal,Spearman Correlation,1.000,.000,+Infinit +Interval by Interval,Pearson's R,.992,.004,22.638 +N of Valid Cases,,10,, ]) AT_CLEANUP -AT_SETUP([CROSSTABS Goodman and Kruskal's lambda]) +AT_SETUP([CROSSTABS Goodman and Kruskal's lambda - 1]) AT_DATA([lambda.sps], [dnl SET FORMAT F8.3. @@ -1129,6 +1147,28 @@ BEGIN DATA. END DATA. CROSSTABS x BY y/CELLS=NONE/STATISTICS=LAMBDA. +]) +AT_CHECK([pspp -o pspp.csv -o pspp.txt lambda.sps]) +AT_CHECK([cat pspp.csv], [0], [dnl +Table: Summary +,Cases,,,,, +,Valid,,Missing,,Total, +,N,Percent,N,Percent,N,Percent +x × y,1296.000,100.0%,.000,.0%,1296.000,100.0% + +Table: Directional Measures +,,,Value,Asymp. Std. Error,Approx. T,Approx Sig. +Nominal by Nominal,Lambda,Symmetric,.423,.021,16.875,.000 +,,x Dependent,.497,.024,15.986,.000 +,,y Dependent,.370,.020,16.339,.000 +,Goodman and Kruskal tau,x Dependent,.382,,, +,,y Dependent,.198,,, +]) +AT_CLEANUP + +AT_SETUP([CROSSTABS Goodman and Kruskal's lambda - 2]) +AT_DATA([lambda.sps], [dnl +SET FORMAT F8.3. * From http://vassarstats.net. DATA LIST LIST NOTABLE/x y w. @@ -1146,6 +1186,28 @@ BEGIN DATA. END DATA. CROSSTABS x BY y/CELLS=NONE/STATISTICS=LAMBDA. +]) +AT_CHECK([pspp -o pspp.csv -o pspp.txt lambda.sps]) +AT_CHECK([cat pspp.csv], [0], [dnl +Table: Summary +,Cases,,,,, +,Valid,,Missing,,Total, +,N,Percent,N,Percent,N,Percent +x × y,137.000,100.0%,.000,.0%,137.000,100.0% + +Table: Directional Measures +,,,Value,Asymp. Std. Error,Approx. T,Approx Sig. +Nominal by Nominal,Lambda,Symmetric,.259,.081,2.902,.004 +,,x Dependent,.250,.089,2.479,.013 +,,y Dependent,.267,.085,2.766,.006 +,Goodman and Kruskal tau,x Dependent,.129,,, +,,y Dependent,.123,,, +]) +AT_CLEANUP + +AT_SETUP([CROSSTABS Goodman and Kruskal's lambda - 3]) +AT_DATA([lambda.sps], [dnl +SET FORMAT F8.3. * From Goodman, L.A., Kruskal, W.H. (1954) "Measures of association for cross classifications". Part I. Journal of the American Statistical @@ -1168,48 +1230,21 @@ BEGIN DATA. END DATA. CROSSTABS x BY y/CELLS=NONE/STATISTICS=LAMBDA. ]) -AT_CHECK([pspp -O format=csv lambda.sps], [0], [dnl -Table: Summary. +AT_CHECK([pspp -o pspp.csv -o pspp.txt lambda.sps]) +AT_CHECK([cat pspp.csv], [0], [dnl +Table: Summary ,Cases,,,,, ,Valid,,Missing,,Total, ,N,Percent,N,Percent,N,Percent -x * y,1296.000,100.0%,.000,0.0%,1296.000,100.0% +x × y,6800.000,100.0%,.000,.0%,6800.000,100.0% -Table: Directional measures. -Category,Statistic,Type,Value,Asymp. Std. Error,Approx. T,Approx. Sig. -Nominal by Nominal,Lambda,Symmetric,.423,.021,16.875,.000 -,,x Dependent,.497,.024,15.986,.000 -,,y Dependent,.370,.020,16.339,.000 -,Goodman and Kruskal tau,x Dependent,.382,,,. @&t@ -,,y Dependent,.198,,,. @&t@ - -Table: Summary. -,Cases,,,,, -,Valid,,Missing,,Total, -,N,Percent,N,Percent,N,Percent -x * y,137.000,100.0%,.000,0.0%,137.000,100.0% - -Table: Directional measures. -Category,Statistic,Type,Value,Asymp. Std. Error,Approx. T,Approx. Sig. -Nominal by Nominal,Lambda,Symmetric,.259,.081,2.902,.004 -,,x Dependent,.250,.089,2.479,.013 -,,y Dependent,.267,.085,2.766,.006 -,Goodman and Kruskal tau,x Dependent,.129,,,. @&t@ -,,y Dependent,.123,,,. @&t@ - -Table: Summary. -,Cases,,,,, -,Valid,,Missing,,Total, -,N,Percent,N,Percent,N,Percent -x * y,6800.000,100.0%,.000,0.0%,6800.000,100.0% - -Table: Directional measures. -Category,Statistic,Type,Value,Asymp. Std. Error,Approx. T,Approx. Sig. +Table: Directional Measures +,,,Value,Asymp. Std. Error,Approx. T,Approx Sig. Nominal by Nominal,Lambda,Symmetric,.208,.010,18.793,.000 ,,x Dependent,.224,.013,16.076,.000 ,,y Dependent,.192,.012,14.438,.000 -,Goodman and Kruskal tau,x Dependent,.089,,,. @&t@ -,,y Dependent,.081,,,. @&t@ +,Goodman and Kruskal tau,x Dependent,.089,,, +,,y Dependent,.081,,, ]) AT_CLEANUP @@ -1231,24 +1266,25 @@ END DATA. CROSSTABS x BY y/CELLS=NONE/STATISTICS=LAMBDA. ]) -AT_CHECK([pspp -O format=csv lambda.sps], [0], [dnl -Table: Summary. +AT_CHECK([pspp -o pspp.csv -o pspp.txt lambda.sps]) +AT_CHECK([cat pspp.csv], [0], [dnl +Table: Summary ,Cases,,,,, ,Valid,,Missing,,Total, ,N,Percent,N,Percent,N,Percent -x * y,500.000,100.0%,.000,0.0%,500.000,100.0% +x × y,500.000,100.0%,.000,.0%,500.000,100.0% -Table: Directional measures. -Category,Statistic,Type,Value,Asymp. Std. Error,Approx. T,Approx. Sig. +Table: Directional Measures +,,,Value,Asymp. Std. Error,Approx. T,Approx Sig. Nominal by Nominal,Lambda,Symmetric,.031,.013,2.336,.019 ,,x Dependent,.000,.000,NaN,NaN ,,y Dependent,.033,.014,2.336,.019 -,Goodman and Kruskal tau,x Dependent,.012,,,. @&t@ -,,y Dependent,.009,,,. @&t@ +,Goodman and Kruskal tau,x Dependent,.012,,, +,,y Dependent,.009,,, ]) AT_CLEANUP -AT_SETUP([CROSSTABS Somers' D, Tau-B, Tau-C, Gamma]) +AT_SETUP([CROSSTABS Somers' D, Tau-B, Tau-C, Gamma - 1]) AT_DATA([somersd.sps], [dnl SET FORMAT F8.3. @@ -1272,6 +1308,26 @@ BEGIN DATA. 2 7 0.0375 END DATA. CROSSTABS x BY y/STATISTICS=D/CELLS=NONE. +]) +AT_CHECK([pspp -o pspp.csv -o pspp.txt somersd.sps]) +AT_CHECK([cat pspp.csv], [0], [dnl +Table: Summary +,Cases,,,,, +,Valid,,Missing,,Total, +,N,Percent,N,Percent,N,Percent +x × y,1.000000,100.0%,.000000,.0%,1.000000,100.0% + +Table: Directional Measures +,,,Value,Asymp. Std. Error,Approx. T,Approx Sig. +Ordinal by Ordinal,Somers' d,Symmetric,-.084,,-.149,.882 +,,x Dependent,-.045,.300,-.149,.882 +,,y Dependent,-.684,2.378,-.149,.882 +]) +AT_CLEANUP + +AT_SETUP([CROSSTABS Somers' D, Tau-B, Tau-C, Gamma - 2]) +AT_DATA([somersd.sps], [dnl +SET FORMAT F8.3. * From http://uregina.ca/~gingrich/gamma.pdf. DATA LIST LIST NOTABLE/x y w. @@ -1289,39 +1345,30 @@ BEGIN DATA. END DATA. CROSSTABS x BY y/STATISTICS=BTAU CTAU GAMMA D/CELLS=NONE. ]) -AT_CHECK([pspp -O format=csv somersd.sps], [0], [dnl -Table: Summary. -,Cases,,,,, -,Valid,,Missing,,Total, -,N,Percent,N,Percent,N,Percent -x * y,1.000000,100.0%,.000000,0.0%,1.000000,100.0% - -Table: Directional measures. -Category,Statistic,Type,Value,Asymp. Std. Error,Approx. T,Approx. Sig. -Ordinal by Ordinal,Somers' d,Symmetric,-.084,,-.149,.882 -,,x Dependent,-.045,.300,-.149,.882 -,,y Dependent,-.684,2.378,-.149,.882 - -Table: Summary. +AT_CHECK([pspp -o pspp.csv -o pspp.txt somersd.sps]) +AT_CHECK([cat pspp.csv], [0], [dnl +Table: Summary ,Cases,,,,, ,Valid,,Missing,,Total, ,N,Percent,N,Percent,N,Percent -x * y,687.000,100.0%,.000,0.0%,687.000,100.0% +x × y,687.000,100.0%,.000,.0%,687.000,100.0% -Table: Symmetric measures. -Category,Statistic,Value,Asymp. Std. Error,Approx. T,Approx. Sig. -Ordinal by Ordinal,Kendall's tau-b,.372,.033,10.669, -,Kendall's tau-c,.310,.029,10.669, -,Gamma,.591,.043,10.669, -N of Valid Cases,,687.000,,, +Table: Symmetric Measures +,,Value,Asymp. Std. Error,Approx. T +Ordinal by Ordinal,Kendall's tau-b,.372,.033,10.669 +,Kendall's tau-c,.310,.029,10.669 +,Gamma,.591,.043,10.669 +N of Valid Cases,,687.000,, -Table: Directional measures. -Category,Statistic,Type,Value,Asymp. Std. Error,Approx. T,Approx. Sig. +Table: Directional Measures +,,,Value,Asymp. Std. Error,Approx. T,Approx Sig. Ordinal by Ordinal,Somers' d,Symmetric,.371,,10.669,.000 ,,x Dependent,.351,.032,10.669,.000 ,,y Dependent,.394,.035,10.669,.000 ]) +AT_CLEANUP +AT_SETUP([CROSSTABS Somers' D, Tau-B, Tau-C, Gamma - 3]) AT_DATA([ordinal.sps], [dnl SET FORMAT F8.3. @@ -1430,159 +1477,160 @@ BEGIN DATA. END DATA. CROSSTABS x BY y/STATISTICS=LAMBDA D PHI BTAU/CELLS=NONE. ]) -AT_CHECK([pspp -O format=csv ordinal.sps], [0], [dnl -Table: Summary. +AT_CHECK([pspp -o pspp.csv -o pspp.txt ordinal.sps]) +AT_CHECK([cat pspp.csv], [0], [dnl +Table: Summary ,Cases,,,,, ,Valid,,Missing,,Total, ,N,Percent,N,Percent,N,Percent -x * y,150.000,100.0%,.000,0.0%,150.000,100.0% +x × y,150.000,100.0%,.000,.0%,150.000,100.0% -Table: Symmetric measures. -Category,Statistic,Value,Asymp. Std. Error,Approx. T,Approx. Sig. -Ordinal by Ordinal,Kendall's tau-b,1.000,.000,24.841, -,Gamma,1.000,.000,24.841, -N of Valid Cases,,150.000,,, +Table: Symmetric Measures +,,Value,Asymp. Std. Error,Approx. T +Ordinal by Ordinal,Kendall's tau-b,1.000,.000,24.841 +,Gamma,1.000,.000,24.841 +N of Valid Cases,,150.000,, -Table: Directional measures. -Category,Statistic,Type,Value,Asymp. Std. Error,Approx. T,Approx. Sig. +Table: Directional Measures +,,,Value,Asymp. Std. Error,Approx. T,Approx Sig. Ordinal by Ordinal,Somers' d,Symmetric,1.000,,24.841,.000 ,,x Dependent,1.000,.000,24.841,.000 ,,y Dependent,1.000,.000,24.841,.000 -Table: Summary. +Table: Summary ,Cases,,,,, ,Valid,,Missing,,Total, ,N,Percent,N,Percent,N,Percent -x * y,150.000,100.0%,.000,0.0%,150.000,100.0% +x × y,150.000,100.0%,.000,.0%,150.000,100.0% -Table: Symmetric measures. -Category,Statistic,Value,Asymp. Std. Error,Approx. T,Approx. Sig. -Ordinal by Ordinal,Kendall's tau-b,1.000,.000,24.841, -,Gamma,1.000,.000,24.841, -N of Valid Cases,,150.000,,, +Table: Symmetric Measures +,,Value,Asymp. Std. Error,Approx. T +Ordinal by Ordinal,Kendall's tau-b,1.000,.000,24.841 +,Gamma,1.000,.000,24.841 +N of Valid Cases,,150.000,, -Table: Directional measures. -Category,Statistic,Type,Value,Asymp. Std. Error,Approx. T,Approx. Sig. +Table: Directional Measures +,,,Value,Asymp. Std. Error,Approx. T,Approx Sig. Ordinal by Ordinal,Somers' d,Symmetric,1.000,,24.841,.000 ,,x Dependent,1.000,.000,24.841,.000 ,,y Dependent,1.000,.000,24.841,.000 -Table: Summary. +Table: Summary ,Cases,,,,, ,Valid,,Missing,,Total, ,N,Percent,N,Percent,N,Percent -x * y,150.000,100.0%,.000,0.0%,150.000,100.0% +x × y,150.000,100.0%,.000,.0%,150.000,100.0% -Table: Symmetric measures. -Category,Statistic,Value,Asymp. Std. Error,Approx. T,Approx. Sig. -Ordinal by Ordinal,Kendall's tau-b,-1.000,.000,-24.841, -,Gamma,-1.000,.000,-24.841, -N of Valid Cases,,150.000,,, +Table: Symmetric Measures +,,Value,Asymp. Std. Error,Approx. T +Ordinal by Ordinal,Kendall's tau-b,-1.000,.000,-24.841 +,Gamma,-1.000,.000,-24.841 +N of Valid Cases,,150.000,, -Table: Directional measures. -Category,Statistic,Type,Value,Asymp. Std. Error,Approx. T,Approx. Sig. +Table: Directional Measures +,,,Value,Asymp. Std. Error,Approx. T,Approx Sig. Ordinal by Ordinal,Somers' d,Symmetric,-1.000,,-24.841,.000 ,,x Dependent,-1.000,.000,-24.841,.000 ,,y Dependent,-1.000,.000,-24.841,.000 -Table: Summary. +Table: Summary ,Cases,,,,, ,Valid,,Missing,,Total, ,N,Percent,N,Percent,N,Percent -x * y,150.000,100.0%,.000,0.0%,150.000,100.0% +x × y,150.000,100.0%,.000,.0%,150.000,100.0% -Table: Symmetric measures. -Category,Statistic,Value,Asymp. Std. Error,Approx. T,Approx. Sig. -Ordinal by Ordinal,Kendall's tau-b,.972,.007,24.841, -,Gamma,1.000,.000,24.841, -N of Valid Cases,,150.000,,, +Table: Symmetric Measures +,,Value,Asymp. Std. Error,Approx. T +Ordinal by Ordinal,Kendall's tau-b,.972,.007,24.841 +,Gamma,1.000,.000,24.841 +N of Valid Cases,,150.000,, -Table: Directional measures. -Category,Statistic,Type,Value,Asymp. Std. Error,Approx. T,Approx. Sig. +Table: Directional Measures +,,,Value,Asymp. Std. Error,Approx. T,Approx Sig. Ordinal by Ordinal,Somers' d,Symmetric,.971,,24.841,.000 ,,x Dependent,.944,.013,24.841,.000 ,,y Dependent,1.000,.000,24.841,.000 -Table: Summary. +Table: Summary ,Cases,,,,, ,Valid,,Missing,,Total, ,N,Percent,N,Percent,N,Percent -x * y,150.000,100.0%,.000,0.0%,150.000,100.0% +x × y,150.000,100.0%,.000,.0%,150.000,100.0% -Table: Symmetric measures. -Category,Statistic,Value,Asymp. Std. Error,Approx. T,Approx. Sig. -Ordinal by Ordinal,Kendall's tau-b,.119,.059,1.009, -,Gamma,1.000,.000,1.009, -N of Valid Cases,,150.000,,, +Table: Symmetric Measures +,,Value,Asymp. Std. Error,Approx. T +Ordinal by Ordinal,Kendall's tau-b,.119,.059,1.009 +,Gamma,1.000,.000,1.009 +N of Valid Cases,,150.000,, -Table: Directional measures. -Category,Statistic,Type,Value,Asymp. Std. Error,Approx. T,Approx. Sig. +Table: Directional Measures +,,,Value,Asymp. Std. Error,Approx. T,Approx Sig. Ordinal by Ordinal,Somers' d,Symmetric,.035,,1.009,.313 ,,x Dependent,.805,.032,1.009,.313 ,,y Dependent,.018,.017,1.009,.313 -Table: Summary. +Table: Summary ,Cases,,,,, ,Valid,,Missing,,Total, ,N,Percent,N,Percent,N,Percent -x * y,148.000,100.0%,.000,0.0%,148.000,100.0% +x × y,148.000,100.0%,.000,.0%,148.000,100.0% -Table: Symmetric measures. -Category,Statistic,Value,Asymp. Std. Error,Approx. T,Approx. Sig. -Ordinal by Ordinal,Kendall's tau-b,-.208,.078,-2.641, -,Gamma,-.381,.130,-2.641, -N of Valid Cases,,148.000,,, +Table: Symmetric Measures +,,Value,Asymp. Std. Error,Approx. T +Ordinal by Ordinal,Kendall's tau-b,-.208,.078,-2.641 +,Gamma,-.381,.130,-2.641 +N of Valid Cases,,148.000,, -Table: Directional measures. -Category,Statistic,Type,Value,Asymp. Std. Error,Approx. T,Approx. Sig. +Table: Directional Measures +,,,Value,Asymp. Std. Error,Approx. T,Approx Sig. Ordinal by Ordinal,Somers' d,Symmetric,-.206,,-2.641,.008 ,,x Dependent,-.182,.069,-2.641,.008 ,,y Dependent,-.237,.089,-2.641,.008 -Table: Summary. +Table: Summary ,Cases,,,,, ,Valid,,Missing,,Total, ,N,Percent,N,Percent,N,Percent -x * y,148.000,100.0%,.000,0.0%,148.000,100.0% +x × y,148.000,100.0%,.000,.0%,148.000,100.0% -Table: Symmetric measures. -Category,Statistic,Value,Asymp. Std. Error,Approx. T,Approx. Sig. -Nominal by Nominal,Phi,.731,,, -,Cramer's V,.731,,, -Ordinal by Ordinal,Gamma,-.110,.107,-1.022, -N of Valid Cases,,148.000,,, +Table: Symmetric Measures +,,Value,Asymp. Std. Error,Approx. T +Nominal by Nominal,Phi,.731,, +,Cramer's V,.731,, +Ordinal by Ordinal,Gamma,-.110,.107,-1.022 +N of Valid Cases,,148.000,, -Table: Directional measures. -Category,Statistic,Type,Value,Asymp. Std. Error,Approx. T,Approx. Sig. +Table: Directional Measures +,,,Value,Asymp. Std. Error,Approx. T,Approx Sig. Nominal by Nominal,Lambda,Symmetric,.338,.059,4.743,.000 ,,x Dependent,.640,.085,4.875,.000 ,,y Dependent,.174,.050,3.248,.001 -,Goodman and Kruskal tau,x Dependent,.534,,,. @&t@ -,,y Dependent,.167,,,. @&t@ +,Goodman and Kruskal tau,x Dependent,.534,,, +,,y Dependent,.167,,, Ordinal by Ordinal,Somers' d,Symmetric,-.074,,-1.022,.307 ,,x Dependent,-.060,.059,-1.022,.307 ,,y Dependent,-.096,.094,-1.022,.307 -Table: Summary. +Table: Summary ,Cases,,,,, ,Valid,,Missing,,Total, ,N,Percent,N,Percent,N,Percent -x * y,212.000,100.0%,.000,0.0%,212.000,100.0% +x × y,212.000,100.0%,.000,.0%,212.000,100.0% -Table: Symmetric measures. -Category,Statistic,Value,Asymp. Std. Error,Approx. T,Approx. Sig. -Nominal by Nominal,Phi,.432,,, -,Cramer's V,.249,,, -Ordinal by Ordinal,Kendall's tau-b,.209,.062,3.338, -N of Valid Cases,,212.000,,, +Table: Symmetric Measures +,,Value,Asymp. Std. Error,Approx. T +Nominal by Nominal,Phi,.432,, +,Cramer's V,.249,, +Ordinal by Ordinal,Kendall's tau-b,.209,.062,3.338 +N of Valid Cases,,212.000,, -Table: Directional measures. -Category,Statistic,Type,Value,Asymp. Std. Error,Approx. T,Approx. Sig. +Table: Directional Measures +,,,Value,Asymp. Std. Error,Approx. T,Approx Sig. Nominal by Nominal,Lambda,Symmetric,.102,.067,1.473,.141 ,,x Dependent,.027,.087,.302,.763 ,,y Dependent,.165,.065,2.349,.019 -,Goodman and Kruskal tau,x Dependent,.051,,,. @&t@ -,,y Dependent,.068,,,. @&t@ +,Goodman and Kruskal tau,x Dependent,.051,,, +,,y Dependent,.068,,, Ordinal by Ordinal,Somers' d,Symmetric,.209,,3.338,.001 ,,x Dependent,.202,.060,3.338,.001 ,,y Dependent,.217,.064,3.338,.001 @@ -1611,24 +1659,25 @@ crosstabs /table = p1 by p2 . ]) -AT_CHECK([pspp -O format=csv kappa.sps], [0], [dnl -Table: Summary. +AT_CHECK([pspp -o pspp.csv -o pspp.txt kappa.sps]) +AT_CHECK([cat pspp.csv], [0], [dnl +Table: Summary ,Cases,,,,, ,Valid,,Missing,,Total, ,N,Percent,N,Percent,N,Percent -p1 * p2,20.000,100.0%,.000,0.0%,20.000,100.0% - -Table: p1 * p2 [[count]]. -,p2,, -p1,.000,1.000,Total -.000,18.000,1.000,19.000 -1.000,1.000,.000,1.000 -Total,19.000,1.000,20.000 - -Table: Symmetric measures. -Category,Statistic,Value,Asymp. Std. Error,Approx. T,Approx. Sig. -Measure of Agreement,Kappa,-.053,.037,-.235, -N of Valid Cases,,20.000,,, +p1 × p2,20.000,100.0%,.000,.0%,20.000,100.0% + +Table: p1 × p2 +,,,p2,,Total +,,,.000,1.000, +p1,.000,Count,18.000,1.000,19.000 +,1.000,,1.000,.000,1.000 +Total,,,19.000,1.000,20.000 + +Table: Symmetric Measures +,,Value,Asymp. Std. Error,Approx. T +Measure of Agreement,Kappa,-.053,.037,-.235 +N of Valid Cases,,20.000,, ]) AT_CLEANUP @@ -1650,42 +1699,43 @@ BEGIN DATA. END DATA. CROSSTABS x BY y/STATISTICS=CHISQ PHI CC LAMBDA UC BTAU CTAU GAMMA D CORR/CELLS=NONE. ]) -AT_CHECK([pspp -O format=csv crosstabs.sps], [0], [dnl -Table: Summary. +AT_CHECK([pspp -o pspp.csv -o pspp.txt crosstabs.sps]) +AT_CHECK([cat pspp.csv], [0], [dnl +Table: Summary ,Cases,,,,, ,Valid,,Missing,,Total, ,N,Percent,N,Percent,N,Percent -x * y,66.0000,100.0%,.0000,0.0%,66.0000,100.0% +x × y,66.0000,100.0%,.0000,.0%,66.0000,100.0% -Table: Chi-square tests. -Statistic,Value,df,Asymp. Sig. (2-tailed) +Table: Chi-Square Tests +,Value,df,Asymptotic Sig. (2-tailed) Pearson Chi-Square,6.9562,2.0000,.031 Likelihood Ratio,6.6901,2.0000,.035 Linear-by-Linear Association,5.8450,1.0000,.016 N of Valid Cases,66.0000,, -Table: Symmetric measures. -Category,Statistic,Value,Asymp. Std. Error,Approx. T,Approx. Sig. -Nominal by Nominal,Phi,.3246,,, -,Cramer's V,.3246,,, -,Contingency Coefficient,.3088,,, -Ordinal by Ordinal,Kendall's tau-b,.2752,.0856,1.9920, -,Kendall's tau-c,.1497,.0751,1.9920, -,Gamma,.8717,.1250,1.9920, -,Spearman Correlation,.2908,.0906,2.4311, -Interval by Interval,Pearson's R,.2999,.0973,2.5147, -N of Valid Cases,,66.0000,,, - -Table: Directional measures. -Category,Statistic,Type,Value,Asymp. Std. Error,Approx. T,Approx. Sig. +Table: Symmetric Measures +,,Value,Asymp. Std. Error,Approx. T +Nominal by Nominal,Phi,.3246,, +,Cramer's V,.3246,, +,Contingency Coefficient,.3088,, +Ordinal by Ordinal,Kendall's tau-b,.2752,.0856,1.9920 +,Kendall's tau-c,.1497,.0751,1.9920 +,Gamma,.8717,.1250,1.9920 +,Spearman Correlation,.2908,.0906,2.4311 +Interval by Interval,Pearson's R,.2999,.0973,2.5147 +N of Valid Cases,,66.0000,, + +Table: Directional Measures +,,,Value,Asymp. Std. Error,Approx. T,Approx Sig. Nominal by Nominal,Lambda,Symmetric,.0455,.1629,.2723,.785 ,,x Dependent,.0000,.0000,NaN,NaN ,,y Dependent,.0500,.1791,.2723,.785 -,Goodman and Kruskal tau,x Dependent,.1054,,,. @&t@ -,,y Dependent,.0434,,,. @&t@ -,Uncertainty Coefficient,Symmetric,.0780,.0474,,. @&t@ -,,x Dependent,.2217,.1062,1.5373,. @&t@ -,,y Dependent,.0473,.0306,1.5373,. @&t@ +,Goodman and Kruskal tau,x Dependent,.1054,,, +,,y Dependent,.0434,,, +,Uncertainty Coefficient,Symmetric,.0780,.0474,, +,,x Dependent,.2217,.1062,1.5373, +,,y Dependent,.0473,.0306,1.5373, Ordinal by Ordinal,Somers' d,Symmetric,.1960,,1.9920,.046 ,,x Dependent,.1152,.0572,1.9920,.046 ,,y Dependent,.6573,.1417,1.9920,.046 @@ -1709,27 +1759,82 @@ BEGIN DATA. END DATA. CROSSTABS x BY y/STATISTICS=LAMBDA UC/CELLS=NONE. ]) -AT_CHECK([pspp -O format=csv uc.sps], [0], [dnl -Table: Summary. +AT_CHECK([pspp -o pspp.csv -o pspp.txt uc.sps]) +AT_CHECK([cat pspp.csv], [0], [dnl +Table: Summary ,Cases,,,,, ,Valid,,Missing,,Total, ,N,Percent,N,Percent,N,Percent -x * y,987.000,100.0%,.000,0.0%,987.000,100.0% +x × y,987.000,100.0%,.000,.0%,987.000,100.0% -Table: Directional measures. -Category,Statistic,Type,Value,Asymp. Std. Error,Approx. T,Approx. Sig. +Table: Directional Measures +,,,Value,Asymp. Std. Error,Approx. T,Approx Sig. Nominal by Nominal,Lambda,Symmetric,.000,.000,NaN,NaN ,,x Dependent,.000,.000,NaN,NaN ,,y Dependent,.000,.000,NaN,NaN -,Goodman and Kruskal tau,x Dependent,.076,,,. @&t@ -,,y Dependent,.108,,,. @&t@ -,Uncertainty Coefficient,Symmetric,.105,.012,,. @&t@ -,,x Dependent,.073,.009,7.890,. @&t@ -,,y Dependent,.184,.019,7.890,. @&t@ +,Goodman and Kruskal tau,x Dependent,.076,,, +,,y Dependent,.108,,, +,Uncertainty Coefficient,Symmetric,.105,.012,, +,,x Dependent,.073,.009,7.890, +,,y Dependent,.184,.019,7.890, ]) AT_CLEANUP +AT_SETUP([CROSSTABS estimated risk]) +dnl Example data and expected output from +dnl http://www.psychology.nottingham.ac.uk/staff/ddc/c8cxpa/further/Project_resources/SPSSCrosstabW.pdf +AT_DATA([risk.sps], [dnl +DATA LIST LIST /factor disease count (F8.0). +WEIGHT BY count. +VALUE LABELS /factor 0 'Placebo' 1 'Aspirin' + /disease 1 'No' 0 'Yes'. +BEGIN DATA. +0 1 80 +0 0 20 +1 1 135 +1 0 15 +END DATA. +CROSSTABS factor BY disease/STATISTICS=RISK CHISQ. +]) +AT_CHECK([pspp -o pspp.csv -o pspp.txt risk.sps]) +AT_CHECK([cat pspp.csv], [0], [dnl +Table: Reading free-form data from INLINE. +Variable,Format +factor,F8.0 +disease,F8.0 +count,F8.0 +Table: Summary +,Cases,,,,, +,Valid,,Missing,,Total, +,N,Percent,N,Percent,N,Percent +factor × disease,250,100.0%,0,.0%,250,100.0% + +Table: factor × disease +,,,disease,,Total +,,,Yes,No, +factor,Placebo,Count,20,80,100 +,Aspirin,,15,135,150 +Total,,,35,215,250 + +Table: Chi-Square Tests +,Value,df,Asymptotic Sig. (2-tailed),Exact Sig. (2-tailed),Exact Sig. (1-tailed) +Pearson Chi-Square,4.98,1,.026,, +Likelihood Ratio,4.88,1,.027,, +Fisher's Exact Test,,,,.039,.021 +Continuity Correction,4.19,1,.041,, +Linear-by-Linear Association,4.96,1,.026,, +N of Valid Cases,250,,,, + +Table: Risk Estimate +,Value,95% Confidence Interval, +,,Lower,Upper +Odds Ratio for factor (Placebo / Aspirin),2.25,2.25,2.25 +For cohort disease = Yes,1.08,1.08,1.08 +For cohort disease = No,.99,.99,.99 +N of Valid Cases,250.00,, +]) +AT_CLEANUP AT_SETUP([CROSSTABS barchart]) AT_DATA([bc.sps], [dnl diff --git a/tests/language/stats/descriptives.at b/tests/language/stats/descriptives.at index 508f954e12..60ec213097 100644 --- a/tests/language/stats/descriptives.at +++ b/tests/language/stats/descriptives.at @@ -57,25 +57,27 @@ V14,1,15- 15,F1.0 V15,1,16- 16,F1.0 V16,1,17- 17,F1.0 -Table: Valid cases = 10; cases with missing value(s) = 0. -Variable,Valid N,Missing N,Mean,S.E. Mean,Std Dev,Variance,Kurtosis,S.E. Kurt,Skewness,S.E. Skew,Range,Minimum,Maximum,Sum -V0,10,0,3.80,.84,2.66,7.07,-.03,1.33,.89,.69,8.00,1.00,9.00,38.00 -V1,10,0,4.60,.96,3.03,9.16,-1.39,1.33,-.03,.69,9.00,.00,9.00,46.00 -V2,10,0,4.10,1.16,3.67,13.43,-2.02,1.33,.48,.69,8.00,1.00,9.00,41.00 -V3,10,0,4.10,.87,2.77,7.66,-2.05,1.33,.42,.69,7.00,1.00,8.00,41.00 -V4,10,0,7.00,.47,1.49,2.22,7.15,1.33,-2.52,.69,5.00,3.00,8.00,70.00 -V5,10,0,4.90,1.03,3.25,10.54,-1.40,1.33,-.20,.69,9.00,.00,9.00,49.00 -V6,10,0,5.90,.80,2.51,6.32,-.29,1.33,-.96,.69,7.00,1.00,8.00,59.00 -V7,10,0,4.70,1.10,3.47,12.01,-1.99,1.33,-.16,.69,9.00,.00,9.00,47.00 -V8,10,0,4.10,1.10,3.48,12.10,-1.93,1.33,.37,.69,9.00,.00,9.00,41.00 -V9,10,0,4.30,.87,2.75,7.57,-.87,1.33,.73,.69,8.00,1.00,9.00,43.00 -V10,10,0,5.50,.85,2.68,7.17,-1.84,1.33,-.33,.69,7.00,2.00,9.00,55.00 -V11,10,0,6.50,.78,2.46,6.06,-1.28,1.33,-.89,.69,6.00,3.00,9.00,65.00 -V12,10,0,7.90,.60,1.91,3.66,5.24,1.33,-2.21,.69,6.00,3.00,9.00,79.00 -V13,10,0,4.30,.99,3.13,9.79,-1.25,1.33,.33,.69,9.00,.00,9.00,43.00 -V14,10,0,3.60,1.01,3.20,10.27,-.96,1.33,.81,.69,9.00,.00,9.00,36.00 -V15,10,0,3.70,.92,2.91,8.46,-1.35,1.33,.71,.69,7.00,1.00,8.00,37.00 -V16,10,0,6.40,.91,2.88,8.27,-1.14,1.33,-.92,.69,7.00,2.00,9.00,64.00 +Table: Descriptive Statistics +,N,Mean,S.E. Mean,Std Dev,Variance,Kurtosis,S.E. Kurt,Skewness,S.E. Skew,Range,Minimum,Maximum,Sum +V0,10,3.80,.84,2.66,7.07,-.03,1.33,.89,.69,8.00,1,9,38.00 +V1,10,4.60,.96,3.03,9.16,-1.39,1.33,-.03,.69,9.00,0,9,46.00 +V2,10,4.10,1.16,3.67,13.43,-2.02,1.33,.48,.69,8.00,1,9,41.00 +V3,10,4.10,.87,2.77,7.66,-2.05,1.33,.42,.69,7.00,1,8,41.00 +V4,10,7.00,.47,1.49,2.22,7.15,1.33,-2.52,.69,5.00,3,8,70.00 +V5,10,4.90,1.03,3.25,10.54,-1.40,1.33,-.20,.69,9.00,0,9,49.00 +V6,10,5.90,.80,2.51,6.32,-.29,1.33,-.96,.69,7.00,1,8,59.00 +V7,10,4.70,1.10,3.47,12.01,-1.99,1.33,-.16,.69,9.00,0,9,47.00 +V8,10,4.10,1.10,3.48,12.10,-1.93,1.33,.37,.69,9.00,0,9,41.00 +V9,10,4.30,.87,2.75,7.57,-.87,1.33,.73,.69,8.00,1,9,43.00 +V10,10,5.50,.85,2.68,7.17,-1.84,1.33,-.33,.69,7.00,2,9,55.00 +V11,10,6.50,.78,2.46,6.06,-1.28,1.33,-.89,.69,6.00,3,9,65.00 +V12,10,7.90,.60,1.91,3.66,5.24,1.33,-2.21,.69,6.00,3,9,79.00 +V13,10,4.30,.99,3.13,9.79,-1.25,1.33,.33,.69,9.00,0,9,43.00 +V14,10,3.60,1.01,3.20,10.27,-.96,1.33,.81,.69,9.00,0,9,36.00 +V15,10,3.70,.92,2.91,8.46,-1.35,1.33,.71,.69,7.00,1,8,37.00 +V16,10,6.40,.91,2.88,8.27,-1.14,1.33,-.92,.69,7.00,2,9,64.00 +Valid N (listwise),10,,,,,,,,,,,, +Missing N (listwise),0,,,,,,,,,,,, ]) AT_CLEANUP @@ -98,12 +100,14 @@ AT_DATA([descriptives.sps], [DESCRIPTIVES_MISSING_DATA descript all/stat=all/format=serial. ]) -AT_CHECK([pspp -O format=csv descriptives.sps], [0], - [Table: Valid cases = 7; cases with missing value(s) = 6. -Variable,Valid N,Missing N,Mean,S.E. Mean,Std Dev,Variance,Kurtosis,S.E. Kurt,Skewness,S.E. Skew,Range,Minimum,Maximum,Sum -V1,1,6,2.00,. ,. ,. ,. ,. ,. ,. ,.00,2.00,2.00,2.00 -V2,2,5,2.50,.50,.71,.50,. ,. ,. ,. ,1.00,2.00,3.00,5.00 -V3,3,4,3.00,.58,1.00,1.00,. ,. ,.00,1.22,2.00,2.00,4.00,9.00 +AT_CHECK([pspp -O format=csv descriptives.sps], [0], [dnl +Table: Descriptive Statistics +,N,Mean,S.E. Mean,Std Dev,Variance,Kurtosis,S.E. Kurt,Skewness,S.E. Skew,Range,Minimum,Maximum,Sum +V1,1,2.00,. ,. ,. ,. ,. ,. ,. ,.00,2,2,2.00 +V2,2,2.50,.50,.71,.50,. ,. ,. ,. ,1.00,2,3,5.00 +V3,3,3.00,.58,1.00,1.00,. ,. ,.00,1.22,2.00,2,4,9.00 +Valid N (listwise),7,,,,,,,,,,,, +Missing N (listwise),6,,,,,,,,,,,, ]) AT_CLEANUP @@ -112,12 +116,14 @@ AT_DATA([descriptives.sps], [DESCRIPTIVES_MISSING_DATA descript all/stat=all/format=serial/missing=include. ]) -AT_CHECK([pspp -O format=csv descriptives.sps], [0], - [Table: Valid cases = 7; cases with missing value(s) = 3. -Variable,Valid N,Missing N,Mean,S.E. Mean,Std Dev,Variance,Kurtosis,S.E. Kurt,Skewness,S.E. Skew,Range,Minimum,Maximum,Sum -V1,5,2,1.20,.20,.45,.20,5.00,2.00,2.24,.91,1.00,1.00,2.00,6.00 -V2,5,2,1.60,.40,.89,.80,.31,2.00,1.26,.91,2.00,1.00,3.00,8.00 -V3,5,2,2.20,.58,1.30,1.70,-1.49,2.00,.54,.91,3.00,1.00,4.00,11.00 +AT_CHECK([pspp -O format=csv descriptives.sps], [0], [dnl +Table: Descriptive Statistics +,N,Mean,S.E. Mean,Std Dev,Variance,Kurtosis,S.E. Kurt,Skewness,S.E. Skew,Range,Minimum,Maximum,Sum +V1,5,1.20,.20,.45,.20,5.00,2.00,2.24,.91,1.00,1,2,6.00 +V2,5,1.60,.40,.89,.80,.31,2.00,1.26,.91,2.00,1,3,8.00 +V3,5,2.20,.58,1.30,1.70,-1.49,2.00,.54,.91,3.00,1,4,11.00 +Valid N (listwise),7,,,,,,,,,,,, +Missing N (listwise),3,,,,,,,,,,,, ]) AT_CLEANUP @@ -126,12 +132,14 @@ AT_DATA([descriptives.sps], [DESCRIPTIVES_MISSING_DATA descript all/stat=all/format=serial/missing=listwise. ]) -AT_CHECK([pspp -O format=csv descriptives.sps], [0], - [Table: Valid cases = 1; cases with missing value(s) = 6. -Variable,Valid N,Missing N,Mean,S.E. Mean,Std Dev,Variance,Kurtosis,S.E. Kurt,Skewness,S.E. Skew,Range,Minimum,Maximum,Sum -V1,1,0,2.00,. ,. ,. ,. ,. ,. ,. ,.00,2.00,2.00,2.00 -V2,1,0,3.00,. ,. ,. ,. ,. ,. ,. ,.00,3.00,3.00,3.00 -V3,1,0,4.00,. ,. ,. ,. ,. ,. ,. ,.00,4.00,4.00,4.00 +AT_CHECK([pspp -O format=csv descriptives.sps], [0], [dnl +Table: Descriptive Statistics +,N,Mean,S.E. Mean,Std Dev,Variance,Kurtosis,S.E. Kurt,Skewness,S.E. Skew,Range,Minimum,Maximum,Sum +V1,1,2.00,. ,. ,. ,. ,. ,. ,. ,.00,2,2,2.00 +V2,1,3.00,. ,. ,. ,. ,. ,. ,. ,.00,3,3,3.00 +V3,1,4.00,. ,. ,. ,. ,. ,. ,. ,.00,4,4,4.00 +Valid N (listwise),1,,,,,,,,,,,, +Missing N (listwise),6,,,,,,,,,,,, ]) AT_CLEANUP @@ -140,12 +148,14 @@ AT_DATA([descriptives.sps], [DESCRIPTIVES_MISSING_DATA descript all/stat=all/format=serial/missing=listwise include. ]) -AT_CHECK([pspp -O format=csv descriptives.sps], [0], - [Table: Valid cases = 4; cases with missing value(s) = 3. -Variable,Valid N,Missing N,Mean,S.E. Mean,Std Dev,Variance,Kurtosis,S.E. Kurt,Skewness,S.E. Skew,Range,Minimum,Maximum,Sum -V1,4,0,1.25,.25,.50,.25,4.00,2.62,2.00,1.01,1.00,1.00,2.00,5.00 -V2,4,0,1.75,.48,.96,.92,-1.29,2.62,.85,1.01,2.00,1.00,3.00,7.00 -V3,4,0,2.50,.65,1.29,1.67,-1.20,2.62,.00,1.01,3.00,1.00,4.00,10.00 +AT_CHECK([pspp -O format=csv descriptives.sps], [0], [dnl +Table: Descriptive Statistics +,N,Mean,S.E. Mean,Std Dev,Variance,Kurtosis,S.E. Kurt,Skewness,S.E. Skew,Range,Minimum,Maximum,Sum +V1,4,1.25,.25,.50,.25,4.00,2.62,2.00,1.01,1.00,1,2,5.00 +V2,4,1.75,.48,.96,.92,-1.29,2.62,.85,1.01,2.00,1,3,7.00 +V3,4,2.50,.65,1.29,1.67,-1.20,2.62,.00,1.01,3.00,1,4,10.00 +Valid N (listwise),4,,,,,,,,,,,, +Missing N (listwise),3,,,,,,,,,,,, ]) AT_CLEANUP @@ -165,10 +175,12 @@ end data. descript all/stat=mean. ]) -AT_CHECK([pspp -O format=csv descriptives.sps], [0], - [Table: Valid cases = 6; cases with missing value(s) = 0. -Variable,N,Mean +AT_CHECK([pspp -O format=csv descriptives.sps], [0], [dnl +Table: Descriptive Statistics +,N,Mean X,6,2.500 +Valid N (listwise),6, +Missing N (listwise),0, ]) AT_CLEANUP @@ -194,9 +206,11 @@ SELECT IF id < 7 . DESCRIPTIVES /VAR=abc. ]) AT_CHECK([pspp -O format=csv descriptives.sps], [0], [dnl -Table: Valid cases = 6; cases with missing value(s) = 0. -Variable,N,Mean,Std Dev,Minimum,Maximum +Table: Descriptive Statistics +,N,Mean,Std Dev,Minimum,Maximum abc,6,3.00,.84,2.00,4.00 +Valid N (listwise),6,,,, +Missing N (listwise),0,,,, ]) AT_CLEANUP @@ -213,15 +227,17 @@ DESCRIPTIVES /VAR=a b /SAVE. LIST. ]) AT_CHECK([pspp -O format=csv descriptives.sps], [0], [dnl -Table: Mapping of variables to corresponding Z-scores. +Table: Mapping of Variables to Z-scores Source,Target a,Za b,Zb -Table: Valid cases = 3; cases with missing value(s) = 0. -Variable,N,Mean,Std Dev,Minimum,Maximum +Table: Descriptive Statistics +,N,Mean,Std Dev,Minimum,Maximum a,3,2.00,1.00,1.00,3.00 b,3,60.00,10.00,50.00,70.00 +Valid N (listwise),3,,,, +Missing N (listwise),0,,,, Table: Data List a,b,Za,Zb @@ -248,30 +264,38 @@ SPLIT FILE BY group. DESCRIPTIVES /VAR=a b /SAVE. LIST. ]) -AT_CHECK([pspp -O format=csv descriptives.sps], [0], [dnl -Table: Mapping of variables to corresponding Z-scores. +AT_CHECK([pspp -o pspp.csv -o pspp.txt descriptives.sps]) +AT_CHECK([cat pspp.csv], [0], [dnl +Table: Mapping of Variables to Z-scores Source,Target a,Za b,Zb -Variable,Value,Label -group,1.00, +Table: Split Values +Variable,Value +group,1.00 -Table: Valid cases = 3; cases with missing value(s) = 0. -Variable,N,Mean,Std Dev,Minimum,Maximum +Table: Descriptive Statistics +,N,Mean,Std Dev,Minimum,Maximum a,3,2.00,1.00,1.00,3.00 b,3,60.00,10.00,50.00,70.00 +Valid N (listwise),3,,,, +Missing N (listwise),0,,,, -Variable,Value,Label -group,2.00, +Table: Split Values +Variable,Value +group,2.00 -Table: Valid cases = 4; cases with missing value(s) = 0. -Variable,N,Mean,Std Dev,Minimum,Maximum +Table: Descriptive Statistics +,N,Mean,Std Dev,Minimum,Maximum a,4,300.00,182.57,100.00,500.00 b,4,8000.00,1825.74,6000.00,10000.00 +Valid N (listwise),4,,,, +Missing N (listwise),0,,,, -Variable,Value,Label -group,1.00, +Table: Split Values +Variable,Value +group,1.00 Table: Data List group,a,b,Za,Zb @@ -279,8 +303,9 @@ group,a,b,Za,Zb 1.00,2.00,60.00,.00,.00 1.00,3.00,70.00,1.00,1.00 -Variable,Value,Label -group,2.00, +Table: Split Values +Variable,Value +group,2.00 Table: Data List group,a,b,Za,Zb @@ -314,16 +339,21 @@ SELECT IF id < 7 . DESCRIPTIVES /VAR=abc/SAVE. LIST. ]) -AT_CHECK([pspp -O format=csv descriptives.sps], [0], [dnl +AT_CHECK([pspp -o pspp.csv -o pspp.txt descriptives.sps], [0], [dnl +descriptives.sps:15: warning: DESCRIPTIVES: DESCRIPTIVES with Z scores ignores TEMPORARY. Temporary transformations will be made permanent. +]) +AT_CHECK([cat pspp.csv], [0], [dnl descriptives.sps:15: warning: DESCRIPTIVES: DESCRIPTIVES with Z scores ignores TEMPORARY. Temporary transformations will be made permanent. -Table: Mapping of variables to corresponding Z-scores. +Table: Mapping of Variables to Z-scores Source,Target abc,Zabc -Table: Valid cases = 6; cases with missing value(s) = 0. -Variable,N,Mean,Std Dev,Minimum,Maximum +Table: Descriptive Statistics +,N,Mean,Std Dev,Minimum,Maximum abc,6,3.00,.84,2.00,4.00 +Valid N (listwise),6,,,, +Missing N (listwise),0,,,, Table: Data List id,abc,Zabc @@ -391,3 +421,24 @@ filter1,filter2,x,Zx,ZSC001,ZSC002,ZSC003,ZSC004 1.00,1.00,1.00,-.66,-1.26,-1.26,-1.00,-1.00 ]) AT_CLEANUP + +dnl This is an example from doc/tutorial.texi +dnl So if the results of this have to be changed in any way, +dnl make sure to update that file. +AT_SETUP([DESCRIPTIVES tutorial example]) +cp $top_srcdir/examples/physiology.sav . +AT_DATA([descriptives.sps], [dnl +GET FILE='physiology.sav'. +DESCRIPTIVES sex, weight, height. +]) +AT_CHECK([pspp -o pspp.csv -o pspp.txt descriptives.sps]) +AT_CHECK([cat pspp.csv], [0], [dnl +Table: Descriptive Statistics +,N,Mean,Std Dev,Minimum,Maximum +Sex of subject ,40,.45,.50,Male,Female +Weight in kilograms ,40,72.12,26.70,-55.6,92.1 +Height in millimeters ,40,1677.12,262.87,179,1903 +Valid N (listwise),40,,,, +Missing N (listwise),0,,,, +]) +AT_CLEANUP diff --git a/tests/language/stats/examine.at b/tests/language/stats/examine.at index 9d4374d376..b2afe616b8 100644 --- a/tests/language/stats/examine.at +++ b/tests/language/stats/examine.at @@ -87,7 +87,7 @@ Table: Case Processing Summary ,Cases,,,,, ,Valid,,Missing,,Total, ,N,Percent,N,Percent,N,Percent -Breaking Strain,24.00,100%,.00,0%,24.00,100% +Breaking Strain,24.00,100.0%,.00,.0%,24.00,100.0% Table: Extreme Values ,,,Case Number,Value @@ -118,9 +118,9 @@ Table: Case Processing Summary ,,Cases,,,,, ,,Valid,,Missing,,Total, ,Manufacturer,N,Percent,N,Percent,N,Percent -Breaking Strain,Aspeger,8.00,100%,.00,0%,8.00,100% -,Bloggs,8.00,100%,.00,0%,8.00,100% -,Charlies,8.00,100%,.00,0%,8.00,100% +Breaking Strain,Aspeger,8.00,100.0%,.00,.0%,8.00,100.0% +,Bloggs,8.00,100.0%,.00,.0%,8.00,100.0% +,Charlies,8.00,100.0%,.00,.0%,8.00,100.0% Table: Extreme Values ,Manufacturer,,,Case Number,Value @@ -228,7 +228,7 @@ Table: Case Processing Summary ,Cases,,,,, ,Valid,,Missing,,Total, ,N,Percent,N,Percent,N,Percent -V1,23.00,100%,.00,0%,23.00,100% +V1,23.00,100.0%,.00,.0%,23.00,100.0% Table: Extreme Values ,,,Case Number,Value @@ -290,7 +290,7 @@ Table: Case Processing Summary ,Cases,,,,, ,Valid,,Missing,,Total, ,N,Percent,N,Percent,N,Percent -x,19.430,100%,.000,0%,19.430,100% +x,19.430,100.0%,.000,.0%,19.430,100.0% Table: Extreme Values ,,,Case Number,Value @@ -352,7 +352,7 @@ EXAMINE /x EXAMINE /x /PERCENTILES=AEMPIRICAL. ]) -AT_CHECK([pspp -o pspp.csv examine.sps]) +AT_CHECK([pspp -o pspp.csv -o pspp.txt examine.sps]) AT_CHECK([cat pspp.csv], [0], [dnl Table: Reading free-form data from INLINE. Variable,Format @@ -362,19 +362,19 @@ Table: Case Processing Summary ,Cases,,,,, ,Valid,,Missing,,Total, ,N,Percent,N,Percent,N,Percent -X,3,100%,0,0%,3,100% +X,3,100.0%,0,.0%,3,100.0% Table: Percentiles ,,Percentiles,,,,,, ,,5,10,25,50,75,90,95 -X,HAverage,.40,.80,2.00,5.00,8.00,8.00,8.00 +X,Weighted Average,.40,.80,2.00,5.00,8.00,8.00,8.00 ,Tukey's Hinges,,,3.50,5.00,6.50,, Table: Case Processing Summary ,Cases,,,,, ,Valid,,Missing,,Total, ,N,Percent,N,Percent,N,Percent -X,3,100%,0,0%,3,100% +X,3,100.0%,0,.0%,3,100.0% Table: Percentiles ,,Percentiles,,,,,, @@ -386,36 +386,36 @@ Table: Case Processing Summary ,Cases,,,,, ,Valid,,Missing,,Total, ,N,Percent,N,Percent,N,Percent -X,3,100%,0,0%,3,100% +X,3,100.0%,0,.0%,3,100.0% Table: Percentiles ,,Percentiles,,,,,, ,,5,10,25,50,75,90,95 -X,Rounded,.00,.00,2.00,5.00,5.00,8.00,8.00 +X,Weighted Average,.00,.00,2.00,5.00,5.00,8.00,8.00 ,Tukey's Hinges,,,3.50,5.00,6.50,, Table: Case Processing Summary ,Cases,,,,, ,Valid,,Missing,,Total, ,N,Percent,N,Percent,N,Percent -X,3,100%,0,0%,3,100% +X,3,100.0%,0,.0%,3,100.0% Table: Percentiles ,,Percentiles,,,,,, ,,5,10,25,50,75,90,95 -X,Empirical,2.00,2.00,2.00,5.00,8.00,8.00,8.00 +X,Weighted Average,2.00,2.00,2.00,5.00,8.00,8.00,8.00 ,Tukey's Hinges,,,3.50,5.00,6.50,, Table: Case Processing Summary ,Cases,,,,, ,Valid,,Missing,,Total, ,N,Percent,N,Percent,N,Percent -X,3,100%,0,0%,3,100% +X,3,100.0%,0,.0%,3,100.0% Table: Percentiles ,,Percentiles,,,,,, ,,5,10,25,50,75,90,95 -X,Empirical with averaging,2.00,2.00,2.00,5.00,8.00,8.00,8.00 +X,Weighted Average,2.00,2.00,2.00,5.00,8.00,8.00,8.00 ,Tukey's Hinges,,,3.50,5.00,6.50,, ]) AT_CLEANUP @@ -449,14 +449,14 @@ Table: Case Processing Summary ,Cases,,,,, ,Valid,,Missing,,Total, ,N,Percent,N,Percent,N,Percent -x,6,85.7143%,1,14.2857%,7,100% +x,6,85.7%,1,14.3%,7,100.0% Table: Case Processing Summary ,,Cases,,,,, ,,Valid,,Missing,,Total, ,y,N,Percent,N,Percent,N,Percent -x,1.00,4,100%,0,0%,4,100% -,2.00,2,66.6667%,1,33.3333%,3,100% +x,1.00,4,100.0%,0,.0%,4,100.0% +,2.00,2,66.7%,1,33.3%,3,100.0% ]) AT_CLEANUP @@ -483,8 +483,8 @@ Table: Case Processing Summary ,Cases,,,,, ,Valid,,Missing,,Total, ,N,Percent,N,Percent,N,Percent -x,1,33.3333%,2,66.6667%,3,100% -y,2,66.6667%,1,33.3333%,3,100% +x,1,33.3%,2,66.7%,3,100.0% +y,2,66.7%,1,33.3%,3,100.0% ]) AT_CLEANUP @@ -537,7 +537,7 @@ Table: Case Processing Summary ,Cases,,,,, ,Valid,,Missing,,Total, ,N,Percent,N,Percent,N,Percent -X,52.00,100%,.00,0%,52.00,100% +X,52.00,100.0%,.00,.0%,52.00,100.0% Table: Descriptives ,,,Statistic,Std. Error @@ -657,7 +657,7 @@ AT_CLEANUP dnl Test that big input doesn't crash (bug 11307). AT_SETUP([EXAMINE -- big input doesn't crash]) -AT_KEYWORDS([categorical categoricals]) +AT_KEYWORDS([categorical categoricals slow]) AT_DATA([examine.sps], [dnl INPUT PROGRAM. LOOP #I=1 TO 50000. @@ -678,7 +678,7 @@ AT_CLEANUP dnl Another test that big input doesn't crash. dnl The actual bug that this checks for has been lost. AT_SETUP([EXAMINE -- big input doesn't crash 2]) -AT_KEYWORDS([categorical categoricals]) +AT_KEYWORDS([categorical categoricals slow]) AT_DATA([make-big-input.pl], [for ($i=0; $i<100000; $i++) { print "AB12\n" }; for ($i=0; $i<100000; $i++) { print "AB04\n" }; @@ -739,20 +739,20 @@ AT_CHECK([pspp -O format=csv examine-id.sps], [0], ,Cases,,,,, ,Valid,,Missing,,Total, ,N,Percent,N,Percent,N,Percent -x,14,100%,0,0%,14,100% +x,14,100.0%,0,.0%,14,100.0% Table: Extreme Values ,,,y,Value x,Highest,1,threehundred,300.00 -,,2,thirty ,30.00 -,,3,twelve ,12.00 -,,4,eleven ,11.00 -,,5,ten ,10.00 -,Lowest,1,one ,1.00 -,,2,two ,2.00 -,,3,three ,3.00 -,,4,four ,4.00 -,,5,five ,5.00 +,,2,thirty,30.00 +,,3,twelve,12.00 +,,4,eleven,11.00 +,,5,ten,10.00 +,Lowest,1,one,1.00 +,,2,two,2.00 +,,3,three,3.00 +,,4,four,4.00 +,,5,five,5.00 ]) AT_CLEANUP @@ -840,8 +840,9 @@ EXAMINE ]) -AT_CHECK([pspp -O format=csv examine-report.sps], [0], [dnl -Table: Reading free-form data from INLINE. +AT_CHECK([pspp -o pspp.csv -o pspp.txt examine-report.sps]) +AT_CHECK([cat pspp.csv], [0], + [[Table: Reading free-form data from INLINE. Variable,Format x,F8.0 g,F8.0 @@ -850,15 +851,18 @@ Table: Case Processing Summary ,,Cases,,,,, ,,Valid,,Missing,,Total, ,g,N,Percent,N,Percent,N,Percent -x,. (missing),4,100%,0,0%,4,100% -,1,9,100%,0,0%,9,100% -,2,9,100%,0,0%,9,100% -,9 (missing),4,100%,0,0%,4,100% -,99 (missing),5,100%,0,0%,5,100% +x,.,4,100.0%,0,.0%,4,100.0% +,1,9,100.0%,0,.0%,9,100.0% +,2,9,100.0%,0,.0%,9,100.0% +,9[a],4,100.0%,0,.0%,4,100.0% +,99[a],5,100.0%,0,.0%,5,100.0% + +Footnotes: +a,User-missing value. Table: Extreme Values ,g,,,Case Number,Value -x,. (missing),Highest,1,31,4004 +x,.,Highest,1,31,4004 ,,,2,30,3003 ,,,3,29,2002 ,,,4,28,1001 @@ -888,7 +892,7 @@ x,. (missing),Highest,1,31,4004 ,,,3,12,30 ,,,4,13,40 ,,,5,14,50 -,9 (missing),Highest,1,22,401 +,9[a],Highest,1,22,401 ,,,2,21,301 ,,,3,20,201 ,,,4,19,101 @@ -898,7 +902,7 @@ x,. (missing),Highest,1,31,4004 ,,,3,21,301 ,,,4,22,401 ,,,5,22,401 -,99 (missing),Highest,1,27,901 +,99[a],Highest,1,27,901 ,,,2,26,801 ,,,3,25,701 ,,,4,24,601 @@ -908,8 +912,10 @@ x,. (missing),Highest,1,31,4004 ,,,3,25,701 ,,,4,26,801 ,,,5,27,901 -]) +Footnotes: +a,User-missing value. +]]) AT_CLEANUP @@ -1037,7 +1043,7 @@ Table: Case Processing Summary ,Cases,,,,, ,Valid,,Missing,,Total, ,N,Percent,N,Percent,N,Percent -X,100,100%,0,0%,100,100% +X,100,100.0%,0,.0%,100,100.0% Table: Descriptives ,,,Statistic,Std. Error @@ -1136,7 +1142,7 @@ Table: Case Processing Summary ,Cases,,,,, ,Valid,,Missing,,Total, ,N,Percent,N,Percent,N,Percent -h,3.00,100%,.00,0%,3.00,100% +h,3.00,100.0%,.00,.0%,3.00,100.0% Table: Extreme Values ,,,Case Number,Value @@ -1150,5 +1156,97 @@ h,Highest,1,3,5.00 AT_CLEANUP +dnl This is an example from doc/tutorial.texi +dnl So if the results of this have to be changed in any way, +dnl make sure to update that file. +AT_SETUP([EXAMINE tutorial example 1]) +cp $top_srcdir/examples/repairs.sav . +AT_DATA([repairs.sps], [dnl +GET FILE='repairs.sav'. +EXAMINE mtbf /STATISTICS=DESCRIPTIVES. +COMPUTE mtbf_ln = LN (mtbf). +EXAMINE mtbf_ln /STATISTICS=DESCRIPTIVES. +]) +AT_CHECK([pspp -o pspp.csv -o pspp.txt repairs.sps]) +AT_CHECK([cat pspp.csv], [0], [dnl +Table: Case Processing Summary +,Cases,,,,, +,Valid,,Missing,,Total, +,N,Percent,N,Percent,N,Percent +Mean time between failures (months) ,15,100.0%,0,.0%,15,100.0% + +Table: Descriptives +,,,Statistic,Std. Error +Mean time between failures (months) ,Mean,,8.32,1.62 +,95% Confidence Interval for Mean,Lower Bound,4.85, +,,Upper Bound,11.79, +,5% Trimmed Mean,,7.69, +,Median,,8.12, +,Variance,,39.21, +,Std. Deviation,,6.26, +,Minimum,,1.63, +,Maximum,,26.47, +,Range,,24.84, +,Interquartile Range,,5.83, +,Skewness,,1.85,.58 +,Kurtosis,,4.49,1.12 +Table: Case Processing Summary +,Cases,,,,, +,Valid,,Missing,,Total, +,N,Percent,N,Percent,N,Percent +mtbf_ln,15,100.0%,0,.0%,15,100.0% + +Table: Descriptives +,,,Statistic,Std. Error +mtbf_ln,Mean,,1.88,.19 +,95% Confidence Interval for Mean,Lower Bound,1.47, +,,Upper Bound,2.29, +,5% Trimmed Mean,,1.88, +,Median,,2.09, +,Variance,,.54, +,Std. Deviation,,.74, +,Minimum,,.49, +,Maximum,,3.28, +,Range,,2.79, +,Interquartile Range,,.92, +,Skewness,,-.16,.58 +,Kurtosis,,-.09,1.12 +]) +AT_CLEANUP + +dnl This is an example from doc/tutorial.texi +dnl So if the results of this have to be changed in any way, +dnl make sure to update that file. +AT_SETUP([EXAMINE tutorial example 2]) +cp $top_srcdir/examples/physiology.sav . +AT_DATA([examine.sps], [dnl +GET FILE='physiology.sav'. +EXAMINE height, weight /STATISTICS=EXTREME(3). +]) +AT_CHECK([pspp -o pspp.csv -o pspp.txt examine.sps]) +AT_CHECK([cat pspp.csv], [0], [dnl +Table: Case Processing Summary +,Cases,,,,, +,Valid,,Missing,,Total, +,N,Percent,N,Percent,N,Percent +Height in millimeters ,40,100.0%,0,.0%,40,100.0% +Weight in kilograms ,40,100.0%,0,.0%,40,100.0% + +Table: Extreme Values +,,,Case Number,Value +Height in millimeters ,Highest,1,14,1903 +,,2,15,1884 +,,3,12,1802 +,Lowest,1,30,179 +,,2,31,1598 +,,3,28,1601 +Weight in kilograms ,Highest,1,13,92.1 +,,2,5,92.1 +,,3,17,91.7 +,Lowest,1,38,-55.6 +,,2,39,54.5 +,,3,33,55.4 +]) +AT_CLEANUP diff --git a/tests/language/stats/factor.at b/tests/language/stats/factor.at index ac29f50cfc..ab0b066c2b 100644 --- a/tests/language/stats/factor.at +++ b/tests/language/stats/factor.at @@ -1487,7 +1487,7 @@ question24,3.666,.926,1365 Table: Correlation Matrix ,,question13,question14,question15,question16,question17,question18,question19,question20,question21,question22,question23,question24 -Correlations,question13,1.000,.661,.600,.566,.577,.409,.286,.304,.476,.333,.564,.454 +Correlation,question13,1.000,.661,.600,.566,.577,.409,.286,.304,.476,.333,.564,.454 ,question14,.661,1.000,.635,.500,.552,.433,.320,.315,.449,.333,.565,.443 ,question15,.600,.635,1.000,.505,.587,.457,.359,.356,.509,.369,.582,.435 ,question16,.566,.500,.505,1.000,.586,.405,.335,.317,.452,.363,.459,.430 @@ -1499,7 +1499,7 @@ Correlations,question13,1.000,.661,.600,.566,.577,.409,.286,.304,.476,.333,.564, ,question22,.333,.333,.369,.363,.450,.536,.484,.383,.507,1.000,.493,.444 ,question23,.564,.565,.582,.459,.613,.569,.444,.410,.598,.493,1.000,.705 ,question24,.454,.443,.435,.430,.521,.474,.374,.357,.500,.444,.705,1.000 -Determinant,.002,,,,,,,,,,,, +Caption: Determinant: 0.00 Table: Factor Matrix ,Factor,, @@ -1767,12 +1767,12 @@ socst,1.000,.900 Table: Total Variance Explained ,Initial Eigenvalues,,,Extraction Sums of Squared Loadings,,,Rotation Sums of Squared Loadings,, -Component,Total,% of Variance,Cumulative %,Total,% of Variance,Cumulative %,Total,% of Variance,Cumulative % -1,3.381,67.616,67.616,3.381,67.616,67.616,2.113,42.267,42.267 -2,.557,11.148,78.764,.557,11.148,78.764,1.825,36.497,78.764 -3,.407,8.136,86.900,,,,,, -4,.356,7.123,94.023,,,,,, -5,.299,5.977,100.000,,,,,, +,Total,% of Variance,Cumulative %,Total,% of Variance,Cumulative %,Total,% of Variance,Cumulative % +1,3.381,67.6%,67.6%,3.381,67.6%,67.6%,2.113,42.3%,42.3% +2,.557,11.1%,78.8%,.557,11.1%,78.8%,1.825,36.5%,78.8% +3,.407,8.1%,86.9%,,,,,, +4,.356,7.1%,94.0%,,,,,, +5,.299,6.0%,100.0%,,,,,, Table: Component Matrix ,Component, @@ -1848,17 +1848,17 @@ TRAIT5,7.29,2.66,7 Table: Correlation Matrix ,,TRAIT1,TRAIT2,TRAIT3,TRAIT4,TRAIT5 -Correlations,TRAIT1,1.00,.30,.88,1.00,.54 -,TRAIT2,.30,1.00,-.02,.33,.84 -,TRAIT3,.88,-.02,1.00,.87,.13 -,TRAIT4,1.00,.33,.87,1.00,.54 -,TRAIT5,.54,.84,.13,.54,1.00 +Correlation,TRAIT1,1.000,.296,.881,.995,.545 +,TRAIT2,.296,1.000,-.022,.326,.837 +,TRAIT3,.881,-.022,1.000,.867,.130 +,TRAIT4,.995,.326,.867,1.000,.544 +,TRAIT5,.545,.837,.130,.544,1.000 Sig. (1-tailed),TRAIT1,,.260,.004,.000,.103 ,TRAIT2,.260,,.482,.238,.009 ,TRAIT3,.004,.482,,.006,.390 ,TRAIT4,.000,.238,.006,,.103 ,TRAIT5,.103,.009,.390,.103, -Determinant,.00,,,,, +Caption: Determinant: 0.00 Table: Communalities ,Initial,Extraction @@ -1870,12 +1870,12 @@ TRAIT5,1.00,.99 Table: Total Variance Explained ,Initial Eigenvalues,,,Extraction Sums of Squared Loadings,, -Component,Total,% of Variance,Cumulative %,Total,% of Variance,Cumulative % -1,3.26,65.26,65.26,3.26,65.26,65.26 -2,1.54,30.77,96.03,1.54,30.77,96.03 -3,.17,3.36,99.39,.17,3.36,99.39 -4,.03,.61,100.00,.03,.61,100.00 -5,.00,.00,100.00,,, +,Total,% of Variance,Cumulative %,Total,% of Variance,Cumulative % +1,3.26,65.3%,65.3%,3.26,65.3%,65.3% +2,1.54,30.8%,96.0%,1.54,30.8%,96.0% +3,.17,3.4%,99.4%,.17,3.4%,99.4% +4,.03,.6%,100.0%,.03,.6%,100.0% +5,.00,.0%,100.0%,,, Table: Component Matrix ,Component,,, @@ -1927,10 +1927,10 @@ z,.514,.523 Table: Total Variance Explained ,Initial Eigenvalues,,,Extraction Sums of Squared Loadings,, -Factor,Total,% of Variance,Cumulative %,Total,% of Variance,Cumulative % -1,2.404,80.124,80.124,2.155,71.847,71.847 -2,.425,14.166,94.290,,, -3,.171,5.710,100.000,,, +,Total,% of Variance,Cumulative %,Total,% of Variance,Cumulative % +1,2.404,80.1%,80.1%,2.155,71.8%,71.8% +2,.425,14.2%,94.3%,,, +3,.171,5.7%,100.0%,,, Table: Factor Matrix ,Factor @@ -1984,26 +1984,26 @@ ZN,.208,.412 ZS,.130,.158 Table: Total Variance Explained -,Initial Eigenvalues,,,Extraction Sums of Squared Loadings,,,Rotation Sums of Squared Loadings -Factor,Total,% of Variance,Cumulative %,Total,% of Variance,Cumulative %,Total -1,2.968,16.491,16.491,2.411,13.393,13.393,2.355 -2,2.026,11.253,27.744,1.271,7.059,20.452,1.209 -3,1.622,9.011,36.756,.948,5.264,25.716,1.231 -4,1.086,6.032,42.788,.283,1.574,27.290,.770 -5,.996,5.533,48.321,,,, -6,.923,5.130,53.451,,,, -7,.873,4.852,58.303,,,, -8,.856,4.756,63.060,,,, -9,.836,4.644,67.703,,,, -10,.816,4.534,72.237,,,, -11,.785,4.359,76.596,,,, -12,.740,4.110,80.706,,,, -13,.713,3.964,84.670,,,, -14,.653,3.626,88.296,,,, -15,.633,3.519,91.815,,,, -16,.604,3.356,95.171,,,, -17,.484,2.687,97.858,,,, -18,.386,2.142,100.000,,,, +,Initial Eigenvalues,,,Extraction Sums of Squared Loadings,,,Rotation Sums of Squared Loadings,, +,Total,% of Variance,Cumulative %,Total,% of Variance,Cumulative %,Total,% of Variance,Cumulative % +1,2.968,16.5%,16.5%,2.411,13.4%,13.4%,. ,. ,. @&t@ +2,2.026,11.3%,27.7%,1.271,7.1%,20.5%,. ,. ,-Infinity +3,1.622,9.0%,36.8%,.948,5.3%,25.7%,. ,. ,-Infinity +4,1.086,6.0%,42.8%,.283,1.6%,27.3%,. ,. ,-Infinity +5,.996,5.5%,48.3%,,,,,, +6,.923,5.1%,53.5%,,,,,, +7,.873,4.9%,58.3%,,,,,, +8,.856,4.8%,63.1%,,,,,, +9,.836,4.6%,67.7%,,,,,, +10,.816,4.5%,72.2%,,,,,, +11,.785,4.4%,76.6%,,,,,, +12,.740,4.1%,80.7%,,,,,, +13,.713,4.0%,84.7%,,,,,, +14,.653,3.6%,88.3%,,,,,, +15,.633,3.5%,91.8%,,,,,, +16,.604,3.4%,95.2%,,,,,, +17,.484,2.7%,97.9%,,,,,, +18,.386,2.1%,100.0%,,,,,, Table: Factor Matrix ,Factor,,, @@ -2140,15 +2140,15 @@ var08,2.250 Table: Total Variance Explained ,Initial Eigenvalues,, -Component,Total,% of Variance,Cumulative % -1,556.895,81.881,81.881 -2,57.963,8.522,90.403 -3,23.576,3.466,93.869 -4,16.446,2.418,96.288 -5,14.603,2.147,98.435 -6,6.831,1.004,99.439 -7,2.375,.349,99.788 -8,1.440,.212,100.000 +,Total,% of Variance,Cumulative % +1,556.895,81.9%,81.9% +2,57.963,8.5%,90.4% +3,23.576,3.5%,93.9% +4,16.446,2.4%,96.3% +5,14.603,2.1%,98.4% +6,6.831,1.0%,99.4% +7,2.375,.3%,99.8% +8,1.440,.2%,100.0% Table: Component Matrix ,Component,,,,,, @@ -2240,14 +2240,14 @@ bnt_actws_56,1.000,.316 Table: Total Variance Explained ,Initial Eigenvalues,,,Extraction Sums of Squared Loadings,, -Component,Total,% of Variance,Cumulative %,Total,% of Variance,Cumulative % -1,3.914,55.908,55.908,3.914,55.908,55.908 -2,1.320,18.852,74.760,,, -3,.716,10.223,84.983,,, -4,.422,6.030,91.012,,, -5,.278,3.977,94.989,,, -6,.216,3.088,98.077,,, -7,.135,1.923,100.000,,, +,Total,% of Variance,Cumulative %,Total,% of Variance,Cumulative % +1,3.914,55.9%,55.9%,3.914,55.9%,55.9% +2,1.320,18.9%,74.8%,,, +3,.716,10.2%,85.0%,,, +4,.422,6.0%,91.0%,,, +5,.278,4.0%,95.0%,,, +6,.216,3.1%,98.1%,,, +7,.135,1.9%,100.0%,,, Table: Component Matrix ,Component diff --git a/tests/language/stats/flip.at b/tests/language/stats/flip.at index 06fb969fa5..f6d665e1fe 100644 --- a/tests/language/stats/flip.at +++ b/tests/language/stats/flip.at @@ -47,19 +47,19 @@ flip.sps:12: warning: FLIP: FLIP ignores TEMPORARY. Temporary transformations w Table: Data List CASE_LBL,v,w,x,y,z -a ,1.00,6.00,11.00,16.00,21.00 -b ,2.00,7.00,12.00,17.00,22.00 -c ,3.00,8.00,13.00,18.00,23.00 -d ,4.00,9.00,14.00,19.00,24.00 -e ,1.00,6.00,11.00,16.00,21.00 +a,1.00,6.00,11.00,16.00,21.00 +b,2.00,7.00,12.00,17.00,22.00 +c,3.00,8.00,13.00,18.00,23.00 +d,4.00,9.00,14.00,19.00,24.00 +e,1.00,6.00,11.00,16.00,21.00 Table: Data List CASE_LBL,a,b,c,d,e -v ,1.00,2.00,3.00,4.00,1.00 -w ,6.00,7.00,8.00,9.00,6.00 -x ,11.00,12.00,13.00,14.00,11.00 -y ,16.00,17.00,18.00,19.00,16.00 -z ,21.00,22.00,23.00,24.00,21.00 +v,1.00,2.00,3.00,4.00,1.00 +w,6.00,7.00,8.00,9.00,6.00 +x,11.00,12.00,13.00,14.00,11.00 +y,16.00,17.00,18.00,19.00,16.00 +z,21.00,22.00,23.00,24.00,21.00 ]) AT_CLEANUP @@ -85,16 +85,16 @@ v1,v2,v3,v4,v5,v6,v7,v8,v9,v10 Table: Data List CASE_LBL,VAR000,VAR001 -v1 ,1.00,4.00 -v2 ,2.00,5.00 -v3 ,3.00,6.00 -v4 ,4.00,7.00 -v5 ,5.00,8.00 -v6 ,6.00,9.00 -v7 ,7.00,10.00 -v8 ,8.00,11.00 -v9 ,9.00,12.00 -v10 ,10.00,13.00 +v1,1.00,4.00 +v2,2.00,5.00 +v3,3.00,6.00 +v4,4.00,7.00 +v5,5.00,8.00 +v6,6.00,9.00 +v7,7.00,10.00 +v8,8.00,11.00 +v9,9.00,12.00 +v10,10.00,13.00 ]) AT_CLEANUP @@ -134,10 +134,10 @@ list. AT_CHECK([pspp -O format=csv flip.sps], [0], [dnl Table: Data List CASE_LBL,v,BY1 -a ,1.00,1.00 -b ,2.00,2.00 -c ,3.00,3.00 -d ,4.00,4.00 +a,1.00,1.00 +b,2.00,2.00 +c,3.00,3.00 +d,4.00,4.00 ]) AT_CLEANUP diff --git a/tests/language/stats/frequencies.at b/tests/language/stats/frequencies.at index cf7913b40d..ca0467264e 100644 --- a/tests/language/stats/frequencies.at +++ b/tests/language/stats/frequencies.at @@ -38,12 +38,12 @@ FREQUENCIES /VAR = name/ORDER=ANALYSIS. ]) AT_CHECK([pspp -O format=csv frequencies.sps], [0], [dnl Table: name -Value Label,Value,Frequency,Percent,Valid Percent,Cum Percent -,bar ,2,20.00,20.00,20.00 -,baz ,4,40.00,40.00,60.00 -,foo ,2,20.00,20.00,80.00 -,quux ,2,20.00,20.00,100.00 -Total,,10,100.0,100.0, +,,Frequency,Percent,Valid Percent,Cumulative Percent +Valid,bar,2,20.0%,20.0%,20.0% +,baz,4,40.0%,40.0%,60.0% +,foo,2,20.0%,20.0%,80.0% +,quux,2,20.0%,20.0%,100.0% +Total,,10,100.0%,, ]) AT_CLEANUP @@ -62,38 +62,38 @@ end data. frequencies v1 v2/statistics=none/ORDER=VARIABLE. frequencies v1 v2/statistics=none. ]) -AT_CHECK([pspp -O format=csv frequencies.sps], [0], - [Table: v1 -Value Label,Value,Frequency,Percent,Valid Percent,Cum Percent -,.00,1,25.00,25.00,25.00 -,2.00,1,25.00,25.00,50.00 -,3.00,1,25.00,25.00,75.00 -,4.00,1,25.00,25.00,100.00 -Total,,4,100.0,100.0, +AT_CHECK([pspp -O format=csv frequencies.sps], [0], [dnl +Table: v1 +,,Frequency,Percent,Valid Percent,Cumulative Percent +Valid,.00,1,25.0%,25.0%,25.0% +,2.00,1,25.0%,25.0%,50.0% +,3.00,1,25.0%,25.0%,75.0% +,4.00,1,25.0%,25.0%,100.0% +Total,,4,100.0%,, Table: v2 -Value Label,Value,Frequency,Percent,Valid Percent,Cum Percent -,1.00,1,25.00,25.00,25.00 -,3.00,1,25.00,25.00,50.00 -,4.00,1,25.00,25.00,75.00 -,5.00,1,25.00,25.00,100.00 -Total,,4,100.0,100.0, +,,Frequency,Percent,Valid Percent,Cumulative Percent +Valid,1.00,1,25.0%,25.0%,25.0% +,3.00,1,25.0%,25.0%,50.0% +,4.00,1,25.0%,25.0%,75.0% +,5.00,1,25.0%,25.0%,100.0% +Total,,4,100.0%,, Table: v1 -Value Label,Value,Frequency,Percent,Valid Percent,Cum Percent -,.00,1,25.00,25.00,25.00 -,2.00,1,25.00,25.00,50.00 -,3.00,1,25.00,25.00,75.00 -,4.00,1,25.00,25.00,100.00 -Total,,4,100.0,100.0, +,,Frequency,Percent,Valid Percent,Cumulative Percent +Valid,.00,1,25.0%,25.0%,25.0% +,2.00,1,25.0%,25.0%,50.0% +,3.00,1,25.0%,25.0%,75.0% +,4.00,1,25.0%,25.0%,100.0% +Total,,4,100.0%,, Table: v2 -Value Label,Value,Frequency,Percent,Valid Percent,Cum Percent -,1.00,1,25.00,25.00,25.00 -,3.00,1,25.00,25.00,50.00 -,4.00,1,25.00,25.00,75.00 -,5.00,1,25.00,25.00,100.00 -Total,,4,100.0,100.0, +,,Frequency,Percent,Valid Percent,Cumulative Percent +Valid,1.00,1,25.0%,25.0%,25.0% +,3.00,1,25.0%,25.0%,50.0% +,4.00,1,25.0%,25.0%,75.0% +,5.00,1,25.0%,25.0%,100.0% +Total,,4,100.0%,, ]) AT_CLEANUP @@ -112,11 +112,11 @@ frequencies v1 v2/statistics=none/FORMAT=LIMIT(3). ]) AT_CHECK([pspp -O format=csv frequencies.sps], [0], [dnl Table: v2 -Value Label,Value,Frequency,Percent,Valid Percent,Cum Percent -,1.00,1,25.00,25.00,25.00 -,3.00,1,25.00,25.00,50.00 -,5.00,2,50.00,50.00,100.00 -Total,,4,100.0,100.0, +,,Frequency,Percent,Valid Percent,Cumulative Percent +Valid,1.00,1,25.0%,25.0%,25.0% +,3.00,1,25.0%,25.0%,50.0% +,5.00,2,50.0%,50.0%,100.0% +Total,,4,100.0%,, ]) AT_CLEANUP @@ -145,12 +145,12 @@ v1,v2 3.00,4.00 Table: v1 -Value Label,Value,Frequency,Percent,Valid Percent,Cum Percent -,.00,1,25.00,25.00,25.00 -,2.00,1,25.00,25.00,50.00 -,3.00,1,25.00,25.00,75.00 -,4.00,1,25.00,25.00,100.00 -Total,,4,100.0,100.0, +,,Frequency,Percent,Valid Percent,Cumulative Percent +Valid,.00,1,25.0%,25.0%,25.0% +,2.00,1,25.0%,25.0%,50.0% +,3.00,1,25.0%,25.0%,75.0% +,4.00,1,25.0%,25.0%,100.0% +Total,,4,100.0%,, ]) AT_CHECK([test -s pspp.html]) AT_CLEANUP @@ -185,7 +185,7 @@ AT_CHECK([pspp frequencies.sps], [0], [dnl Reading free-form data from INLINE. +--------+------+ |Variable|Format| -#========#======# ++--------+------+ |x |F8.0 | |w |F8.0 | +--------+------+ @@ -260,32 +260,35 @@ FREQUENCIES /X . FINISH ]) -AT_CHECK([pspp -O format=csv frequencies.sps], [0], - [Table: Reading free-form data from INLINE. +AT_CHECK([pspp -o pspp.csv -o pspp.txt frequencies.sps]) +AT_CHECK([cat pspp.csv], [0], [dnl +Table: Reading free-form data from INLINE. Variable,Format SEX,A1 X,F8.0 -Table: X -Value Label,Value,Frequency,Percent,Valid Percent,Cum Percent -,12.00,1,25.00,25.00,25.00 -,13.00,1,25.00,25.00,50.00 -,21.00,1,25.00,25.00,75.00 -,31.00,1,25.00,25.00,100.00 -Total,,4,100.0,100.0, - -Table: X +Table: Statistics +,,X N,Valid,4 ,Missing,0 Mean,,19.25 Std Dev,,8.81 Minimum,,12.00 Maximum,,31.00 + +Table: X +,,Frequency,Percent,Valid Percent,Cumulative Percent +Valid,12.00,1,25.0%,25.0%,25.0% +,13.00,1,25.0%,25.0%,50.0% +,21.00,1,25.0%,25.0%,75.0% +,31.00,1,25.0%,25.0%,100.0% +Total,,4,100.0%,, ]) AT_CLEANUP -m4_define([FREQUENCIES_NTILES_OUTPUT], - [Table: x +m4_define([FREQUENCIES_NTILES_OUTPUT], [dnl +Table: Statistics +,,x N,Valid,5 ,Missing,0 Mean,,3.00 @@ -295,7 +298,7 @@ Maximum,,5.00 Percentiles,0,1.00 ,25,2.00 ,33,2.33 -,50 (Median),3.00 +,50,3.00 ,67,3.67 ,75,4.00 ,100,5.00 @@ -357,17 +360,9 @@ FREQUENCIES /ALGORITHM=COMPATIBLE /PERCENTILES = 0 25 50 75 100. ]) -AT_CHECK([pspp -O format=csv frequencies.sps], [0], - [Table: X -Value Label,Value,Frequency,Percent,Valid Percent,Cum Percent -,1.00,1,20.00,20.00,20.00 -,2.00,1,20.00,20.00,40.00 -,3.00,1,20.00,20.00,60.00 -,4.00,1,20.00,20.00,80.00 -,5.00,1,20.00,20.00,100.00 -Total,,5,100.0,100.0, - -Table: X +AT_CHECK([pspp -O format=csv frequencies.sps], [0], [dnl +Table: Statistics +,,X N,Valid,5 ,Missing,0 Mean,,3.00 @@ -376,9 +371,18 @@ Minimum,,1.00 Maximum,,5.00 Percentiles,0,1.00 ,25,1.50 -,50 (Median),3.00 +,50,3.00 ,75,4.50 ,100,5.00 + +Table: X +,,Frequency,Percent,Valid Percent,Cumulative Percent +Valid,1.00,1,20.0%,20.0%,20.0% +,2.00,1,20.0%,20.0%,40.0% +,3.00,1,20.0%,20.0%,60.0% +,4.00,1,20.0%,20.0%,80.0% +,5.00,1,20.0%,20.0%,100.0% +Total,,5,100.0%,, ]) AT_CLEANUP @@ -397,17 +401,9 @@ FREQUENCIES VAR=x /PERCENTILES = 0 25 50 75 100. ]) -AT_CHECK([pspp -O format=csv frequencies.sps], [0], - [Table: X -Value Label,Value,Frequency,Percent,Valid Percent,Cum Percent -,1.00,1,20.00,20.00,20.00 -,2.00,1,20.00,20.00,40.00 -,3.00,1,20.00,20.00,60.00 -,4.00,1,20.00,20.00,80.00 -,5.00,1,20.00,20.00,100.00 -Total,,5,100.0,100.0, - -Table: X +AT_CHECK([pspp -O format=csv frequencies.sps], [0], [dnl +Table: Statistics +,,X N,Valid,5 ,Missing,0 Mean,,3.00 @@ -416,9 +412,18 @@ Minimum,,1.00 Maximum,,5.00 Percentiles,0,1.00 ,25,2.00 -,50 (Median),3.00 +,50,3.00 ,75,4.00 ,100,5.00 + +Table: X +,,Frequency,Percent,Valid Percent,Cumulative Percent +Valid,1.00,1,20.0%,20.0%,20.0% +,2.00,1,20.0%,20.0%,40.0% +,3.00,1,20.0%,20.0%,60.0% +,4.00,1,20.0%,20.0%,80.0% +,5.00,1,20.0%,20.0%,100.0% +Total,,5,100.0%,, ]) AT_CLEANUP @@ -441,17 +446,9 @@ FREQUENCIES VAR=x /PERCENTILES = 0 25 50 75 100. ]) -AT_CHECK([pspp -O format=csv frequencies.sps], [0], - [Table: X -Value Label,Value,Frequency,Percent,Valid Percent,Cum Percent -,1.00,2.00,20.00,20.00,20.00 -,2.00,2.00,20.00,20.00,40.00 -,3.00,2.00,20.00,20.00,60.00 -,4.00,2.00,20.00,20.00,80.00 -,5.00,2.00,20.00,20.00,100.00 -Total,,10.00,100.0,100.0, - -Table: X +AT_CHECK([pspp -O format=csv frequencies.sps], [0], [dnl +Table: Statistics +,,X N,Valid,10.00 ,Missing,.00 Mean,,3.00 @@ -460,9 +457,18 @@ Minimum,,1.00 Maximum,,5.00 Percentiles,0,1.00 ,25,2.00 -,50 (Median),3.00 +,50,3.00 ,75,4.00 ,100,5.00 + +Table: X +,,Frequency,Percent,Valid Percent,Cumulative Percent +Valid,1.00,2.00,20.0%,20.0%,20.0% +,2.00,2.00,20.0%,20.0%,40.0% +,3.00,2.00,20.0%,20.0%,60.0% +,4.00,2.00,20.0%,20.0%,80.0% +,5.00,2.00,20.0%,20.0%,100.0% +Total,,10.00,100.0%,, ]) AT_CLEANUP @@ -483,16 +489,9 @@ FREQUENCIES VAR=x /PERCENTILES = 0 25 50 75 100. ]) -AT_CHECK([pspp -O format=csv frequencies.sps], [0], - [Table: X -Value Label,Value,Frequency,Percent,Valid Percent,Cum Percent -,1.00,1.00,16.67,16.67,16.67 -,3.00,2.00,33.33,33.33,50.00 -,4.00,1.00,16.67,16.67,66.67 -,5.00,2.00,33.33,33.33,100.00 -Total,,6.00,100.0,100.0, - -Table: X +AT_CHECK([pspp -O format=csv frequencies.sps], [0], [dnl +Table: Statistics +,,X N,Valid,6.00 ,Missing,.00 Mean,,3.50 @@ -501,9 +500,17 @@ Minimum,,1.00 Maximum,,5.00 Percentiles,0,1.00 ,25,3.00 -,50 (Median),3.50 +,50,3.50 ,75,4.75 ,100,5.00 + +Table: X +,,Frequency,Percent,Valid Percent,Cumulative Percent +Valid,1.00,1.00,16.7%,16.7%,16.7% +,3.00,2.00,33.3%,33.3%,50.0% +,4.00,1.00,16.7%,16.7%,66.7% +,5.00,2.00,33.3%,33.3%,100.0% +Total,,6.00,100.0%,, ]) AT_CLEANUP @@ -525,15 +532,8 @@ FREQUENCIES /PERCENTILES = 0 25 50 75 100. ]) AT_CHECK([pspp -O format=csv frequencies.sps], [0], [dnl -Table: X -Value Label,Value,Frequency,Percent,Valid Percent,Cum Percent -,1.00,7.00,17.50,17.50,17.50 -,2.00,16.00,40.00,40.00,57.50 -,3.00,12.00,30.00,30.00,87.50 -,4.00,5.00,12.50,12.50,100.00 -Total,,40.00,100.0,100.0, - -Table: X +Table: Statistics +,,X N,Valid,40.00 ,Missing,.00 Mean,,2.38 @@ -542,9 +542,17 @@ Minimum,,1.00 Maximum,,4.00 Percentiles,0,1.00 ,25,2.00 -,50 (Median),2.00 +,50,2.00 ,75,3.00 ,100,4.00 + +Table: X +,,Frequency,Percent,Valid Percent,Cumulative Percent +Valid,1.00,7.00,17.5%,17.5%,17.5% +,2.00,16.00,40.0%,40.0%,57.5% +,3.00,12.00,30.0%,30.0%,87.5% +,4.00,5.00,12.5%,12.5%,100.0% +Total,,40.00,100.0%,, ]) AT_CLEANUP @@ -568,17 +576,9 @@ FREQUENCIES /PERCENTILES = 0 25 50 75 100. ]) -AT_CHECK([pspp -O format=csv frequencies.sps], [0], - [Table: X -Value Label,Value,Frequency,Percent,Valid Percent,Cum Percent -,1.00,1.00,10.00,16.67,16.67 -,3.00,2.00,20.00,33.33,50.00 -,4.00,1.00,10.00,16.67,66.67 -,5.00,2.00,20.00,33.33,100.00 -,99.00,4.00,40.00,Missing, -Total,,10.00,100.0,100.0, - -Table: X +AT_CHECK([pspp -O format=csv frequencies.sps], [0], [dnl +Table: Statistics +,,X N,Valid,6.00 ,Missing,4.00 Mean,,3.50 @@ -587,9 +587,18 @@ Minimum,,1.00 Maximum,,5.00 Percentiles,0,1.00 ,25,3.00 -,50 (Median),3.50 +,50,3.50 ,75,4.75 ,100,5.00 + +Table: X +,,Frequency,Percent,Valid Percent,Cumulative Percent +Valid,1.00,1.00,10.0%,16.7%,16.7% +,3.00,2.00,20.0%,33.3%,50.0% +,4.00,1.00,10.0%,16.7%,66.7% +,5.00,2.00,20.0%,33.3%,100.0% +Missing,99.00,4.00,40.0%,, +Total,,10.00,100.0%,, ]) AT_CLEANUP @@ -642,18 +651,19 @@ FREQUENCIES . ]) -AT_CHECK([pspp median.sps -O format=csv], [0], [dnl -Table: x -Value Label,Value,Frequency,Percent,Valid Percent,Cum Percent -,1.00,1,33.33,33.33,33.33 -,2.00,1,33.33,33.33,66.67 -,3000000.00,1,33.33,33.33,100.00 -Total,,3,100.0,100.0, - -Table: x +AT_CHECK([pspp median.sps -O format=csv], [0], [dnl +Table: Statistics +,,x N,Valid,3 ,Missing,0 -Percentiles,50 (Median),2.00 +Median,,2.00 + +Table: x +,,Frequency,Percent,Valid Percent,Cumulative Percent +Valid,1.00,1,33.3%,33.3%,33.3% +,2.00,1,33.3%,33.3%,66.7% +,3000000,1,33.3%,33.3%,100.0% +Total,,3,100.0%,, ]) AT_CLEANUP @@ -672,19 +682,20 @@ FREQUENCIES /STATISTICS = VARIANCE. ]) -AT_CHECK([pspp variance.sps -O format=csv], [0], [dnl -Table: height -Value Label,Value,Frequency,Percent,Valid Percent,Cum Percent -,109.00,1,25.00,25.00,25.00 -,134.00,1,25.00,25.00,50.00 -,167.00,1,25.00,25.00,75.00 -,188.00,1,25.00,25.00,100.00 -Total,,4,100.0,100.0, - -Table: height +AT_CHECK([pspp variance.sps -O format=csv], [0], [dnl +Table: Statistics +,,height N,Valid,4 ,Missing,0 Variance,,1223.00 + +Table: height +,,Frequency,Percent,Valid Percent,Cumulative Percent +Valid,109.00,1,25.0%,25.0%,25.0% +,134.00,1,25.0%,25.0%,50.0% +,167.00,1,25.0%,25.0%,75.0% +,188.00,1,25.0%,25.0%,100.0% +Total,,4,100.0%,, ]) AT_CLEANUP @@ -708,36 +719,39 @@ FREQUENCIES . ]) -AT_CHECK([pspp median.sps -O format=csv], [0], [dnl -Table: x -Value Label,Value,Frequency,Percent,Valid Percent,Cum Percent -,10.00,1,33.33,33.33,33.33 -,20.00,1,33.33,33.33,66.67 -,3000000.00,1,33.33,33.33,100.00 -Total,,3,100.0,100.0, - -Table: x +AT_CHECK([pspp median.sps -o pspp.csv -o pspp.txt]) +AT_CHECK([cat pspp.csv], [0], [dnl +Table: Statistics +,,x N,Valid,3 ,Missing,0 -Mean,,1000010.00 -Std Dev,,1732042.15 +Mean,,1000010 +Std Dev,,1732042 Minimum,,10.00 -Maximum,,3000000.00 - -Table: x -Value Label,Value,Frequency,Percent,Valid Percent,Cum Percent -,10.00,1,33.33,33.33,33.33 -,20.00,1,33.33,33.33,66.67 -,3000000.00,1,33.33,33.33,100.00 -Total,,3,100.0,100.0, +Maximum,,3000000 Table: x +,,Frequency,Percent,Valid Percent,Cumulative Percent +Valid,10.00,1,33.3%,33.3%,33.3% +,20.00,1,33.3%,33.3%,66.7% +,3000000,1,33.3%,33.3%,100.0% +Total,,3,100.0%,, + +Table: Statistics +,,x N,Valid,3 ,Missing,0 -Mean,,1000010.00 -Std Dev,,1732042.15 +Mean,,1000010 +Std Dev,,1732042 Minimum,,10.00 -Maximum,,3000000.00 +Maximum,,3000000 + +Table: x +,,Frequency,Percent,Valid Percent,Cumulative Percent +Valid,10.00,1,33.3%,33.3%,33.3% +,20.00,1,33.3%,33.3%,66.7% +,3000000,1,33.3%,33.3%,100.0% +Total,,3,100.0%,, ]) AT_CLEANUP @@ -759,28 +773,29 @@ FREQUENCIES ]) AT_CHECK([pspp empty.sps -O format=csv], [0], [dnl -Table: x -Value Label,Value,Frequency,Percent,Valid Percent,Cum Percent -,. ,3,100.00,Missing, -Total,,3,100.0,100.0, - -Table: x +Table: Statistics +,,x N,Valid,0 ,Missing,3 -Mean,,. -S.E. Mean,,. -Mode,,. -Std Dev,,. -Variance,,. -Kurtosis,,. -S.E. Kurt,,. -Skewness,,. -S.E. Skew,,. -Range,,. -Minimum,,. -Maximum,,. -Sum,,. -Percentiles,,. +Mean,,. @&t@ +S.E. Mean,,. @&t@ +Median,,. @&t@ +Mode,,. @&t@ +Std Dev,,. @&t@ +Variance,,. @&t@ +Kurtosis,,. @&t@ +S.E. Kurt,,. @&t@ +Skewness,,. @&t@ +S.E. Skew,,. @&t@ +Range,,. @&t@ +Minimum,,. @&t@ +Maximum,,. @&t@ +Sum,,. @&t@ + +Table: x +,,Frequency,Percent,Valid Percent,Cumulative Percent +Missing,. ,3,100.0%,, +Total,,3,.0%,, ]) AT_CLEANUP diff --git a/tests/language/stats/glm.at b/tests/language/stats/glm.at index 564c8dee40..ac18c340da 100644 --- a/tests/language/stats/glm.at +++ b/tests/language/stats/glm.at @@ -75,7 +75,7 @@ glm y by b a c AT_CHECK([pspp -O format=csv latin.sps | sed 's/329.62[[678]]/329.62/'], [0], [dnl Table: Tests of Between-Subjects Effects -Source,Type III Sum of Squares,df,Mean Square,F,Sig. +,Type III Sum Of Squares,df,Mean Square,F,Sig. Corrected Model,263.064,15,17.538,5.269,.000 Intercept,815.103,1,815.103,244.910,.000 Factor A,78.869,5,15.774,4.739,.005 @@ -127,12 +127,12 @@ glm points by Factor0 Factor1 AT_CHECK([pspp -O format=csv 2by2.sps ], [0], [dnl Table: Tests of Between-Subjects Effects -Source,Type III Sum of Squares,df,Mean Square,F,Sig. +,Type III Sum Of Squares,df,Mean Square,F,Sig. Corrected Model,8667.053,3,2889.018,5.043,.012 Intercept,2256018.640,1,2256018.640,3937.693,.000 Factor0,313.394,1,313.394,.547,.470 Factor1,5157.508,1,5157.508,9.002,.008 -Factor0 * Factor1,3196.150,1,3196.150,5.579,.031 +Factor0 × Factor1,3196.150,1,3196.150,5.579,.031 Error,9166.865,16,572.929,, Total,2273852.559,20,,, Corrected Total,17833.918,19,,, @@ -225,23 +225,23 @@ glm dv by Agrp Bgrp AT_CHECK([pspp -O format=csv type1.sps], [0], [dnl Table: Tests of Between-Subjects Effects -Source,Type I Sum of Squares,df,Mean Square,F,Sig. +,Type I Sum Of Squares,df,Mean Square,F,Sig. Corrected Model,216.017,7,30.860,5.046,.001 Intercept,,,,, Agrp,9.579,1,9.579,1.566,.220 Bgrp,186.225,3,62.075,10.151,.000 -Agrp * Bgrp,20.212,3,6.737,1.102,.364 +Agrp × Bgrp,20.212,3,6.737,1.102,.364 Error,183.457,30,6.115,, Total,3810.000,38,,, Corrected Total,399.474,37,,, Table: Tests of Between-Subjects Effects -Source,Type I Sum of Squares,df,Mean Square,F,Sig. +,Type I Sum Of Squares,df,Mean Square,F,Sig. Corrected Model,216.017,7,30.860,5.046,.001 Intercept,,,,, Bgrp,193.251,3,64.417,10.534,.000 Agrp,2.553,1,2.553,.418,.523 -Bgrp * Agrp,20.212,3,6.737,1.102,.364 +Bgrp × Agrp,20.212,3,6.737,1.102,.364 Error,183.457,30,6.115,, Total,3810.000,38,,, Corrected Total,399.474,37,,, @@ -260,12 +260,12 @@ glm dv by Agrp Bgrp AT_CHECK([pspp -O format=csv type2.sps], [0], [dnl Table: Tests of Between-Subjects Effects -Source,Type II Sum of Squares,df,Mean Square,F,Sig. +,Type II Sum Of Squares,df,Mean Square,F,Sig. Corrected Model,216.017,7,30.860,5.046,.001 Intercept,,,,, Agrp,2.553,1,2.553,.418,.523 Bgrp,186.225,3,62.075,10.151,.000 -Agrp * Bgrp,20.212,3,6.737,1.102,.364 +Agrp × Bgrp,20.212,3,6.737,1.102,.364 Error,183.457,30,6.115,, Total,3810.000,38,,, Corrected Total,399.474,37,,, @@ -328,14 +328,14 @@ GLM depvar by A AT_CHECK([pspp -O format=csv intercept-exclude.sps], [0], [dnl Table: Tests of Between-Subjects Effects -Source,Type III Sum of Squares,df,Mean Square,F,Sig. +,Type III Sum Of Squares,df,Mean Square,F,Sig. Model,1636.826,2,818.413,43.556,.000 A,1636.826,2,818.413,43.556,.000 Error,338.216,18,18.790,, Total,1975.042,20,,, Table: Tests of Between-Subjects Effects -Source,Type III Sum of Squares,df,Mean Square,F,Sig. +,Type III Sum Of Squares,df,Mean Square,F,Sig. Corrected Model,98.568,1,98.568,5.246,.034 Intercept,1538.258,1,1538.258,81.867,.000 A,98.568,1,98.568,5.246,.034 @@ -405,7 +405,7 @@ glm y by b a c AT_CHECK([pspp -O format=csv glm-miss.sps], [0], [dnl Table: Tests of Between-Subjects Effects -Source,Type III Sum of Squares,df,Mean Square,F,Sig. +,Type III Sum Of Squares,df,Mean Square,F,Sig. Corrected Model,251.621,14,17.973,4.969,.002 Intercept,628.376,1,628.376,173.737,.000 a,72.929,4,18.232,5.041,.009 @@ -432,7 +432,7 @@ glm y by b a c AT_CHECK([pspp -O format=csv glm-miss2.sps], [0], [dnl Table: Tests of Between-Subjects Effects -Source,Type III Sum of Squares,df,Mean Square,F,Sig. +,Type III Sum Of Squares,df,Mean Square,F,Sig. Corrected Model,251.621,14,17.973,4.969,.002 Intercept,628.376,1,628.376,173.737,.000 a,72.929,4,18.232,5.041,.009 @@ -462,7 +462,7 @@ glm y by b a c AT_CHECK([pspp -O format=csv glm-miss3.sps], [0], [dnl Table: Tests of Between-Subjects Effects -Source,Type III Sum of Squares,df,Mean Square,F,Sig. +,Type III Sum Of Squares,df,Mean Square,F,Sig. Corrected Model,251.621,14,17.973,4.969,.002 Intercept,628.376,1,628.376,173.737,.000 a,72.929,4,18.232,5.041,.009 diff --git a/tests/language/stats/logistic.at b/tests/language/stats/logistic.at index d604c0ad14..6952167fa0 100644 --- a/tests/language/stats/logistic.at +++ b/tests/language/stats/logistic.at @@ -110,41 +110,39 @@ logistic regression . ]) -AT_CHECK([pspp -O format=csv lr-data.sps], [0], - [dnl -Table: Dependent Variable Encoding +AT_CHECK([pspp -o pspp.csv -o pspp.txt lr-data.sps], [0], [dnl +note: Estimation terminated at iteration number 6 because parameter estimates changed by less than 0.001 +]) +AT_CHECK([cat pspp.csv], [0], [Table: Dependent Variable Encoding Original Value,Internal Value -1.000,0 -2.000,1 +1.000,.000 +2.000,1.000 Table: Case Processing Summary Unweighted Cases,N,Percent -Included in Analysis,66,100.000 -Missing Cases,0,.000 -Total,66,100.000 +Included in Analysis,66,100.0% +Missing Cases,0,.0% +Total,66,100.0% note: Estimation terminated at iteration number 6 because parameter estimates changed by less than 0.001 Table: Model Summary -Step 1,-2 Log likelihood,Cox & Snell R Square,Nagelkerke R Square -,37.323,.455,.659 +Step,-2 Log likelihood,Cox & Snell R Square,Nagelkerke R Square +1,37.323,.455,.659 Table: Classification Table ,,,Predicted,, -,,,outcome,,"Percentage -Correct" +,,,outcome,,Percentage Correct ,Observed,,1.000,2.000, -Step 1,outcome,1.000,43,5,89.583 -,,2.000,4,14,77.778 -,Overall Percentage,,,,86.364 +Step 1,outcome,1.000,43,5,89.6% +,,2.000,4,14,77.8% +,Overall Percentage,,,,86.4% Table: Variables in the Equation ,,B,S.E.,Wald,df,Sig.,Exp(B) Step 1,survrate,-.081,.019,17.756,1,.000,.922 ,Constant,2.684,.811,10.941,1,.001,14.639 ]) - - AT_CLEANUP AT_SETUP([LOGISTIC REGRESSION missing values]) @@ -180,13 +178,13 @@ AT_CHECK([pspp -O format=csv lr-data.sps > run1], [0], [ignore]) dnl Only the summary information should be different AT_CHECK([diff run0 run1], [1], [dnl 8,10c8,10 -< Included in Analysis,66,100.000 -< Missing Cases,0,.000 -< Total,66,100.000 +< Included in Analysis,66,100.0% +< Missing Cases,0,.0% +< Total,66,100.0% --- -> Included in Analysis,66,94.286 -> Missing Cases,4,5.714 -> Total,70,100.000 +> Included in Analysis,66,94.3% +> Missing Cases,4,5.7% +> Total,70,100.0% ]) AT_CLEANUP @@ -236,19 +234,19 @@ dnl The only difference should be the summary information, since dnl this displays the unweighted totals. AT_CHECK([diff unweighted-result weighted-result], [1], [dnl 8c8 -< Included in Analysis,66,100.000 +< Included in Analysis,66,100.0% --- -> Included in Analysis,63,100.000 +> Included in Analysis,63,100.0% 10c10 -< Total,66,100.000 +< Total,66,100.0% --- -> Total,63,100.000 -23,24c23,24 -< Step 1,outcome,1.000,43,5,89.583 -< ,,2.000,4,14,77.778 +> Total,63,100.0% +22,23c22,23 +< Step 1,outcome,1.000,43,5,89.6% +< ,,2.000,4,14,77.8% --- -> Step 1,outcome,1.000,43.000,5.000,89.583 -> ,,2.000,4.000,14.000,77.778 +> Step 1,outcome,1.000,43.000,5.000,89.6% +> ,,2.000,4.000,14.000,77.8% ]) @@ -277,33 +275,31 @@ compute constant = 1. logistic regression female with constant /noconst. ]) -AT_CHECK([pspp -O format=csv non-const.sps], [0], - [dnl +AT_CHECK([pspp -O format=csv non-const.sps], [0], [dnl Table: Dependent Variable Encoding Original Value,Internal Value -.00,0 -1.00,1 +.00,.000 +1.00,1.000 Table: Case Processing Summary Unweighted Cases,N,Percent -Included in Analysis,200,100.000 -Missing Cases,0,.000 -Total,200,100.000 +Included in Analysis,200,100.0% +Missing Cases,0,.0% +Total,200,100.0% note: Estimation terminated at iteration number 2 because parameter estimates changed by less than 0.001 Table: Model Summary -Step 1,-2 Log likelihood,Cox & Snell R Square,Nagelkerke R Square -,275.637,.008,.011 +Step,-2 Log likelihood,Cox & Snell R Square,Nagelkerke R Square +1,275.637,.008,.011 Table: Classification Table ,,,Predicted,, -,,,female,,"Percentage -Correct" +,,,female,,Percentage Correct ,Observed,,.00,1.00, -Step 1,female,.00,0,91,.000 -,,1.00,0,109,100.000 -,Overall Percentage,,,,54.500 +Step 1,female,.00,0,91,.0% +,,1.00,0,109,100.0% +,Overall Percentage,,,,54.5% Table: Variables in the Equation ,,B,S.E.,Wald,df,Sig.,Exp(B) @@ -759,28 +755,27 @@ logistic regression . ]) -AT_CHECK([pspp -O format=csv lr-cat.sps], [0], - [dnl +AT_CHECK([pspp -O format=csv lr-cat.sps], [0], [dnl Table: Dependent Variable Encoding Original Value,Internal Value -4.000,0 -9.000,1 +4.000,.000 +9.000,1.000 Table: Case Processing Summary Unweighted Cases,N,Percent -Included in Analysis,400,100.000 -Missing Cases,0,.000 -Total,400,100.000 +Included in Analysis,400,100.0% +Missing Cases,0,.0% +Total,400,100.0% note: Estimation terminated at iteration number 4 because parameter estimates changed by less than 0.001 Table: Model Summary -Step 1,-2 Log likelihood,Cox & Snell R Square,Nagelkerke R Square -,458.517,.098,.138 +Step,-2 Log likelihood,Cox & Snell R Square,Nagelkerke R Square +1,458.517,.098,.138 Table: Categorical Variables' Codings -,,,Parameter coding,, -,,Frequency,(1),(2),(3) +,,Frequency,Parameter coding,, +,,,(1),(2),(3) bcat,1.000,61,1,0,0 ,2.000,151,0,1,0 ,3.000,121,0,0,1 @@ -788,12 +783,11 @@ bcat,1.000,61,1,0,0 Table: Classification Table ,,,Predicted,, -,,,y,,"Percentage -Correct" +,,,y,,Percentage Correct ,Observed,,4.000,9.000, -Step 1,y,4.000,254,19,93.040 -,,9.000,97,30,23.622 -,Overall Percentage,,,,71.000 +Step 1,y,4.000,254,19,93.0% +,,9.000,97,30,23.6% +,Overall Percentage,,,,71.0% Table: Variables in the Equation ,,B,S.E.,Wald,df,Sig.,Exp(B) @@ -805,7 +799,6 @@ Step 1,b1,.002,.001,4.284,1,.038,1.002 ,bcat(3),.211,.393,.289,1,.591,1.235 ,Constant,-5.541,1.138,23.709,1,.000,.004 ]) - AT_CLEANUP @@ -1029,40 +1022,38 @@ logistic regression honcomp with read science ses ]) -AT_CHECK([pspp -O format=csv stringcat.sps], [0], - [dnl +AT_CHECK([pspp -O format=csv stringcat.sps], [0], [dnl Table: Dependent Variable Encoding Original Value,Internal Value -.000,0 -1.000,1 +.000,.000 +1.000,1.000 Table: Case Processing Summary Unweighted Cases,N,Percent -Included in Analysis,200,100.000 -Missing Cases,0,.000 -Total,200,100.000 +Included in Analysis,200,100.0% +Missing Cases,0,.0% +Total,200,100.0% note: Estimation terminated at iteration number 5 because parameter estimates changed by less than 0.001 Table: Model Summary -Step 1,-2 Log likelihood,Cox & Snell R Square,Nagelkerke R Square -,165.701,.280,.408 +Step,-2 Log likelihood,Cox & Snell R Square,Nagelkerke R Square +1,165.701,.280,.408 Table: Categorical Variables' Codings -,,,Parameter coding, -,,Frequency,(1),(2) +,,Frequency,Parameter coding, +,,,(1),(2) ses,a,47,1,0 ,b,95,0,1 ,c,58,0,0 Table: Classification Table ,,,Predicted,, -,,,honcomp,,"Percentage -Correct" +,,,honcomp,,Percentage Correct ,Observed,,.000,1.000, -Step 1,honcomp,.000,132,15,89.796 -,,1.000,26,27,50.943 -,Overall Percentage,,,,79.500 +Step 1,honcomp,.000,132,15,89.8% +,,1.000,26,27,50.9% +,Overall Percentage,,,,79.5% Table: Variables in the Equation ,,B,S.E.,Wald,df,Sig.,Exp(B) @@ -1222,13 +1213,13 @@ AT_CHECK([pspp -O format=csv miss.sps > file2], [0], [ignore]) AT_CHECK([diff file1 file2], [1], [dnl 8,10c8,10 -< Included in Analysis,100,100.00 -< Missing Cases,0,.00 -< Total,100,100.00 +< Included in Analysis,100,100.0% +< Missing Cases,0,.0% +< Total,100,100.0% --- -> Included in Analysis,100,99.01 -> Missing Cases,1,.99 -> Total,101,100.00 +> Included in Analysis,100,99.0% +> Missing Cases,1,1.0% +> Total,101,100.0% ]) AT_CLEANUP @@ -1452,24 +1443,24 @@ logistic regression AT_CHECK([pspp -O format=csv ci.sps], [0], [dnl Table: Dependent Variable Encoding Original Value,Internal Value -.000,0 -1.000,1 +.000,.000 +1.000,1.000 Table: Case Processing Summary Unweighted Cases,N,Percent -Included in Analysis,196,100.000 -Missing Cases,0,.000 -Total,196,100.000 +Included in Analysis,196,100.0% +Missing Cases,0,.0% +Total,196,100.0% note: Estimation terminated at iteration number 4 because parameter estimates changed by less than 0.001 Table: Model Summary -Step 1,-2 Log likelihood,Cox & Snell R Square,Nagelkerke R Square -,211.195,.120,.172 +Step,-2 Log likelihood,Cox & Snell R Square,Nagelkerke R Square +1,211.195,.120,.172 Table: Categorical Variables' Codings -,,,Parameter coding, -,,Frequency,(1),(2) +,,Frequency,Parameter coding, +,,,(1),(2) sciostat,1.000,77,1,0 ,2.000,49,0,1 ,3.000,70,0,0 @@ -1478,16 +1469,15 @@ sector,1.000,117,1, Table: Classification Table ,,,Predicted,, -,,,disease,,"Percentage -Correct" +,,,disease,,Percentage Correct ,Observed,,.000,1.000, -Step 1,disease,.000,131,8,94.245 -,,1.000,41,16,28.070 -,Overall Percentage,,,,75.000 +Step 1,disease,.000,131,8,94.2% +,,1.000,41,16,28.1% +,Overall Percentage,,,,75.0% Table: Variables in the Equation -,,,,,,,,95% CI for Exp(B), -,,B,S.E.,Wald,df,Sig.,Exp(B),Lower,Upper +,,B,S.E.,Wald,df,Sig.,Exp(B),95% CI for Exp(B), +,,,,,,,,Lower,Upper Step 1,age,.027,.009,8.647,1,.003,1.027,1.009,1.045 ,savings,.061,.386,.025,1,.874,1.063,.499,2.264 ,sciostat,,,.440,2,.803,,, diff --git a/tests/language/stats/means.at b/tests/language/stats/means.at index d4db9ec8af..93ef68ac70 100644 --- a/tests/language/stats/means.at +++ b/tests/language/stats/means.at @@ -61,8 +61,8 @@ Table: Case Processing Summary ,Cases,,,,, ,Included,,Excluded,,Total, ,N,Percent,N,Percent,N,Percent -score: factor,26,100%,0,0%,26,100% -score: ,26,100%,0,0%,26,100% +score: factor,26,100.0%,0,.0%,26,100.0% +score: ,26,100.0%,0,.0%,26,100.0% Table: Report ,factor,Mean,N,Std. Deviation @@ -101,7 +101,7 @@ Table: Case Processing Summary ,Cases,,,,, ,Included,,Excluded,,Total, ,N,Percent,N,Percent,N,Percent -score: ,4,100%,0,0%,4,100% +score: ,4,100.0%,0,.0%,4,100.0% Table: Report ,Mean,N,Std. Deviation @@ -143,16 +143,16 @@ Table: Case Processing Summary ,Cases,,,,, ,Included,,Excluded,,Total, ,N,Percent,N,Percent,N,Percent -a: g1 * g2,6,75%,2,25%,8,100% -a: g2,6,75%,2,25%,8,100% -a: ,7,87.5%,1,12.5%,8,100% +a: g1 × g2,6,75.0%,2,25.0%,8,100.0% +a: g2,6,75.0%,2,25.0%,8,100.0% +a: ,7,87.5%,1,12.5%,8,100.0% Table: Report ,g1,g2,Mean,N a,1.00,11.00,4.00,1.00 -,1.00,21.00,3.00,1.00 -,2.00,21.00,6.00,1.00 -,2.00,31.00,5.67,3.00 +,,21.00,3.00,1.00 +,2.00,,6.00,1.00 +,,31.00,5.67,3.00 Table: Report ,g2,Mean,N @@ -202,8 +202,8 @@ Table: Case Processing Summary ,Cases,,,,, ,Included,,Excluded,,Total, ,N,Percent,N,Percent,N,Percent -test1: group,10,100%,0,0%,10,100% -test1: ,10,100%,0,0%,10,100% +test1: group,10,100.0%,0,.0%,10,100.0% +test1: ,10,100.0%,0,.0%,10,100.0% Table: Report ,group,Mean,N,Std. Deviation,Sum,Min,Max,Range,Variance,Kurtosis,Skewness @@ -248,8 +248,8 @@ Table: Case Processing Summary ,Cases,,,,, ,Included,,Excluded,,Total, ,N,Percent,N,Percent,N,Percent -test1: group,10,100%,0,0%,10,100% -test1: ,10,100%,0,0%,10,100% +test1: group,10,100.0%,0,.0%,10,100.0% +test1: ,10,100.0%,0,.0%,10,100.0% Table: Report ,group,Mean,N,S.E. Mean,S.E. Skew,S.E. Kurt @@ -292,8 +292,8 @@ Table: Case Processing Summary ,Cases,,,,, ,Included,,Excluded,,Total, ,N,Percent,N,Percent,N,Percent -x: ,5,100%,0,0%,5,100% -y: ,5,100%,0,0%,5,100% +x: ,5,100.0%,0,.0%,5,100.0% +y: ,5,100.0%,0,.0%,5,100.0% Table: Report ,Mean,Harmonic Mean,Geom. Mean @@ -337,7 +337,7 @@ Table: Case Processing Summary ,Cases,,,,, ,Included,,Excluded,,Total, ,N,Percent,N,Percent,N,Percent -score: ,5,100%,0,0%,5,100% +score: ,5,100.0%,0,.0%,5,100.0% Table: Report ,Mean,N,Std. Deviation,S.E. Mean,Sum,Min,Max,Range,Variance,Kurtosis,S.E. Kurt,Skewness,S.E. Skew,First,Last,Harmonic Mean,Geom. Mean @@ -347,7 +347,7 @@ Table: Case Processing Summary ,Cases,,,,, ,Included,,Excluded,,Total, ,N,Percent,N,Percent,N,Percent -score: ,5,100%,0,0%,5,100% +score: ,5,100.0%,0,.0%,5,100.0% Table: Report ,Mean,N,Std. Deviation @@ -357,11 +357,9 @@ Table: Case Processing Summary ,Cases,,,,, ,Included,,Excluded,,Total, ,N,Percent,N,Percent,N,Percent -score: ,5,100%,0,0%,5,100% +score: ,5,100.0%,0,.0%,5,100.0% Table: Report - -score ]) AT_CLEANUP @@ -397,16 +395,16 @@ MEANS a b BY g1 ]) -AT_CHECK([pspp -O format=csv means-miss-table.sps], [0], - [dnl +AT_CHECK([pspp -o pspp.csv -o pspp.txt means-miss-table.sps]) +AT_CHECK([cat pspp.csv], [0], [dnl Table: Case Processing Summary ,Cases,,,,, ,Included,,Excluded,,Total, ,N,Percent,N,Percent,N,Percent -a: g1,7,100%,0,0%,7,100% -a: ,7,100%,0,0%,7,100% -b: g1,6,85.7143%,1,14.2857%,7,100% -b: ,6,85.7143%,1,14.2857%,7,100% +a: g1,7,100.0%,0,.0%,7,100.0% +a: ,7,100.0%,0,.0%,7,100.0% +b: g1,6,85.7%,1,14.3%,7,100.0% +b: ,6,85.7%,1,14.3%,7,100.0% Table: Report ,g1,N @@ -424,8 +422,8 @@ Table: Case Processing Summary ,Cases,,,,, ,Included,,Excluded,,Total, ,N,Percent,N,Percent,N,Percent -a: g1,7,100%,0,0%,7,100% -a: ,7,100%,0,0%,7,100% +a: g1,7,100.0%,0,.0%,7,100.0% +a: ,7,100.0%,0,.0%,7,100.0% Table: Report ,g1,N @@ -440,10 +438,10 @@ Table: Case Processing Summary ,Cases,,,,, ,Included,,Excluded,,Total, ,N,Percent,N,Percent,N,Percent -a: g1,7,100%,0,0%,7,100% -a: ,7,100%,0,0%,7,100% -b: g1,6,85.7143%,1,14.2857%,7,100% -b: ,6,85.7143%,1,14.2857%,7,100% +a: g1,7,100.0%,0,.0%,7,100.0% +a: ,7,100.0%,0,.0%,7,100.0% +b: g1,6,85.7%,1,14.3%,7,100.0% +b: ,6,85.7%,1,14.3%,7,100.0% Table: Report ,g1,N @@ -461,8 +459,8 @@ Table: Case Processing Summary ,Cases,,,,, ,Included,,Excluded,,Total, ,N,Percent,N,Percent,N,Percent -a: g1,7,100%,0,0%,7,100% -a: ,7,100%,0,0%,7,100% +a: g1,7,100.0%,0,.0%,7,100.0% +a: ,7,100.0%,0,.0%,7,100.0% Table: Report ,g1,N @@ -473,13 +471,8 @@ Table: Report ,N a,7.00 ]) - AT_CLEANUP - - - - AT_SETUP([MEANS user missing values]) AT_KEYWORDS([categorical categoricals]) @@ -505,16 +498,16 @@ MEANS a b BY g1 /cells = COUNT /missing = dependent . ]) -AT_CHECK([pspp -O format=csv means-missing.sps], [0], - [dnl +AT_CHECK([pspp -o pspp.csv -o pspp.txt means-missing.sps]) +AT_CHECK([cat pspp.csv], [0], [dnl Table: Case Processing Summary ,Cases,,,,, ,Included,,Excluded,,Total, ,N,Percent,N,Percent,N,Percent -a: g1,6,85.7143%,1,14.2857%,7,100% -a: ,7,100%,0,0%,7,100% -b: g1,5,71.4286%,2,28.5714%,7,100% -b: ,6,85.7143%,1,14.2857%,7,100% +a: g1,6,85.7%,1,14.3%,7,100.0% +a: ,7,100.0%,0,.0%,7,100.0% +b: g1,5,71.4%,2,28.6%,7,100.0% +b: ,6,85.7%,1,14.3%,7,100.0% Table: Report ,g1,N @@ -532,10 +525,10 @@ Table: Case Processing Summary ,Cases,,,,, ,Included,,Excluded,,Total, ,N,Percent,N,Percent,N,Percent -a: g1,7,100%,0,0%,7,100% -a: ,7,100%,0,0%,7,100% -b: g1,7,100%,0,0%,7,100% -b: ,7,100%,0,0%,7,100% +a: g1,7,100.0%,0,.0%,7,100.0% +a: ,7,100.0%,0,.0%,7,100.0% +b: g1,7,100.0%,0,.0%,7,100.0% +b: ,7,100.0%,0,.0%,7,100.0% Table: Report ,g1,N @@ -555,10 +548,10 @@ Table: Case Processing Summary ,Cases,,,,, ,Included,,Excluded,,Total, ,N,Percent,N,Percent,N,Percent -a: g1,7,100%,0,0%,7,100% -a: ,7,100%,0,0%,7,100% -b: g1,6,85.7143%,1,14.2857%,7,100% -b: ,6,85.7143%,1,14.2857%,7,100% +a: g1,7,100.0%,0,.0%,7,100.0% +a: ,7,100.0%,0,.0%,7,100.0% +b: g1,6,85.7%,1,14.3%,7,100.0% +b: ,6,85.7%,1,14.3%,7,100.0% Table: Report ,g1,N @@ -574,7 +567,6 @@ Table: Report a,7.00 b,6.00 ]) - AT_CLEANUP diff --git a/tests/language/stats/npar.at b/tests/language/stats/npar.at index 24a8cce659..10889a4123 100644 --- a/tests/language/stats/npar.at +++ b/tests/language/stats/npar.at @@ -35,8 +35,8 @@ NPAR TESTS AT_CHECK([pspp -O format=csv npar.sps], [0], [dnl Table: Binomial Test ,,Category,N,Observed Prop.,Test Prop.,Exact Sig. (1-tailed) -x,Group1,1.000,6.000,.286,.300,.551 -,Group2,2.000,15.000,.714,, +x,Group 1,1.000,6.000,.286,.300,.551 +,Group 2,2.000,15.000,.714,, ,Total,,21.000,1.000,, ]) AT_CLEANUP @@ -60,8 +60,8 @@ NPAR TESTS AT_CHECK([pspp -O format=csv npar.sps], [0], [dnl Table: Binomial Test ,,Category,N,Observed Prop.,Test Prop.,Exact Sig. (1-tailed) -x,Group1,1,7,.538,.400,.229 -,Group2,2,6,.462,, +x,Group 1,1,7,.538,.400,.229 +,Group 2,2,6,.462,, ,Total,,13,1.000,, ]) AT_CLEANUP @@ -85,8 +85,8 @@ NPAR TESTS AT_CHECK([pspp -O format=csv npar.sps], [0], [dnl Table: Binomial Test ,,Category,N,Observed Prop.,Test Prop.,Exact Sig. (1-tailed) -x,Group1,1,8,.500,.400,.284 -,Group2,2,8,.500,, +x,Group 1,1,8,.500,.400,.284 +,Group 2,2,8,.500,, ,Total,,16,1.000,, ]) AT_CLEANUP @@ -110,8 +110,8 @@ NPAR TESTS AT_CHECK([pspp -O format=csv npar.sps], [0], [dnl Table: Binomial Test ,,Category,N,Observed Prop.,Test Prop.,Exact Sig. (1-tailed) -x,Group1,1,11,.478,.600,.164 -,Group2,2,12,.522,, +x,Group 1,1,11,.478,.600,.164 +,Group 2,2,12,.522,, ,Total,,23,1.000,, ]) AT_CLEANUP @@ -134,8 +134,8 @@ NPAR TESTS AT_CHECK([pspp -O format=csv npar.sps], [0], [dnl Table: Binomial Test ,,Category,N,Observed Prop.,Test Prop.,Exact Sig. (1-tailed) -x,Group1,1,11,.550,.600,.404 -,Group2,2,9,.450,, +x,Group 1,1,11,.550,.600,.404 +,Group 2,2,9,.450,, ,Total,,20,1.000,, ]) AT_CLEANUP @@ -158,8 +158,8 @@ NPAR TESTS AT_CHECK([pspp -O format=csv npar.sps], [0], [dnl Table: Binomial Test ,,Category,N,Observed Prop.,Test Prop.,Exact Sig. (1-tailed) -x,Group1,1,11,.500,.600,.228 -,Group2,2,11,.500,, +x,Group 1,1,11,.500,.600,.228 +,Group 2,2,11,.500,, ,Total,,22,1.000,, ]) AT_CLEANUP @@ -183,8 +183,8 @@ NPAR TESTS AT_CHECK([pspp -O format=csv npar.sps], [0], [dnl Table: Binomial Test ,,Category,N,Observed Prop.,Test Prop.,Exact Sig. (2-tailed) -x,Group1,1,8,.348,.500,.210 -,Group2,2,15,.652,, +x,Group 1,1,8,.348,.500,.210 +,Group 2,2,15,.652,, ,Total,,23,1.000,, ]) AT_CLEANUP @@ -207,8 +207,8 @@ NPAR TESTS AT_CHECK([pspp -O format=csv npar.sps], [0], [dnl Table: Binomial Test ,,Category,N,Observed Prop.,Test Prop.,Exact Sig. (2-tailed) -x,Group1,1,12,.667,.500,.238 -,Group2,2,6,.333,, +x,Group 1,1,12,.667,.500,.238 +,Group 2,2,6,.333,, ,Total,,18,1.000,, ]) AT_CLEANUP @@ -232,8 +232,8 @@ NPAR TESTS AT_CHECK([pspp -O format=csv npar.sps], [0], [dnl Table: Binomial Test ,,Category,N,Observed Prop.,Test Prop.,Exact Sig. (2-tailed) -x,Group1,1,10,.500,.500,1.000 -,Group2,2,10,.500,, +x,Group 1,1,10,.500,.500,1.000 +,Group 2,2,10,.500,, ,Total,,20,1.000,, ]) AT_CLEANUP @@ -258,8 +258,8 @@ NPAR TESTS AT_CHECK([pspp -O format=csv npar.sps], [0], [dnl Table: Binomial Test ,,Category,N,Observed Prop.,Test Prop.,Exact Sig. (2-tailed) -x,Group1,<= 10,10.000,.385,.500,.327 -,Group2,,16.000,.615,, +x,Group 1,<= 10,10.000,.385,.500,.327 +,Group 2,,16.000,.615,, ,Total,,26.000,1.000,, ]) AT_CLEANUP @@ -284,8 +284,8 @@ NPAR TESTS AT_CHECK([pspp -O format=csv npar.sps], [0], [dnl Table: Binomial Test ,,Category,N,Observed Prop.,Test Prop.,Exact Sig. (2-tailed) -x,Group1,10.000,10.000,.435,.500,.678 -,Group2,20.000,13.000,.565,, +x,Group 1,10.000,10.000,.435,.500,.678 +,Group 2,20.000,13.000,.565,, ,Total,,23.000,1.000,, ]) AT_CLEANUP @@ -344,7 +344,7 @@ NPAR TESTS AT_CHECK([pspp -O format=csv npar.sps], [0], [dnl Table: x -,Observed N,Expected N,Residual +Value,Observed N,Expected N,Residual 1.00,3.00,2.33,.67 2.00,3.00,2.33,.67 3.10,4.00,2.33,1.67 @@ -354,7 +354,7 @@ Table: x Total,14.00,, Table: y -,Observed N,Expected N,Residual +Value,Observed N,Expected N,Residual 1.00,7.00,3.50,3.50 2.00,4.00,3.50,.50 3.00,1.00,3.50,-2.50 @@ -362,13 +362,12 @@ Table: y Total,14.00,, Table: Test Statistics -,x,y -Chi-Square,3.14,6.00 -df,5,3 -Asymp. Sig.,.678,.112 +,Chi-square,df,Asymp. Sig. +x,3.14,5,.678 +y,6.00,3,.112 Table: y -,Observed N,Expected N,Residual +Value,Observed N,Expected N,Residual 1.00,7.00,2.63,4.38 2.00,4.00,3.50,.50 3.00,1.00,4.38,-3.38 @@ -376,10 +375,8 @@ Table: y Total,14.00,, Table: Test Statistics -,y -Chi-Square,10.61 -df,3 -Asymp. Sig.,.014 +,Chi-square,df,Asymp. Sig. +y,10.61,3,.014 Table: Frequencies ,x,,,,y,,, @@ -390,10 +387,9 @@ Table: Frequencies Total,,10.00,,,,7.00,, Table: Test Statistics -,x,y -Chi-Square,.13,4.13 -df,2,2 -Asymp. Sig.,.936,.127 +,Chi-square,df,Asymp. Sig. +x,.13,2,.936 +y,4.13,2,.127 ]) AT_CLEANUP @@ -420,13 +416,11 @@ NPAR TESTS ]) AT_CHECK([pspp -O format=csv npar.sps], [1], [dnl -"error: CHISQUARE test specified 6 expected values, but 4 distinct values were encountered in variable y." +"error: CHISQUARE test specified 6 expected values, but variable y has 4 distinct values." Table: Test Statistics -,y -Chi-Square,.00 -df,0 -Asymp. Sig.,1.000 +,Chi-square,df,Asymp. Sig. +y,.00,0,1.000 ]) AT_CLEANUP @@ -471,14 +465,12 @@ Table: Frequencies Total,,12.00,,,,15.00,, Table: Test Statistics -,x,y -Chi-Square,17.33,22.87 -df,7,7 -Asymp. Sig.,.015,.002 +,Chi-square,df,Asymp. Sig. +x,17.33,7,.015 +y,22.87,7,.002 Table: Descriptive Statistics ,N,Mean,Std. Deviation,Minimum,Maximum -,,,,, x,12.00,2.47,1.19,1.00,5.00 y,15.00,2.07,1.33,1.00,5.00 ]) @@ -524,14 +516,12 @@ Table: Frequencies Total,,14.00,,,,14.00,, Table: Test Statistics -,x,y -Chi-Square,13.43,26.00 -df,7,7 -Asymp. Sig.,.062,.001 +,Chi-square,df,Asymp. Sig. +x,13.43,7,.062 +y,26.00,7,.001 Table: Descriptive Statistics ,N,Mean,Std. Deviation,Minimum,Maximum -,,,,, x,14.00,2.69,1.23,1.00,5.00 y,14.00,1.86,1.10,1.00,4.00 ]) @@ -711,20 +701,20 @@ npar tests . ]) -AT_CHECK([pspp -o pspp.csv kw-simple.sps]) +AT_CHECK([pspp -o pspp.csv -o pspp.txt kw-simple.sps]) AT_CHECK([cat pspp.csv], [0], [dnl Table: Ranks -,gv,N,Mean Rank +,,N,Mean Rank xscore,timed out,5,4.400 ,hit wicket,5,7.400 ,handled the ball,4,11.500 ,Total,14, Table: Test Statistics -,,xscore -Chi-Square,,6.406 -df,,2 -Asymp. Sig.,,.041 +,xscore +Chi-Square,6.406 +df,2 +Asymp. Sig.,.041 ]) @@ -818,7 +808,7 @@ npar tests AT_CHECK([pspp -o pspp.csv kw-multi.sps]) AT_CHECK([cat pspp.csv], [0], [dnl Table: Ranks -,gv,N,Mean Rank +,,N,Mean Rank xscore,timed out,5,4.400 ,hit wicket,5,7.400 ,handled the ball,4,11.500 @@ -829,10 +819,10 @@ yscore,hit wicket,5,7.400 ,Total,14, Table: Test Statistics -,,xscore,yscore, -Chi-Square,,6.406,6.406, -df,,2,2, -Asymp. Sig.,,.041,.041, +,xscore,yscore +Chi-Square,6.406,6.406 +df,2,2 +Asymp. Sig.,.041,.041 ]) AT_CLEANUP @@ -1037,9 +1027,10 @@ NPAR TESTS AT_CHECK([pspp -O format=csv npar-mann-whitney.sps], [0], [dnl Table: Ranks -,N,,,Mean Rank,,Sum of Ranks, -,0,1,Total,0,1,0,1 -height,15.0000,15.0000,30.0000,14.5333,16.4667,218.0000,247.0000 +,,N,Mean Rank,Sum of Ranks +height,0,15,14.5333,218.0000 +,1,15,16.4667,247.0000 +,Total,30,, Table: Test Statistics ,Mann-Whitney U,Wilcoxon W,Z,Asymp. Sig. (2-tailed) @@ -1077,12 +1068,19 @@ NPAR TESTS AT_CHECK([pspp -O format=csv npar-mann-whitney.sps], [0], [dnl Table: Ranks -,N,,,Mean Rank,,Sum of Ranks, -,.000,1.000,Total,.000,1.000,.000,1.000 -IOS: Familie,114.000,115.000,229.000,110.018,119.939,12542.000,13793.000 -IOS: Freunde,115.000,115.000,230.000,108.339,122.661,12459.000,14106.000 -IOS: Partner*in,97.000,91.000,188.000,95.351,93.593,9249.000,8517.000 -IOS: Bekannte,115.000,115.000,230.000,111.065,119.935,12772.500,13792.500 +,,N,Mean Rank,Sum of Ranks +IOS: Familie,.000,114,110.018,12542.000 +,1.000,115,119.939,13793.000 +,Total,229,, +IOS: Freunde,.000,115,108.339,12459.000 +,1.000,115,122.661,14106.000 +,Total,230,, +IOS: Partner*in,.000,97,95.351,9249.000 +,1.000,91,93.593,8517.000 +,Total,188,, +IOS: Bekannte,.000,115,111.065,12772.500 +,1.000,115,119.935,13792.500 +,Total,230,, Table: Test Statistics ,Mann-Whitney U,Wilcoxon W,Z,Asymp. Sig. (2-tailed) @@ -1133,6 +1131,7 @@ v6,2,7 v7,5,4 Table: Test Statistics +,Value N,9 Cochran's Q,12.735 df,6 @@ -1242,14 +1241,14 @@ npar tests AT_CHECK([pspp -O format=csv mcnemar.sps], [0], [dnl Table: v1 & v2 -v1,v2, -,.000,1.000 +,v2, +v1,.000,1.000 .000,4,9 1.000,2,5 Table: v1 & junk -v1,junk, -,.000,1.000 +,junk, +v1,.000,1.000 .000,8,5 1.000,2,5 @@ -1850,4 +1849,4 @@ NPAR TESTS AT_CHECK([pspp -O format=csv npar.sps], [1], [ignore]) AT_CLEANUP - \ No newline at end of file + diff --git a/tests/language/stats/oneway.at b/tests/language/stats/oneway.at index 58fd75e289..be9ae130e4 100644 --- a/tests/language/stats/oneway.at +++ b/tests/language/stats/oneway.at @@ -51,10 +51,11 @@ ONEWAY . ]) -AT_CHECK([pspp -O format=csv oneway.sps], [0], [dnl +AT_CHECK([pspp -o pspp.csv -o pspp.txt oneway.sps]) +AT_CHECK([cat pspp.csv], [0], [dnl Table: Descriptives -,,,,,,95% Confidence Interval for Mean,,, -,,N,Mean,Std. Deviation,Std. Error,Lower Bound,Upper Bound,Minimum,Maximum +,,N,Mean,Std. Deviation,Std. Error,95% Confidence Interval for Mean,,Minimum,Maximum +,Manufacturer,,,,,Lower Bound,Upper Bound,, Breaking Strain,Aspeger,5,2.20,1.30,.58,.58,3.82,1.00,4.00 ,Bloggs,5,3.20,1.30,.58,1.58,4.82,2.00,5.00 ,Charlies,5,5.00,1.58,.71,3.04,6.96,3.00,7.00 @@ -71,16 +72,16 @@ Breaking Strain,Between Groups,20.13,2,10.07,5.12,.025 ,Total,43.73,14,,, Table: Contrast Coefficients -,,Manufacturer,, -,,Aspeger,Bloggs,Charlies -Contrast,1,-2,1,1 -,2,0,-1,1 +,Manufacturer,, +Contrast,Aspeger,Bloggs,Charlies +1,-2,1,1 +2,0,-1,1 Table: Contrast Tests ,,Contrast,Value of Contrast,Std. Error,t,df,Sig. (2-tailed) -Breaking Strain,Assume equal variances,1,3.80,1.54,2.47,12,.029 -,,2,1.80,.89,2.03,12,.065 -,Does not assume equal,1,3.80,1.48,2.56,8.74,.031 +Breaking Strain,Assume equal variances,1,3.80,1.54,2.47,12.00,.029 +,,2,1.80,.89,2.03,12.00,.065 +,Does not assume equal variances,1,3.80,1.48,2.56,8.74,.031 ,,2,1.80,.92,1.96,7.72,.086 ]) AT_CLEANUP @@ -123,13 +124,15 @@ ONEWAY . ]) -AT_CHECK([pspp -O format=csv oneway-splits.sps], [0], -[Variable,Value,Label -S,1.00, +AT_CHECK([pspp -o pspp.csv -o pspp.txt oneway-splits.sps]) +AT_CHECK([cat pspp.csv], [0], [dnl +Table: Split Values +Variable,Value +S,1.00 Table: Descriptives -,,,,,,95% Confidence Interval for Mean,,, -,,N,Mean,Std. Deviation,Std. Error,Lower Bound,Upper Bound,Minimum,Maximum +,,N,Mean,Std. Deviation,Std. Error,95% Confidence Interval for Mean,,Minimum,Maximum +,Manufacturer,,,,,Lower Bound,Upper Bound,, Breaking Strain,Aspeger,5,2.20,1.30,.58,.58,3.82,1.00,4.00 ,Bloggs,2,3.50,2.12,1.50,-15.56,22.56,2.00,5.00 ,Total,7,2.57,1.51,.57,1.17,3.97,1.00,5.00 @@ -145,24 +148,25 @@ Breaking Strain,Between Groups,2.41,1,2.41,1.07,.349 ,Total,13.71,6,,, Table: Contrast Coefficients -,,Manufacturer, -,,Aspeger,Bloggs -Contrast,1,-2,2 -,2,-1,1 +,Manufacturer, +Contrast,Aspeger,Bloggs +1,-2,2 +2,-1,1 Table: Contrast Tests ,,Contrast,Value of Contrast,Std. Error,t,df,Sig. (2-tailed) -Breaking Strain,Assume equal variances,1,2.60,2.52,1.03,5,.349 -,,2,1.30,1.26,1.03,5,.349 -,Does not assume equal,1,2.60,3.22,.81,1.32,.539 +Breaking Strain,Assume equal variances,1,2.60,2.52,1.03,5.00,.349 +,,2,1.30,1.26,1.03,5.00,.349 +,Does not assume equal variances,1,2.60,3.22,.81,1.32,.539 ,,2,1.30,1.61,.81,1.32,.539 -Variable,Value,Label -S,2.00, +Table: Split Values +Variable,Value +S,2.00 Table: Descriptives -,,,,,,95% Confidence Interval for Mean,,, -,,N,Mean,Std. Deviation,Std. Error,Lower Bound,Upper Bound,Minimum,Maximum +,,N,Mean,Std. Deviation,Std. Error,95% Confidence Interval for Mean,,Minimum,Maximum +,Manufacturer,,,,,Lower Bound,Upper Bound,, Breaking Strain,Bloggs,3,3.00,1.00,.58,.52,5.48,2.00,4.00 ,Charlies,5,5.00,1.58,.71,3.04,6.96,3.00,7.00 ,Total,8,4.25,1.67,.59,2.85,5.65,2.00,7.00 @@ -178,19 +182,18 @@ Breaking Strain,Between Groups,7.50,1,7.50,3.75,.101 ,Total,19.50,7,,, Table: Contrast Coefficients -,,Manufacturer, -,,Bloggs,Charlies -Contrast,1,-2,2 -,2,-1,1 +,Manufacturer, +Contrast,Bloggs,Charlies +1,-2,2 +2,-1,1 Table: Contrast Tests ,,Contrast,Value of Contrast,Std. Error,t,df,Sig. (2-tailed) -Breaking Strain,Assume equal variances,1,4.00,2.07,1.94,6,.101 -,,2,2.00,1.03,1.94,6,.101 -,Does not assume equal,1,4.00,1.83,2.19,5.88,.072 +Breaking Strain,Assume equal variances,1,4.00,2.07,1.94,6.00,.101 +,,2,2.00,1.03,1.94,6.00,.101 +,Does not assume equal variances,1,4.00,1.83,2.19,5.88,.072 ,,2,2.00,.91,2.19,5.88,.072 ]) - AT_CLEANUP @@ -332,8 +335,8 @@ ONEWAY AT_CHECK([pspp -O format=csv oneway-descriptives.sps], [0], [Table: Descriptives -,,,,,,95% Confidence Interval for Mean,,, -,,N,Mean,Std. Deviation,Std. Error,Lower Bound,Upper Bound,Minimum,Maximum +,,N,Mean,Std. Deviation,Std. Error,95% Confidence Interval for Mean,,Minimum,Maximum +,BRAND,,,,,Lower Bound,Upper Bound,, QUALITY,11.00,5,12.20,1.30,.58,10.58,13.82,11.00,14.00 ,25.00,5,13.20,1.30,.58,11.58,14.82,12.00,15.00 ,301.00,5,15.00,1.58,.71,13.04,16.96,13.00,17.00 @@ -437,13 +440,13 @@ ONEWAY x y z by g . ]) -AT_CHECK([pspp -o pspp.csv multivar.sps]) +AT_CHECK([pspp -o pspp.csv -o pspp.txt multivar.sps]) dnl Some machines return 3.88 instead of 3.87 below (see bug #31611). -AT_CHECK([sed 's/^,Within Groups,3.88/,Within Groups,3.87/' pspp.csv], [0], [dnl -Table: Descriptives -,,,,,,95% Confidence Interval for Mean,,, -,,N,Mean,Std. Deviation,Std. Error,Lower Bound,Upper Bound,Minimum,Maximum +AT_CHECK([sed 's/^,Within Groups,3.88/,Within Groups,3.87/' pspp.csv], [0], + [Table: Descriptives +,,N,Mean,Std. Deviation,Std. Error,95% Confidence Interval for Mean,,Minimum,Maximum +,g,,,,,Lower Bound,Upper Bound,, x,10.00,3,3.67,4.62,2.67,-7.81,15.14,1.00,9.00 ,20.00,5,.80,.45,.20,.24,1.36,.00,1.00 ,30.00,8,.88,.64,.23,.34,1.41,.00,2.00 @@ -479,24 +482,24 @@ z,Between Groups,17.47,3,5.82,.62,.610 ,Total,205.33,23,,, Table: Contrast Coefficients -,,g,,, -,,10.00,20.00,30.00,40.00 -Contrast,1,3,2,0,-5 -,2,2,-9,7,0 +,g,,, +Contrast,10.00,20.00,30.00,40.00 +1,3,2,0,-5 +2,2,-9,7,0 Table: Contrast Tests ,,Contrast,Value of Contrast,Std. Error,t,df,Sig. (2-tailed) -x,Assume equal variances,1,-7.40,6.67,1.11,20,.280 -,,2,6.26,12.32,.51,20,.617 -,Does not assume equal,1,-7.40,10.04,-.74,4.53,.497 +x,Assume equal variances,1,-7.40,6.67,1.11,20.00,.280 +,,2,6.26,12.32,.51,20.00,.617 +,Does not assume equal variances,1,-7.40,10.04,-.74,4.53,1.503 ,,2,6.26,5.85,1.07,2.87,.366 -y,Assume equal variances,1,-6.88,1.16,5.94,20,.000 -,,2,3.50,2.14,1.63,20,.118 -,Does not assume equal,1,-6.88,.91,-7.51,7.00,.000 +y,Assume equal variances,1,-6.88,1.16,5.94,20.00,.000 +,,2,3.50,2.14,1.63,20.00,.118 +,Does not assume equal variances,1,-6.88,.91,-7.51,7.00,2.000 ,,2,3.50,1.32,2.65,7.00,.033 -z,Assume equal variances,1,-9.70,8.07,1.20,20,.243 -,,2,11.73,14.91,.79,20,.440 -,Does not assume equal,1,-9.70,9.57,-1.01,3.64,.373 +z,Assume equal variances,1,-9.70,8.07,1.20,20.00,.243 +,,2,11.73,14.91,.79,20.00,.440 +,Does not assume equal variances,1,-9.70,9.57,-1.01,3.64,1.627 ,,2,11.73,14.53,.81,9.88,.438 ]) @@ -612,10 +615,11 @@ oneway pigmentation by family . ]) -AT_CHECK([pspp -O format=csv oneway-pig.sps], [0], -[Table: Descriptives -,,,,,,95% Confidence Interval for Mean,,, -,,N,Mean,Std. Deviation,Std. Error,Lower Bound,Upper Bound,Minimum,Maximum +AT_CHECK([pspp -o pspp.csv -o pspp.txt oneway-pig.sps]) +AT_CHECK([cat pspp.csv], [0], [dnl +Table: Descriptives +,,N,Mean,Std. Deviation,Std. Error,95% Confidence Interval for Mean,,Minimum,Maximum +,family,,,,,Lower Bound,Upper Bound,, pigmentation,1.000,5,38.600,2.702,1.208,35.245,41.955,36.000,43.000 ,2.000,5,46.000,1.732,.775,43.849,48.151,43.000,47.000 ,3.000,5,46.400,4.336,1.939,41.016,51.784,40.000,50.000 @@ -629,8 +633,8 @@ pigmentation,Between Groups,478.950,3,159.650,12.927,.000 ,Total,676.550,19,,, Table: Multiple Comparisons (pigmentation) -,,,Mean Difference,,,95% Confidence Interval, -,(I) family,(J) family,(I - J),Std. Error,Sig.,Lower Bound,Upper Bound +,,,Mean Difference (I - J),Std. Error,Sig.,95% Confidence Interval, +,(J) Family,(J) Family,,,,Lower Bound,Upper Bound LSD,1.000,2.000,-7.400,2.223,.004,-12.112,-2.688 ,,3.000,-7.800,2.223,.003,-12.512,-3.088 ,,4.000,-13.800,2.223,.000,-18.512,-9.088 @@ -656,7 +660,6 @@ Bonferroni,1.000,2.000,-7.400,2.223,.025,-14.086,-.714 ,,2.000,6.400,2.223,.065,-.286,13.086 ,,3.000,6.000,2.223,.095,-.686,12.686 ]) - AT_CLEANUP @@ -691,23 +694,24 @@ oneway libido by dose /posthoc tukey gh. ]) -AT_CHECK([pspp -O format=csv oneway-tukey.sps], [0], -[Table: ANOVA +AT_CHECK([pspp -o pspp.csv -o pspp.txt oneway-tukey.sps]) +AT_CHECK([cat pspp.csv], [0], [dnl +Table: ANOVA ,,Sum of Squares,df,Mean Square,F,Sig. libido,Between Groups,20.133,2,10.067,5.119,.025 ,Within Groups,23.600,12,1.967,, ,Total,43.733,14,,, Table: Multiple Comparisons (libido) -,,,Mean Difference,,,95% Confidence Interval, -,(I) Dose of Viagra,(J) Dose of Viagra,(I - J),Std. Error,Sig.,Lower Bound,Upper Bound +,,,Mean Difference (I - J),Std. Error,Sig.,95% Confidence Interval, +,(J) Family,(J) Family,,,,Lower Bound,Upper Bound Tukey HSD,Placebo,1 Dose,-1.000,.887,.516,-3.366,1.366 ,,2 Doses,-2.800,.887,.021,-5.166,-.434 ,1 Dose,Placebo,1.000,.887,.516,-1.366,3.366 ,,2 Doses,-1.800,.887,.147,-4.166,.566 ,2 Doses,Placebo,2.800,.887,.021,.434,5.166 ,,1 Dose,1.800,.887,.147,-.566,4.166 -Games-Howell,Placebo,1 Dose,-1.000,.887,.479,-3.356,1.356 +Games-Howell,Placebo,,-1.000,.887,.479,-3.356,1.356 ,,2 Doses,-2.800,.887,.039,-5.439,-.161 ,1 Dose,Placebo,1.000,.887,.479,-1.356,3.356 ,,2 Doses,-1.800,.887,.185,-4.439,.839 @@ -760,8 +764,8 @@ score,Between Groups,54.9500,3,18.3167,7.0449,.003 ,Total,96.5500,19,,, Table: Multiple Comparisons (score) -,,,Mean Difference,,,95% Confidence Interval, -,(I) program,(J) program,(I - J),Std. Error,Sig.,Lower Bound,Upper Bound +,,,Mean Difference (I - J),Std. Error,Sig.,95% Confidence Interval, +,(J) Family,(J) Family,,,,Lower Bound,Upper Bound Šidák,1.0000,2.0000,3.0000,1.0198,.056,-.0575,6.0575 ,,3.0000,-.4000,1.0198,.999,-3.4575,2.6575 ,,4.0000,3.2000,1.0198,.038,.1425,6.2575 @@ -842,8 +846,8 @@ Days of Use,Between Groups,555.275,3,185.092,6.663,.001 ,Total,1555.375,39,,, Table: Multiple Comparisons (Days of Use) -,,,Mean Difference,,,95% Confidence Interval, -,(I) group,(J) group,(I - J),Std. Error,Sig.,Lower Bound,Upper Bound +,,,Mean Difference (I - J),Std. Error,Sig.,95% Confidence Interval, +,(J) Family,(J) Family,,,,Lower Bound,Upper Bound Scheffé,one,two,3.800,2.357,.467,-3.112,10.712 ,,three,10.300,2.357,.001,3.388,17.212 ,,four,6.000,2.357,.110,-.912,12.912 @@ -886,7 +890,10 @@ ONEWAY /VARIABLES= height weight temperature BY sex ]) -AT_CHECK([pspp -O format=csv oneway-bad-contrast.sps], [0], [dnl +AT_CHECK([pspp -o pspp.csv -o pspp.txt oneway-bad-contrast.sps], [0], [dnl +oneway-bad-contrast.sps:18: warning: ONEWAY: In contrast list 3, the number of coefficients (3) does not equal the number of groups (2). This contrast list will be ignored. +]) +AT_CHECK([cat pspp.csv], [0], [dnl "oneway-bad-contrast.sps:18: warning: ONEWAY: In contrast list 3, the number of coefficients (3) does not equal the number of groups (2). This contrast list will be ignored." Table: ANOVA @@ -902,34 +909,33 @@ temperature,Between Groups,1.80,1,1.80,.13,.733 ,Total,86.36,7,,, Table: Contrast Coefficients -,,sex, -,,.00,1.00 -Contrast,1,-1,1 -,2,-3,3 -,3,-9,9 +,sex, +Contrast,.00,1.00 +1,-1,1 +2,-3,3 +3,-9,9 Table: Contrast Tests ,,Contrast,Value of Contrast,Std. Error,t,df,Sig. (2-tailed) -height,Assume equal variances,1,-222.27,20.23,10.99,6,.000 -,,2,-666.80,60.68,10.99,6,.000 -,,3,-2000.40,182.03,10.99,6,.000 -,Does not assume equal,1,-222.27,27.67,-8.03,2.00,.015 -,,2,-666.80,83.02,-8.03,2.00,.015 -,,3,-2000.40,249.07,-8.03,2.00,.015 -weight,Assume equal variances,1,-36.16,2.74,13.21,6,.000 -,,2,-108.48,8.21,13.21,6,.000 -,,3,-325.44,24.63,13.21,6,.000 -,Does not assume equal,1,-36.16,2.19,-16.48,5.42,.000 -,,2,-108.48,6.58,-16.48,5.42,.000 -,,3,-325.44,19.75,-16.48,5.42,.000 -temperature,Assume equal variances,1,-.98,2.74,.36,6,.733 -,,2,-2.94,8.22,.36,6,.733 -,,3,-8.83,24.67,.36,6,.733 -,Does not assume equal,1,-.98,2.07,-.47,4.19,.660 -,,2,-2.94,6.22,-.47,4.19,.660 -,,3,-8.83,18.66,-.47,4.19,.660 +height,Assume equal variances,1,-222.27,20.23,10.99,6.00,.000 +,,2,-666.80,60.68,10.99,6.00,.000 +,,3,-2000.40,182.03,10.99,6.00,.000 +,Does not assume equal variances,1,-222.27,27.67,-8.03,2.00,1.985 +,,2,-666.80,83.02,-8.03,2.00,1.985 +,,3,-2000.40,249.07,-8.03,2.00,1.985 +weight,Assume equal variances,1,-36.16,2.74,13.21,6.00,.000 +,,2,-108.48,8.21,13.21,6.00,.000 +,,3,-325.44,24.63,13.21,6.00,.000 +,Does not assume equal variances,1,-36.16,2.19,-16.48,5.42,2.000 +,,2,-108.48,6.58,-16.48,5.42,2.000 +,,3,-325.44,19.75,-16.48,5.42,2.000 +temperature,Assume equal variances,1,-.98,2.74,.36,6.00,.733 +,,2,-2.94,8.22,.36,6.00,.733 +,,3,-8.83,24.67,.36,6.00,.733 +,Does not assume equal variances,1,-.98,2.07,-.47,4.19,1.340 +,,2,-2.94,6.22,-.47,4.19,1.340 +,,3,-8.83,18.66,-.47,4.19,1.340 ]) - AT_CLEANUP diff --git a/tests/language/stats/quick-cluster.at b/tests/language/stats/quick-cluster.at index ee790ac856..34c04945e9 100644 --- a/tests/language/stats/quick-cluster.at +++ b/tests/language/stats/quick-cluster.at @@ -45,14 +45,13 @@ z,F8.0 Table: Final Cluster Centers ,Cluster, -,, ,1,2 -,, x,6.50,19.20 y,7.50,3250.00 z,6.50,5058.00 Table: Number of Cases in each Cluster +,,Count Cluster,1,6 ,2,5 Valid,,11 @@ -75,12 +74,11 @@ AT_CHECK([pspp -o pspp.csv quick-cluster.sps]) AT_CHECK([cat pspp.csv], [0], [dnl Table: Final Cluster Centers ,Cluster,,, -,,,, ,1,2,3,4 -,,,, x,NaN,NaN,NaN,3.00 Table: Number of Cases in each Cluster +,,Count Cluster,1,0 ,2,0 ,3,0 @@ -228,8 +226,8 @@ QUICK CLUSTER x y AT_CHECK([pspp -O format=csv quick-pw.sps > pspp-pw.csv]) -AT_CHECK([head -n 18 pspp-s.csv > top-s.csv]) -AT_CHECK([head -n 18 pspp-pw.csv > top-pw.csv]) +AT_CHECK([head -n 13 pspp-s.csv > top-s.csv]) +AT_CHECK([head -n 13 pspp-pw.csv > top-pw.csv]) AT_CHECK([diff top-s.csv top-pw.csv]) @@ -280,7 +278,7 @@ AT_CLEANUP AT_SETUP([QUICK CLUSTER /PRINT subcommand]) AT_DATA([quick-cluster.sps], [dnl -data list notable list /cluster (A8) x (F) y (F). +data list notable list /cluster (A8) x y (F8.0). begin data. A 10.45 9.38 A 10.67 9.17 @@ -349,21 +347,18 @@ QUICK CLUSTER x y AT_CHECK([pspp -O format=csv quick-cluster.sps], [0], [dnl Table: Initial Cluster Centers ,Cluster,, -,,, ,1,2,3 -,,, x,-11,-12,11 y,-12,11,11 Table: Final Cluster Centers ,Cluster,, -,,, ,1,2,3 -,,, x,-10,-10,10 y,-10,10,10 Table: Number of Cases in each Cluster +,,Count Cluster,1,20 ,2,19 ,3,18 diff --git a/tests/language/stats/rank.at b/tests/language/stats/rank.at index 40c69d0f97..2194da5f86 100644 --- a/tests/language/stats/rank.at +++ b/tests/language/stats/rank.at @@ -35,11 +35,9 @@ LIST. ]) AT_CHECK([pspp -o pspp.csv rank.sps]) AT_CHECK([cat pspp.csv], [0], [dnl -Variables Created By RANK - - - -x into Rx(RANK of x) +Table: Variables Created by RANK +Existing Variable,New Variable,Function +x,Rx,RANK Table: Data List x,Rx @@ -70,15 +68,11 @@ LIST. ]) AT_CHECK([pspp -o pspp.csv rank.sps]) AT_CHECK([cat pspp.csv], [0], [dnl -Variables Created By RANK - - - -x into Rx(RANK of x) - -y into Ry(RANK of y) - -z into Rz(RANK of z) +Table: Variables Created by RANK +Existing Variable,New Variable,Function +x,Rx,RANK +y,Ry,RANK +z,Rz,RANK Table: Data List x,y,z,Rx,Ry,Rz @@ -117,21 +111,14 @@ LIST. ]) AT_CHECK([pspp -o pspp.csv rank.sps]) AT_CHECK([cat pspp.csv], [0], [dnl -Variables Created By RANK - - - -a into Ra(RANK of a) - -b into Rb(RANK of b) - -a into RFR001(RFRACTION of a) - -b into RFR002(RFRACTION of b) - -a into count(N of a) - -b into Nb(N of b) +Table: Variables Created by RANK +Existing Variable,New Variable,Function +a,Ra,RANK +b,Rb,RANK +a,RFR001,RFRACTION +b,RFR002,RFRACTION +a,count,N +b,Nb,N Table: Variables Name,Position,Label,Measurement Level,Role,Width,Alignment,Print Format,Write Format,Missing Values @@ -189,19 +176,13 @@ LIST. ]) AT_CHECK([pspp -o pspp.csv rank.sps]) AT_CHECK([cat pspp.csv], [0], [dnl -Variables Created By RANK - - - -a into Sa(SAVAGE of a) - -a into Pa(PERCENT of a) - -a into PRO001(PROPORTION of a using BLOM) - -a into Na(NTILES of a) - -a into NOR001(NORMAL of a using BLOM) +Table: Variables Created by RANK +Existing Variable,New Variable,Function,Fraction +a,Sa,SAVAGE, +a,Pa,PERCENT, +a,PRO001,PROPORTION,BLOM +a,Na,NTILES, +a,NOR001,NORMAL,BLOM Table: Data List a,b,Sa,Pa,PRO001,Na,NOR001 @@ -268,21 +249,15 @@ LIST. ]) AT_CHECK([pspp -o pspp.csv rank.sps]) AT_CHECK([cat pspp.csv], [0], [dnl -Variables Created By RANK - - - -a into Ra(RANK of a BY g2 g1) - -a into Na(NORMAL of a using RANKIT BY g2 g1) - -Variables Created By RANK - - - -a into RAN001(RANK of a BY g2) +Table: Variables Created by RANK +Existing Variable,New Variable,Function,Fraction,Grouping Variables +a,Ra,RANK,,g2 g1 +a,Na,NORMAL,RANKIT,g2 g1 -a into NOR001(NORMAL of a using RANKIT BY g2) +Table: Variables Created by RANK +Existing Variable,New Variable,Function,Fraction,Grouping Variables +a,RAN001,RANK,,g2 +a,NOR001,NORMAL,RANKIT,g2 Table: Data List a,g1,g2,Ra,Na,RAN001,NOR001 @@ -334,13 +309,10 @@ LIST. ]) AT_CHECK([pspp -o pspp.csv rank.sps]) AT_CHECK([cat pspp.csv], [0], [dnl -Variables Created By RANK - - - -a into Pa(PROPORTION of a using TUKEY) - -a into Sa(SAVAGE of a) +Table: Variables Created by RANK +Existing Variable,New Variable,Function,Fraction +a,Pa,PROPORTION,TUKEY +a,Sa,SAVAGE, Table: Data List a,w,Pa,Sa @@ -395,29 +367,21 @@ LIST. ]) AT_CHECK([pspp -o pspp.csv rank.sps]) AT_CHECK([cat pspp.csv], [0], [dnl -Variables Created By RANK - - - -x into xl(RANK of x) - -Variables Created By RANK - - - -x into xh(RANK of x) - -Variables Created By RANK - - - -x into xc(RANK of x) - -Variables Created By RANK +Table: Variables Created by RANK +Existing Variable,New Variable,Function +x,xl,RANK +Table: Variables Created by RANK +Existing Variable,New Variable,Function +x,xh,RANK +Table: Variables Created by RANK +Existing Variable,New Variable,Function +x,xc,RANK -x into Nx(NORMAL of x using VW) +Table: Variables Created by RANK +Existing Variable,New Variable,Function,Fraction +x,Nx,NORMAL,VW Table: Data List x,w,xl,xh,xc,Nx @@ -460,17 +424,13 @@ RANK age /RANK INTO Rf. LIST. ]) AT_CHECK([pspp -O format=csv rank.sps], [0], [dnl -Variables Created By RANK +Table: Variables Created by RANK +Existing Variable,New Variable,Function +age,Rm,RANK - - -age into Rm(RANK of age) - -Variables Created By RANK - - - -age into Rf(RANK of age) +Table: Variables Created by RANK +Existing Variable,New Variable,Function +age,Rf,RANK Table: Data List age,gender,Rm,Rf @@ -511,11 +471,9 @@ DISPLAY DICTIONARY. ]) AT_CHECK([pspp -o pspp.csv rank.sps]) AT_CHECK([cat pspp.csv], [0], [dnl -Variables Created By RANK - - - -foo into RAN001(RANK of foo) +Table: Variables Created by RANK +Existing Variable,New Variable,Function +foo,RAN001,RANK Table: Variables Name,Position,Label,Measurement Level,Role,Width,Alignment,Print Format,Write Format,Missing Values @@ -560,11 +518,9 @@ AT_CHECK([pspp -O format=csv rank.sps], [0], [dnl "rank.sps:9: warning: Missing value(s) for all variables from rx onward. These will be filled with the system-missing value or blanks, as appropriate." -Variables Created By RANK - - - -x into RNKRA01(RANK of x) +Table: Variables Created by RANK +Existing Variable,New Variable,Function +x,RNKRA01,RANK Table: Data List x,rx,RNKRA01 @@ -597,11 +553,9 @@ DEBUG XFORM FAIL. RANK x. ]) AT_CHECK([pspp -O format=csv --testing-mode rank.sps], [1], [dnl -Variables Created By RANK - - - -x into Rx(RANK of x) +Table: Variables Created by RANK +Existing Variable,New Variable,Function +x,Rx,RANK rank.sps:14: error: RANK: DEBUG XFORM FAIL transformation executed ]) diff --git a/tests/language/stats/regression.at b/tests/language/stats/regression.at index 7461a45a03..1fc5662da0 100644 --- a/tests/language/stats/regression.at +++ b/tests/language/stats/regression.at @@ -41,21 +41,21 @@ AT_CHECK([pspp -O format=csv regression.sps], [0], [dnl regression.sps:16: warning: REGRESSION: REGRESSION with SAVE ignores FILTER. All cases will be processed. Table: Model Summary (v2) -,R,R Square,Adjusted R Square,Std. Error of the Estimate -,.971,.942,.925,1.337 +R,R Square,Adjusted R Square,Std. Error of the Estimate +.971,.942,.925,1.337 Table: ANOVA (v2) -,,Sum of Squares,df,Mean Square,F,Sig. -,Regression,202.753,2,101.376,56.754,.000 -,Residual,12.504,7,1.786,, -,Total,215.256,9,,, +,Sum of Squares,df,Mean Square,F,Sig. +Regression,202.753,2,101.376,56.754,.000 +Residual,12.504,7,1.786,, +Total,215.256,9,,, Table: Coefficients (v2) -,,Unstandardized Coefficients,,Standardized Coefficients,, -,,B,Std. Error,Beta,t,Sig. -,(Constant),2.191,2.357,.000,.930,.380 -,v0,1.813,1.053,.171,1.722,.129 -,v1,-3.427,.332,-1.026,-10.334,.000 +,Unstandardized Coefficients,,Standardized Coefficients,t,Sig. +,B,Std. Error,Beta,, +(Constant),2.191,2.357,.000,.930,.380 +v0,1.813,1.053,.171,1.722,.129 +v1,-3.427,.332,-1.026,-10.334,.000 Table: Data List v0,v1,v2,RES1,PRED1 @@ -96,38 +96,38 @@ list. AT_CHECK([pspp -O format=csv regression.sps], [0], [dnl Table: Model Summary (v2) -,R,R Square,Adjusted R Square,Std. Error of the Estimate -,.971,.942,.925,1.337 +R,R Square,Adjusted R Square,Std. Error of the Estimate +.971,.942,.925,1.337 Table: ANOVA (v2) -,,Sum of Squares,df,Mean Square,F,Sig. -,Regression,202.753,2,101.376,56.754,.000 -,Residual,12.504,7,1.786,, -,Total,215.256,9,,, +,Sum of Squares,df,Mean Square,F,Sig. +Regression,202.753,2,101.376,56.754,.000 +Residual,12.504,7,1.786,, +Total,215.256,9,,, Table: Coefficients (v2) -,,Unstandardized Coefficients,,Standardized Coefficients,, -,,B,Std. Error,Beta,t,Sig. -,(Constant),2.191,2.357,.000,.930,.380 -,v0,1.813,1.053,.171,1.722,.129 -,v1,-3.427,.332,-1.026,-10.334,.000 +,Unstandardized Coefficients,,Standardized Coefficients,t,Sig. +,B,Std. Error,Beta,, +(Constant),2.191,2.357,.000,.930,.380 +v0,1.813,1.053,.171,1.722,.129 +v1,-3.427,.332,-1.026,-10.334,.000 Table: Model Summary (v2) -,R,R Square,Adjusted R Square,Std. Error of the Estimate -,.971,.942,.925,1.337 +R,R Square,Adjusted R Square,Std. Error of the Estimate +.971,.942,.925,1.337 Table: ANOVA (v2) -,,Sum of Squares,df,Mean Square,F,Sig. -,Regression,202.753,2,101.376,56.754,.000 -,Residual,12.504,7,1.786,, -,Total,215.256,9,,, +,Sum of Squares,df,Mean Square,F,Sig. +Regression,202.753,2,101.376,56.754,.000 +Residual,12.504,7,1.786,, +Total,215.256,9,,, Table: Coefficients (v2) -,,Unstandardized Coefficients,,Standardized Coefficients,, -,,B,Std. Error,Beta,t,Sig. -,(Constant),2.191,2.357,.000,.930,.380 -,v0,1.813,1.053,.171,1.722,.129 -,v1,-3.427,.332,-1.026,-10.334,.000 +,Unstandardized Coefficients,,Standardized Coefficients,t,Sig. +,B,Std. Error,Beta,, +(Constant),2.191,2.357,.000,.930,.380 +v0,1.813,1.053,.171,1.722,.129 +v1,-3.427,.332,-1.026,-10.334,.000 Table: Data List v0,v1,v2,RES1,PRED1 @@ -1786,20 +1786,20 @@ v0,F8.0 v1,F8.0 Table: Model Summary (v0) -,R,R Square,Adjusted R Square,Std. Error of the Estimate -,.05,.00,.00,8.11 +R,R Square,Adjusted R Square,Std. Error of the Estimate +.05,.00,.00,8.11 Table: ANOVA (v0) -,,Sum of Squares,df,Mean Square,F,Sig. -,Regression,235.23,1,235.23,3.58,.059 -,Residual,98438.40,1498,65.71,, -,Total,98673.63,1499,,, +,Sum of Squares,df,Mean Square,F,Sig. +Regression,235.23,1,235.23,3.58,.059 +Residual,98438.40,1498,65.71,, +Total,98673.63,1499,,, Table: Coefficients (v0) -,,Unstandardized Coefficients,,Standardized Coefficients,, -,,B,Std. Error,Beta,t,Sig. -,(Constant),1.24,.42,.00,2.95,.003 -,v1,1.37,.72,.05,1.89,.059 +,Unstandardized Coefficients,,Standardized Coefficients,t,Sig. +,B,Std. Error,Beta,, +(Constant),1.24,.42,.00,2.95,.003 +v1,1.37,.72,.05,1.89,.059 ]) AT_CLEANUP @@ -2125,23 +2125,23 @@ regression AT_CHECK([pspp -O format=csv conf.sps], [0], [dnl Table: Model Summary (science) -,R,R Square,Adjusted R Square,Std. Error of the Estimate -,.699,.489,.479,7.148 +R,R Square,Adjusted R Square,Std. Error of the Estimate +.699,.489,.479,7.148 Table: ANOVA (science) -,,Sum of Squares,df,Mean Square,F,Sig. -,Regression,9543.721,4,2385.930,46.695,.000 -,Residual,9963.779,195,51.096,, -,Total,19507.500,199,,, +,Sum of Squares,df,Mean Square,F,Sig. +Regression,9543.721,4,2385.930,46.695,.000 +Residual,9963.779,195,51.096,, +Total,19507.500,199,,, Table: Coefficients (science) -,,Unstandardized Coefficients,,Standardized Coefficients,,,95% Confidence Interval for B, -,,B,Std. Error,Beta,t,Sig.,Lower Bound,Upper Bound -,(Constant),12.325,3.194,.000,3.859,.000,6.027,18.624 -,math,.389,.074,.368,5.252,.000,.243,.535 -,female,-2.010,1.023,-.101,-1.965,.051,-4.027,.007 -,socst,.050,.062,.054,.801,.424,-.073,.173 -,read,.335,.073,.347,4.607,.000,.192,.479 +,Unstandardized Coefficients,,Standardized Coefficients,t,Sig.,95% Confidence Interval for B, +,B,Std. Error,Beta,,,Lower Bound,Upper Bound +(Constant),12.325,3.194,.000,3.859,.000,6.027,18.624 +math,.389,.074,.368,5.252,.000,.243,.535 +female,-2.010,1.023,-.101,-1.965,.051,-4.027,.007 +socst,.050,.062,.054,.801,.424,-.073,.173 +read,.335,.073,.347,4.607,.000,.192,.479 ]) @@ -2173,27 +2173,27 @@ LIST. AT_CHECK([pspp -o pspp.csv regression.sps]) AT_CHECK([cat pspp.csv], [0], [dnl Table: Model Summary (X1) -,R,R Square,Adjusted R Square,Std. Error of the Estimate -,.95,.89,.84,15.08 +R,R Square,Adjusted R Square,Std. Error of the Estimate +.95,.89,.84,15.08 Table: ANOVA (X1) -,,Sum of Squares,df,Mean Square,F,Sig. -,Regression,3820.45,1,3820.45,16.81,.055 -,Residual,454.55,2,227.27,, -,Total,4275.00,3,,, +,Sum of Squares,df,Mean Square,F,Sig. +Regression,3820.45,1,3820.45,16.81,.055 +Residual,454.55,2,227.27,, +Total,4275.00,3,,, Table: Coefficients (X1) -,,Unstandardized Coefficients,,Standardized Coefficients,, -,,B,Std. Error,Beta,t,Sig. -,(Constant),85.45,10.16,.00,8.41,.004 -,Y,-3.73,.91,-.95,-4.10,.055 +,Unstandardized Coefficients,,Standardized Coefficients,t,Sig. +,B,Std. Error,Beta,, +(Constant),85.45,10.16,.00,8.41,.004 +Y,-3.73,.91,-.95,-4.10,.055 Table: Data List text,Y,X1,RES1 -V00276601 ,.00,90.00,4.55 -V00292909 ,10.00,30.00,-18.18 -V00291204 ,20.00,20.00,9.09 -V00300070 ,.00,90.00,4.55 +V00276601,.00,90.00,4.55 +V00292909,10.00,30.00,-18.18 +V00291204,20.00,20.00,9.09 +V00300070,.00,90.00,4.55 ]) AT_CLEANUP @@ -2260,20 +2260,20 @@ REGRESSION AT_CHECK([pspp -O format=csv regression.sps], [0], [dnl Table: Model Summary (value) -,R,R Square,Adjusted R Square,Std. Error of the Estimate -,.612,.374,.338,6.176 +R,R Square,Adjusted R Square,Std. Error of the Estimate +.612,.374,.338,6.176 Table: ANOVA (value) -,,Sum of Squares,df,Mean Square,F,Sig. -,Regression,388.065,1,388.065,10.173,.005 -,Residual,648.498,17,38.147,, -,Total,1036.563,18,,, +,Sum of Squares,df,Mean Square,F,Sig. +Regression,388.065,1,388.065,10.173,.005 +Residual,648.498,17,38.147,, +Total,1036.563,18,,, Table: Coefficients (value) -,,Unstandardized Coefficients,,Standardized Coefficients,, -,,B,Std. Error,Beta,t,Sig. -,(Constant),.927,2.247,.000,.413,.685 -,number,.611,.192,.612,3.189,.005 +,Unstandardized Coefficients,,Standardized Coefficients,t,Sig. +,B,Std. Error,Beta,, +(Constant),.927,2.247,.000,.413,.685 +number,.611,.192,.612,3.189,.005 ]) AT_CLEANUP @@ -2317,20 +2317,66 @@ REGRESSION AT_CHECK([pspp -O format=csv regression-origin.sps], [0], [dnl Table: Model Summary (value) -,R,R Square,Adjusted R Square,Std. Error of the Estimate -,.802,.643,.622,6.032 +R,R Square,Adjusted R Square,Std. Error of the Estimate +.802,.643,.622,6.032 Table: ANOVA (value) -,,Sum of Squares,df,Mean Square,F,Sig. -,Regression,1181.726,1,1181.726,32.475,.000 -,Residual,654.989,18,36.388,, -,Total,1836.715,19,,, +,Sum of Squares,df,Mean Square,F,Sig. +Regression,1181.726,1,1181.726,32.475,.000 +Residual,654.989,18,36.388,, +Total,1836.715,19,,, Table: Coefficients (value) -,,Unstandardized Coefficients,,Standardized Coefficients,, -,,B,Std. Error,Beta,t,Sig. -,number,.672,.118,.802,5.699,.000 -,,,,,, +,Unstandardized Coefficients,,Standardized Coefficients,t,Sig. +,B,Std. Error,Beta,, +number,.672,.118,.802,5.699,.000 ]) AT_CLEANUP + +dnl This is an example from doc/tutorial.texi +dnl So if the results of this have to be changed in any way, +dnl make sure to update that file. +AT_SETUP([REGRESSION tutorial example]) +cp $top_srcdir/examples/repairs.sav . +AT_DATA([regression.sps], [dnl +GET FILE='repairs.sav'. +REGRESSION /VARIABLES=mtbf duty_cycle /DEPENDENT=mttr. +REGRESSION /VARIABLES=mtbf /DEPENDENT=mttr. +]) +AT_CHECK([pspp -o pspp.csv -o pspp.txt regression.sps]) +AT_CHECK([cat pspp.csv], [0], [dnl +Table: Model Summary (Mean time to repair (hours) ) +R,R Square,Adjusted R Square,Std. Error of the Estimate +.99,.99,.99,2.24 + +Table: ANOVA (Mean time to repair (hours) ) +,Sum of Squares,df,Mean Square,F,Sig. +Regression,5308.87,2,2654.44,530.75,.000 +Residual,60.02,12,5.00,, +Total,5368.89,14,,, + +Table: Coefficients (Mean time to repair (hours) ) +,Unstandardized Coefficients,,Standardized Coefficients,t,Sig. +,B,Std. Error,Beta,, +(Constant),9.81,1.50,.00,6.54,.000 +Mean time between failures (months) ,3.10,.10,.99,32.43,.000 +Ratio of working to non-working time,1.09,1.78,.02,.61,.552 + +Table: Model Summary (Mean time to repair (hours) ) +R,R Square,Adjusted R Square,Std. Error of the Estimate +.99,.99,.99,2.18 + +Table: ANOVA (Mean time to repair (hours) ) +,Sum of Squares,df,Mean Square,F,Sig. +Regression,5307.00,1,5307.00,1114.73,.000 +Residual,61.89,13,4.76,, +Total,5368.89,14,,, + +Table: Coefficients (Mean time to repair (hours) ) +,Unstandardized Coefficients,,Standardized Coefficients,t,Sig. +,B,Std. Error,Beta,, +(Constant),10.50,.96,.00,10.96,.000 +Mean time between failures (months) ,3.11,.09,.99,33.39,.000 +]) +AT_CLEANUP diff --git a/tests/language/stats/reliability.at b/tests/language/stats/reliability.at index be20341581..072a48aca2 100644 --- a/tests/language/stats/reliability.at +++ b/tests/language/stats/reliability.at @@ -199,17 +199,17 @@ RELIABILITY /VARIABLES=var6 var8 var15 var17 . ]) -AT_CHECK([pspp -o pspp.csv reliability.sps], [0], +AT_CHECK([pspp -o pspp.csv -o pspp.txt reliability.sps], [0], [reliability.sps:174: warning: RELIABILITY: The STATISTICS subcommand is not yet implemented. No statistics will be produced. ]) AT_CHECK([cat pspp.csv], [0], [dnl Scale: Everything Table: Case Processing Summary -,,N,% -Cases,Valid,131,92.91 -,Excluded,10,7.09 -,Total,141,100.00 +Cases,N,Percent +Valid,131,92.9% +Excluded,10,7.1% +Total,141,100.0% Table: Reliability Statistics Cronbach's Alpha,N of Items @@ -218,10 +218,10 @@ Cronbach's Alpha,N of Items Scale: Nothing Table: Case Processing Summary -,,N,% -Cases,Valid,131,92.91 -,Excluded,10,7.09 -,Total,141,100.00 +Cases,N,Percent +Valid,131,92.9% +Excluded,10,7.1% +Total,141,100.0% Table: Reliability Statistics Cronbach's Alpha,Part 1,Value,.55 @@ -239,10 +239,10 @@ reliability.sps:174: warning: RELIABILITY: The STATISTICS subcommand is not yet Scale: Totals Table: Case Processing Summary -,,N,% -Cases,Valid,131,92.91 -,Excluded,10,7.09 -,Total,141,100.00 +Cases,N,Percent +Valid,131,92.9% +Excluded,10,7.1% +Total,141,100.0% Table: Reliability Statistics Cronbach's Alpha,N of Items @@ -258,10 +258,10 @@ var17,16.60,8.00,.57,.67 Scale: ANY Table: Case Processing Summary -,,N,% -Cases,Valid,131,92.91 -,Excluded,10,7.09 -,Total,141,100.00 +Cases,N,Percent +Valid,131,92.9% +Excluded,10,7.1% +Total,141,100.0% Table: Reliability Statistics Cronbach's Alpha,N of Items @@ -335,18 +335,18 @@ reliability variables = v1 v3 v4. ]) AT_CHECK([ln -s $top_srcdir/examples/hotel.sav .], [0]) -AT_CHECK([pspp -O format=csv tut-example.sps], [0], [dnl +AT_CHECK([pspp -o pspp.csv -o pspp.txt tut-example.sps]) +AT_CHECK([cat pspp.csv], [0], [dnl Scale: ANY Table: Case Processing Summary -,,N,% -Cases,Valid,17,100.00 -,Excluded,0,.00 -,Total,17,100.00 +Cases,N,Percent +Valid,17,100.0% +Excluded,0,.0% +Total,17,100.0% Table: Reliability Statistics Cronbach's Alpha,N of Items .81,3 ]) - AT_CLEANUP diff --git a/tests/language/stats/roc.at b/tests/language/stats/roc.at index c1fa369b44..5725557c23 100644 --- a/tests/language/stats/roc.at +++ b/tests/language/stats/roc.at @@ -51,19 +51,19 @@ a,Unweighted,Weighted Positive,5,50.000 Negative,5,50.000 -Table: Area Under the Curve (x) -,,,Asymp. 99% Confidence Interval, -Area,Std. Error,Asymptotic Sig.,Lower Bound,Upper Bound -.910,.030,.000,.839,.981 - -Table: Coordinates of the Curve (x) -Positive if greater than or equal to,Sensitivity,1 - Specificity -.000,1.000,1.000 -1.500,.960,.440 -2.500,.880,.160 -3.500,.680,.060 -4.500,.400,.020 -6.000,.000,.000 +Table: Area Under the Curve +,Area,Std. Error,Asymptotic Sig.,Asymp. 99% Confidence Interval, +Variable under test,,,,Lower Bound,Upper Bound +x,.910,.030,.000,.839,.981 + +Table: Coordinates of the Curve +Test variable,Positive if greater than or equal to,Sensitivity,1 - Specificity +x,.000,1.000,1.000 +,1.500,.960,.440 +,2.500,.880,.160 +,3.500,.680,.060 +,4.500,.400,.020 +,6.000,.000,.000 ]) AT_CLEANUP @@ -103,8 +103,8 @@ Positive,5,50.000 Negative,5,50.000 Table: Area Under the Curve -,,,,Asymp. 95% Confidence Interval, -Variable under test,Area,Std. Error,Asymptotic Sig.,Lower Bound,Upper Bound +,Area,Std. Error,Asymptotic Sig.,Asymp. 95% Confidence Interval, +Variable under test,,,,Lower Bound,Upper Bound x,.910,.030,.000,.860,.960 y,.697,.052,.001,.611,.783 @@ -166,7 +166,7 @@ roc x by a (1) print = se . ]) -AT_CHECK([pspp -o pspp.csv roc.sps]) +AT_CHECK([pspp -o pspp.csv -o pspp.txt roc.sps]) AT_CHECK([cat pspp.csv], [0], [dnl Table: Case Summary ,Valid N (listwise), @@ -174,10 +174,10 @@ a,Unweighted,Weighted Positive,14,14.000 Negative,14,14.000 -Table: Area Under the Curve (x) -,,,Asymp. 95% Confidence Interval, -Area,Std. Error,Asymptotic Sig.,Lower Bound,Upper Bound -.490,.111,.927,.307,.673 +Table: Area Under the Curve +,Area,Std. Error,Asymptotic Sig.,Asymp. 95% Confidence Interval, +Variable under test,,,,Lower Bound,Upper Bound +x,.490,.111,.927,.307,.673 ]) AT_CLEANUP diff --git a/tests/language/stats/t-test.at b/tests/language/stats/t-test.at index 46492319cf..8cd4e6cb55 100644 --- a/tests/language/stats/t-test.at +++ b/tests/language/stats/t-test.at @@ -30,7 +30,8 @@ end data. t-test /PAIRS a with b (PAIRED). ]) -AT_CHECK([pspp -O format=csv t-test.sps], [0], [dnl +AT_CHECK([pspp -o pspp.csv -o pspp.txt t-test.sps]) +AT_CHECK([cat pspp.csv], [0], [dnl Table: Reading free-form data from INLINE. Variable,Format ID,F8.0 @@ -38,21 +39,20 @@ A,F8.0 B,F8.0 Table: Paired Sample Statistics -,,Mean,N,Std. Deviation,S.E. Mean -Pair 1,A,2.00,5,.71,.32 -,B,4.00,5,1.54,.69 +,,N,Mean,Std. Deviation,S.E. Mean +Pair 1,A,5,2.00,.71,.32 +,B,5,4.00,1.54,.69 Table: Paired Samples Correlations ,,N,Correlation,Sig. -Pair 1,A & B,5,.92,.028 +Pair 1,A & B,5,.918,.028 Table: Paired Samples Test -,,Paired Differences,,,,,,, -,,,,,95% Confidence Interval of the Difference,,,, -,,Mean,Std. Deviation,Std. Error Mean,Lower,Upper,t,df,Sig. (2-tailed) +,,Paired Differences,,,,,t,df,Sig. (2-tailed) +,,Mean,Std. Deviation,S.E. Mean,95% Confidence Interval of the Difference,,,, +,,,,,Lower,Upper,,, Pair 1,A - B,-2.00,.94,.42,-3.16,-.84,-4.78,4,.009 ]) - AT_CLEANUP @@ -81,21 +81,21 @@ c,F8.0 d,F8.0 Table: Paired Sample Statistics -,,Mean,N,Std. Deviation,S.E. Mean -Pair 1,a,2.00,5,.71,.32 -,b,4.00,5,1.54,.69 -Pair 2,c,5.10,5,.69,.31 -,d,3.80,5,.16,.07 +,,N,Mean,Std. Deviation,S.E. Mean +Pair 1,a,5,2.00,.71,.32 +,b,5,4.00,1.54,.69 +Pair 2,c,5,5.10,.69,.31 +,d,5,3.80,.16,.07 Table: Paired Samples Correlations ,,N,Correlation,Sig. -Pair 1,a & b,5,.92,.028 -Pair 2,c & d,5,-.92,.028 +Pair 1,a & b,5,.918,.028 +Pair 2,c & d,5,-.918,.028 Table: Paired Samples Test -,,Paired Differences,,,,,,, -,,,,,95% Confidence Interval of the Difference,,,, -,,Mean,Std. Deviation,Std. Error Mean,Lower,Upper,t,df,Sig. (2-tailed) +,,Paired Differences,,,,,t,df,Sig. (2-tailed) +,,Mean,Std. Deviation,S.E. Mean,95% Confidence Interval of the Difference,,,, +,,,,,Lower,Upper,,, Pair 1,a - b,-2.00,.94,.42,-3.16,-.84,-4.78,4,.009 Pair 2,c - d,1.30,.84,.37,.26,2.34,3.47,4,.025 ]) @@ -145,21 +145,21 @@ c,F8.0 d,F8.0 Table: Paired Sample Statistics -,,Mean,N,Std. Deviation,S.E. Mean -Pair 1,a,2.00,5,.71,.32 -,c,5.10,5,.69,.31 -Pair 2,b,4.00,5,1.54,.69 -,d,3.80,5,.16,.07 +,,N,Mean,Std. Deviation,S.E. Mean +Pair 1,a,5,2.00,.71,.32 +,c,5,5.10,.69,.31 +Pair 2,b,5,4.00,1.54,.69 +,d,5,3.80,.16,.07 Table: Paired Samples Correlations ,,N,Correlation,Sig. -Pair 1,a & c,5,.41,.493 -Pair 2,b & d,5,-.87,.054 +Pair 1,a & c,5,.410,.493 +Pair 2,b & d,5,-.872,.054 Table: Paired Samples Test -,,Paired Differences,,,,,,, -,,,,,95% Confidence Interval of the Difference,,,, -,,Mean,Std. Deviation,Std. Error Mean,Lower,Upper,t,df,Sig. (2-tailed) +,,Paired Differences,,,,,t,df,Sig. (2-tailed) +,,Mean,Std. Deviation,S.E. Mean,95% Confidence Interval of the Difference,,,, +,,,,,Lower,Upper,,, Pair 1,a - c,-3.10,.76,.34,-4.04,-2.16,-9.14,4,.001 Pair 2,b - d,.20,1.68,.75,-1.89,2.29,.27,4,.803 ]) @@ -209,23 +209,23 @@ T-TEST /CRITERIA=CI(0.95). ]) -AT_CHECK([pspp -O format=csv t-test.sps], [0], [dnl +AT_CHECK([pspp -o pspp.csv -o pspp.txt t-test.sps]) +AT_CHECK([cat pspp.csv], [0], [dnl Table: Paired Sample Statistics -,,Mean,N,Std. Deviation,S.E. Mean -Pair 1,y,1.94,530.00,.96,.04 -,x,1.03,530.00,.17,.01 +,,N,Mean,Std. Deviation,S.E. Mean +Pair 1,y,530.00,1.94,.96,.04 +,x,530.00,1.03,.17,.01 Table: Paired Samples Correlations ,,N,Correlation,Sig. -Pair 1,y & x,530.00,.11,.008 +Pair 1,y & x,530.00,.114,.008 Table: Paired Samples Test -,,Paired Differences,,,,,,, -,,,,,95% Confidence Interval of the Difference,,,, -,,Mean,Std. Deviation,Std. Error Mean,Lower,Upper,t,df,Sig. (2-tailed) +,,Paired Differences,,,,,t,df,Sig. (2-tailed) +,,Mean,Std. Deviation,S.E. Mean,95% Confidence Interval of the Difference,,,, +,,,,,Lower,Upper,,, Pair 1,y - x,.91,.95,.04,.83,.99,22.07,529.00,.000 ]) - AT_CLEANUP @@ -251,18 +251,18 @@ A,F8.0 B,F8.0 Table: Paired Sample Statistics -,,Mean,N,Std. Deviation,S.E. Mean -Pair 1,A,4.333,3,5.774,3.333 -,B,1.333,3,.577,.333 +,,N,Mean,Std. Deviation,S.E. Mean +Pair 1,A,3,4.333,5.774,3.333 +,B,3,1.333,.577,.333 Table: Paired Samples Correlations ,,N,Correlation,Sig. Pair 1,A & B,3,1.000,.000 Table: Paired Samples Test -,,Paired Differences,,,,,,, -,,,,,95% Confidence Interval of the Difference,,,, -,,Mean,Std. Deviation,Std. Error Mean,Lower,Upper,t,df,Sig. (2-tailed) +,,Paired Differences,,,,,t,df,Sig. (2-tailed) +,,Mean,Std. Deviation,S.E. Mean,95% Confidence Interval of the Difference,,,, +,,,,,Lower,Upper,,, Pair 1,A - B,3.000,5.196,3.000,-9.908,15.908,1.000,2,.423 ]) AT_CLEANUP @@ -290,7 +290,8 @@ end data. t-test /GROUPS=indep(1.1,2.1) /var=dep1 dep2. ]) -AT_CHECK([pspp -O format=csv t-test.sps], [0], [dnl +AT_CHECK([pspp -o pspp.csv -o pspp.txt t-test.sps]) +AT_CHECK([cat pspp.csv], [0], [dnl Table: Reading free-form data from INLINE. Variable,Format ID,F8.0 @@ -299,22 +300,21 @@ DEP1,F8.0 DEP2,F8.0 Table: Group Statistics -,INDEP,N,Mean,Std. Deviation,S.E. Mean +,Group,N,Mean,Std. Deviation,S.E. Mean DEP1,1.10,5,2.00,.71,.32 ,2.10,5,4.00,.71,.32 DEP2,1.10,5,4.00,.71,.32 ,2.10,5,2.00,.71,.32 Table: Independent Samples Test -,,Levene's Test for Equality of Variances,,t-test for Equality of Means,,,,,, -,,,,,,,,,95% Confidence Interval of the Difference, -,,F,Sig.,t,df,Sig. (2-tailed),Mean Difference,Std. Error Difference,Lower,Upper +,,Levene's Test for Equality of Variances,,T-Test for Equality of Means,,,,,, +,,F,Sig.,t,df,Sig. (2-tailed),Mean Difference,Std. Error Difference,95% Confidence Interval of the Difference, +,,,,,,,,,Lower,Upper DEP1,Equal variances assumed,.00,1.000,-4.47,8.00,.002,-2.00,.45,-3.03,-.97 ,Equal variances not assumed,,,-4.47,8.00,.002,-2.00,.45,-3.03,-.97 DEP2,Equal variances assumed,.00,1.000,4.47,8.00,.002,2.00,.45,.97,3.03 ,Equal variances not assumed,,,4.47,8.00,.002,2.00,.45,.97,3.03 ]) - AT_CLEANUP AT_SETUP([T-TEST /GROUPS with one value for independent variable]) @@ -347,21 +347,22 @@ end data. t-test /groups=indep(1.514) /var=dep. ]) -AT_CHECK([pspp -O format=csv t-test.sps], [0], [dnl +AT_CHECK([pspp -o pspp.csv -o pspp.txt t-test.sps]) +AT_CHECK([cat pspp.csv], [0], [dnl Table: Reading free-form data from INLINE. Variable,Format INDEP,F8.0 DEP,F8.0 Table: Group Statistics -,INDEP,N,Mean,Std. Deviation,S.E. Mean +,Group,N,Mean,Std. Deviation,S.E. Mean DEP,≥ 1.51,11,9.00,3.82,1.15 ,< 1.51,11,8.00,2.86,.86 Table: Independent Samples Test -,,Levene's Test for Equality of Variances,,t-test for Equality of Means,,,,,, -,,,,,,,,,95% Confidence Interval of the Difference, -,,F,Sig.,t,df,Sig. (2-tailed),Mean Difference,Std. Error Difference,Lower,Upper +,,Levene's Test for Equality of Variances,,T-Test for Equality of Means,,,,,, +,,F,Sig.,t,df,Sig. (2-tailed),Mean Difference,Std. Error Difference,95% Confidence Interval of the Difference, +,,,,,,,,,Lower,Upper DEP,Equal variances assumed,.17,.683,.69,20.00,.495,1.00,1.44,-2.00,4.00 ,Equal variances not assumed,,,.69,18.54,.496,1.00,1.44,-2.02,4.02 ]) @@ -389,16 +390,16 @@ dep1,F8.0 dep2,F8.0 Table: Group Statistics -,indep,N,Mean,Std. Deviation,S.E. Mean +,Group,N,Mean,Std. Deviation,S.E. Mean dep1,1.00,3,2.50,.87,.50 ,2.00,2,3.25,.35,.25 dep2,1.00,3,5.00,1.00,.58 ,2.00,2,2.00,1.41,1.00 Table: Independent Samples Test -,,Levene's Test for Equality of Variances,,t-test for Equality of Means,,,,,, -,,,,,,,,,95% Confidence Interval of the Difference, -,,F,Sig.,t,df,Sig. (2-tailed),Mean Difference,Std. Error Difference,Lower,Upper +,,Levene's Test for Equality of Variances,,T-Test for Equality of Means,,,,,, +,,F,Sig.,t,df,Sig. (2-tailed),Mean Difference,Std. Error Difference,95% Confidence Interval of the Difference, +,,,,,,,,,Lower,Upper dep1,Equal variances assumed,3.75,.148,-1.12,3.00,.346,-.75,.67,-2.89,1.39 ,Equal variances not assumed,,,-1.34,2.78,.279,-.75,.56,-2.61,1.11 dep2,Equal variances assumed,.60,.495,2.85,3.00,.065,3.00,1.05,-.35,6.35 @@ -451,16 +452,16 @@ dep1,F8.0 dep2,F8.0 Table: Group Statistics -,indep,N,Mean,Std. Deviation,S.E. Mean +,Group,N,Mean,Std. Deviation,S.E. Mean dep1,1.00,3,2.50,.87,.50 ,2.00,3,3.50,.50,.29 dep2,1.00,3,5.00,1.00,.58 ,2.00,3,2.00,1.00,.58 Table: Independent Samples Test -,,Levene's Test for Equality of Variances,,t-test for Equality of Means,,,,,, -,,,,,,,,,95% Confidence Interval of the Difference, -,,F,Sig.,t,df,Sig. (2-tailed),Mean Difference,Std. Error Difference,Lower,Upper +,,Levene's Test for Equality of Variances,,T-Test for Equality of Means,,,,,, +,,F,Sig.,t,df,Sig. (2-tailed),Mean Difference,Std. Error Difference,95% Confidence Interval of the Difference, +,,,,,,,,,Lower,Upper dep1,Equal variances assumed,2.00,.230,-1.73,4.00,.158,-1.00,.58,-2.60,.60 ,Equal variances not assumed,,,-1.73,3.20,.176,-1.00,.58,-2.77,.77 dep2,Equal variances assumed,.00,1.000,3.67,4.00,.021,3.00,.82,.73,5.27 @@ -501,7 +502,8 @@ end data. t-test /testval=2.0 /var=abc. ]) -AT_CHECK([pspp -O format=csv t-test.sps], [0], [dnl +AT_CHECK([pspp -o pspp.csv -o pspp.txt t-test.sps]) +AT_CHECK([cat pspp.csv], [0], [dnl Table: Reading free-form data from INLINE. Variable,Format ID,F8.0 @@ -512,9 +514,9 @@ Table: One-Sample Statistics ABC,6,3.00,.84,.34 Table: One-Sample Test -,Test Value = 2.000000,,,,, -,,,,,95% Confidence Interval of the Difference, -,t,df,Sig. (2-tailed),Mean Difference,Lower,Upper +,Test Value = 2,,,,, +,t,df,Sig. (2-tailed),Mean Difference,95% Confidence Interval of the Difference, +,,,,,Lower,Upper ABC,2.93,5,.033,1.00,.12,1.88 ]) AT_CLEANUP @@ -546,9 +548,9 @@ x1,6,3.00,.84,.34 x2,6,32.67,33.40,13.64 Table: One-Sample Test -,Test Value = 3.000000,,,,, -,,,,,95% Confidence Interval of the Difference, -,t,df,Sig. (2-tailed),Mean Difference,Lower,Upper +,Test Value = 3,,,,, +,t,df,Sig. (2-tailed),Mean Difference,95% Confidence Interval of the Difference, +,,,,,Lower,Upper x1,.00,5,1.000,.00,-.88,.88 x2,2.18,5,.082,29.67,-5.39,64.72 ]) @@ -598,9 +600,9 @@ x1,5,2.80,.76,.34 x2,5,37.60,34.82,15.57 Table: One-Sample Test -,Test Value = 3.000000,,,,, -,,,,,95% Confidence Interval of the Difference, -,t,df,Sig. (2-tailed),Mean Difference,Lower,Upper +,Test Value = 3,,,,, +,t,df,Sig. (2-tailed),Mean Difference,95% Confidence Interval of the Difference, +,,,,,Lower,Upper x1,-.59,4,.587,-.20,-1.14,.74 x2,2.22,4,.090,34.60,-8.63,77.83 ]) @@ -646,14 +648,14 @@ ind,F8.0 x,F8.0 Table: Group Statistics -,ind,N,Mean,Std. Deviation,S.E. Mean +,Group,N,Mean,Std. Deviation,S.E. Mean x,1.00,3,2.50,.87,.50 ,2.00,3,3.50,.50,.29 Table: Independent Samples Test -,,Levene's Test for Equality of Variances,,t-test for Equality of Means,,,,,, -,,,,,,,,,95% Confidence Interval of the Difference, -,,F,Sig.,t,df,Sig. (2-tailed),Mean Difference,Std. Error Difference,Lower,Upper +,,Levene's Test for Equality of Variances,,T-Test for Equality of Means,,,,,, +,,F,Sig.,t,df,Sig. (2-tailed),Mean Difference,Std. Error Difference,95% Confidence Interval of the Difference, +,,,,,,,,,Lower,Upper x,Equal variances assumed,2.00,.230,-1.73,4.00,.158,-1.00,.58,-2.60,.60 ,Equal variances not assumed,,,-1.73,3.20,.176,-1.00,.58,-2.77,.77 ]) @@ -680,6 +682,36 @@ AT_CHECK([pspp -o temporary.csv temporary.sps]) AT_CHECK([cat temporary.csv], [0], [expout]) AT_CLEANUP +dnl This is an example from doc/tutorial.texi +dnl So if the results of this have to be changed in any way, +dnl make sure to update that file. +AT_SETUP([T-TEST tutorial example]) +cp $top_srcdir/examples/physiology.sav . +AT_DATA([t-test.sps], [dnl +GET FILE='physiology.sav'. +RECODE height (179 = SYSMIS). +T-TEST GROUP=sex(0,1) /VARIABLES=height temperature. +]) +AT_CHECK([pspp -o pspp.csv -o pspp.txt t-test.sps]) +AT_CHECK([cat pspp.csv], [0], [dnl +Table: Group Statistics +,Group,N,Mean,Std. Deviation,S.E. Mean +Height in millimeters ,Male,22,1796.49,49.71,10.60 +,Female,17,1610.77,25.43,6.17 +Internal body temperature in degrees Celcius,Male,22,36.68,1.95,.42 +,Female,18,37.43,1.61,.38 + +Table: Independent Samples Test +,,Levene's Test for Equality of Variances,,T-Test for Equality of Means,,,,,, +,,F,Sig.,t,df,Sig. (2-tailed),Mean Difference,Std. Error Difference,95% Confidence Interval of the Difference, +,,,,,,,,,Lower,Upper +Height in millimeters ,Equal variances assumed,.97,.331,14.02,37.00,.000,185.72,13.24,158.88,212.55 +,Equal variances not assumed,,,15.15,32.71,.000,185.72,12.26,160.76,210.67 +Internal body temperature in degrees Celcius,Equal variances assumed,.31,.581,-1.31,38.00,.198,-.75,.57,-1.91,.41 +,Equal variances not assumed,,,-1.33,37.99,.190,-.75,.56,-1.89,.39 +]) +AT_CLEANUP + dnl Tests for a bug which caused T-TEST to crash when given invalid syntax. AT_SETUP([T-TEST invalid syntax]) AT_DATA([t-test.sps], [dnl @@ -725,7 +757,8 @@ end data. t-test /GROUPS=indep('a','b') /var=dep1 dep2. ]) -AT_CHECK([pspp -O format=csv t-test.sps], [0], [dnl +AT_CHECK([pspp -o pspp.csv -o pspp.txt t-test.sps]) +AT_CHECK([cat pspp.csv], [0], [dnl Table: Reading free-form data from INLINE. Variable,Format ID,F8.0 @@ -734,16 +767,16 @@ DEP1,F8.0 DEP2,F8.0 Table: Group Statistics -,INDEP,N,Mean,Std. Deviation,S.E. Mean +,Group,N,Mean,Std. Deviation,S.E. Mean DEP1,a,5,2.00,.71,.32 ,b,5,4.00,.71,.32 DEP2,a,5,4.00,.71,.32 ,b,5,2.00,.71,.32 Table: Independent Samples Test -,,Levene's Test for Equality of Variances,,t-test for Equality of Means,,,,,, -,,,,,,,,,95% Confidence Interval of the Difference, -,,F,Sig.,t,df,Sig. (2-tailed),Mean Difference,Std. Error Difference,Lower,Upper +,,Levene's Test for Equality of Variances,,T-Test for Equality of Means,,,,,, +,,F,Sig.,t,df,Sig. (2-tailed),Mean Difference,Std. Error Difference,95% Confidence Interval of the Difference, +,,,,,,,,,Lower,Upper DEP1,Equal variances assumed,.00,1.000,-4.47,8.00,.002,-2.00,.45,-3.03,-.97 ,Equal variances not assumed,,,-4.47,8.00,.002,-2.00,.45,-3.03,-.97 DEP2,Equal variances assumed,.00,1.000,4.47,8.00,.002,2.00,.45,.97,3.03 @@ -795,21 +828,22 @@ t-test group=gv('One', 'Two') /variables = x. ]) -AT_CHECK([pspp -O format=csv t-test.sps], [0], [dnl +AT_CHECK([pspp -o pspp.csv -o pspp.txt t-test.sps]) +AT_CHECK([cat pspp.csv], [0], [dnl Table: Reading free-form data from INLINE. Variable,Format x,F8.0 gv,A8 Table: Group Statistics -,gv,N,Mean,Std. Deviation,S.E. Mean -x,One ,5,2.60,.55,.24 -,Two ,3,3.50,.50,.29 +,Group,N,Mean,Std. Deviation,S.E. Mean +x,One,5,2.60,.55,.24 +,Two,3,3.50,.50,.29 Table: Independent Samples Test -,,Levene's Test for Equality of Variances,,t-test for Equality of Means,,,,,, -,,,,,,,,,95% Confidence Interval of the Difference, -,,F,Sig.,t,df,Sig. (2-tailed),Mean Difference,Std. Error Difference,Lower,Upper +,,Levene's Test for Equality of Variances,,T-Test for Equality of Means,,,,,, +,,F,Sig.,t,df,Sig. (2-tailed),Mean Difference,Std. Error Difference,95% Confidence Interval of the Difference, +,,,,,,,,,Lower,Upper x,Equal variances assumed,1.13,.329,-2.32,6.00,.060,-.90,.39,-1.85,.05 ,Equal variances not assumed,,,-2.38,4.70,.067,-.90,.38,-1.89,.09 ]) @@ -877,7 +911,3 @@ t-test /MISSING=listwise /PAIRS a"b with c d (PA RED). AT_CHECK([pspp t.sps],[1],[ignore],[ignore]) AT_CLEANUP - - - - diff --git a/tests/language/utilities/set.at b/tests/language/utilities/set.at index 059fdfbbc3..b6ff8187cd 100644 --- a/tests/language/utilities/set.at +++ b/tests/language/utilities/set.at @@ -31,9 +31,11 @@ DESCRIPTIVES /x. AT_CHECK([pspp -O format=csv set.pspp], [1], [dnl "set.pspp:7: error: SET: Output format F41.0 specifies width 41, but F requires a width between 1 and 40." -Table: Valid cases = 3; cases with missing value(s) = 0. -Variable,N,Mean,Std Dev,Minimum,Maximum +Table: Descriptive Statistics +,N,Mean,Std Dev,Minimum,Maximum x,3,2.00,1.00,1.00,3.00 +Valid N (listwise),3,,,, +Missing N (listwise),0,,,, ]) AT_CLEANUP diff --git a/tests/language/utilities/title.at b/tests/language/utilities/title.at index bd8318ffb9..bbfb98b695 100644 --- a/tests/language/utilities/title.at +++ b/tests/language/utilities/title.at @@ -80,76 +80,50 @@ Variable,Record,Columns,Format X,1,1- 1,F1.0 Y,1,2- 2,F1.0 -Documents in the active dataset: - -document First line of a document - +Table: Documents +"document First line of a document Second line of a document - The last line should end with a period: . + (Entered )" -(Entered ) - -File label: This is a test file label - -Documents in the active dataset: - -document First line of a document +Table: File Label +Label,This is a test file label +Table: Documents +"document First line of a document Second line of a document - The last line should end with a period: . - -(Entered ) - + (Entered ) Line one - Line two + (Entered )" -(Entered ) - -File label: This is a test file label - -Documents in the active dataset: - -document First line of a document +Table: File Label +Label,This is a test file label +Table: Documents +"document First line of a document Second line of a document - The last line should end with a period: . - -(Entered ) - + (Entered ) Line one - Line two - -(Entered ) - + (Entered ) document There should be another document now. + (Entered )" -(Entered ) - -Documents in the active dataset: - -document First line of a document - +Table: Documents +"document First line of a document Second line of a document - The last line should end with a period: . - -(Entered ) - + (Entered ) Line one - Line two - -(Entered ) - + (Entered ) document There should be another document now. + (Entered )" -(Entered ) - -File label: This is a test file label +Table: File Label +Label,This is a test file label ]) AT_CLEANUP diff --git a/tests/language/xforms/compute.at b/tests/language/xforms/compute.at index 85e52caffd..12a620b798 100644 --- a/tests/language/xforms/compute.at +++ b/tests/language/xforms/compute.at @@ -58,8 +58,8 @@ B,A3 Table: Data List A,B -ABC ,def -GHI ,jkl +ABC,def +GHI,jkl ]) AT_CLEANUP diff --git a/tests/language/xforms/count.at b/tests/language/xforms/count.at index 88d842d564..6f689c2c6a 100644 --- a/tests/language/xforms/count.at +++ b/tests/language/xforms/count.at @@ -81,8 +81,8 @@ v2,1,3- 4,A2 Table: Data List v1,v2,c 12,34,.00 -32,1 ,1.00 -2 ,13,1.00 +32,1,1.00 +2,13,1.00 41,21,.00 11,04,.00 03,4,1.00 diff --git a/tests/language/xforms/recode.at b/tests/language/xforms/recode.at index 05f2ef64db..2d89c5e0b7 100644 --- a/tests/language/xforms/recode.at +++ b/tests/language/xforms/recode.at @@ -155,17 +155,17 @@ LIST s t s0 TO s3 t0 TO t3. AT_CHECK([pspp -O format=csv recode.sps], [0], [Table: Data List s,t,s0,s1,s2,s3,t0,t1,t2,t3 -,,,,xyz ,,,,xyz , -a ,a ,b ,,xyz ,,b ,,xyz ,b @&t@ -ab ,ab ,bc ,,xyz ,,bc ,,xyz , -abc ,abc ,,,def ,,,,def , -abcd,abcd ,,xyzw,xyz ,,,xyzw ,xyz , -123 ,123 ,,,xyz ,,,,xyz , -123,123 ,,,xyz ,,,,xyz , -+1 ,+1 ,,,xyz ,,,,xyz , -1x ,1x ,,,xyz ,,,,xyz , -abcd,abcdefghi ,,xyzw,xyz ,,,,xyz ,xyz @&t@ -xxx ,abcdefghij,,,xyz ,gone,,,xyz ,jklmnopqr @&t@ +,,,,xyz,,,,xyz, +a,a,b,,xyz,,b,,xyz,b +ab,ab,bc,,xyz,,bc,,xyz, +abc,abc,,,def,,,,def, +abcd,abcd,,xyzw,xyz,,,xyzw,xyz, +123,123,,,xyz,,,,xyz, +123,123,,,xyz,,,,xyz, ++1,+1,,,xyz,,,,xyz, +1x,1x,,,xyz,,,,xyz, +abcd,abcdefghi,,xyzw,xyz,,,,xyz,xyz +xxx,abcdefghij,,,xyz,gone,,,xyz,jklmnopqr ]) AT_CLEANUP @@ -183,17 +183,17 @@ LIST s t cs0 TO cs2 ct0 TO ct3. AT_CHECK([pspp -O format=csv recode.sps], [0], [Table: Data List s,t,cs0,cs1,cs2,ct0,ct1,ct2,ct3 -,,,,xyz ,,,xyz , -a ,a ,b ,a ,xyz ,b ,a ,xyz ,b @&t@ -ab ,ab ,bc ,ab ,xyz ,bc ,ab ,xyz ,ab @&t@ -abc ,abc ,abc ,abc ,def ,abc ,abc ,def ,abc @&t@ -abcd,abcd ,abcd,xyzw,xyz ,abcd ,xyzw ,xyz ,abcd @&t@ -123 ,123 ,123 ,123 ,xyz ,123 ,123 ,xyz ,123 @&t@ -123,123 ,123,123,xyz ,123 ,123 ,xyz ,123 @&t@ -+1 ,+1 ,+1 ,+1 ,xyz ,+1 ,+1 ,xyz ,+1 @&t@ -1x ,1x ,1x ,1x ,xyz ,1x ,1x ,xyz ,1x @&t@ -abcd,abcdefghi ,abcd,xyzw,xyz ,abcdefghi ,abcdefghi ,xyz ,xyz @&t@ -xxx ,abcdefghij,xxx ,xxx ,xyz ,abcdefghij,abcdefghij,xyz ,jklmnopqr @&t@ +,,,,xyz,,,xyz, +a,a,b,a,xyz,b,a,xyz,b +ab,ab,bc,ab,xyz,bc,ab,xyz,ab +abc,abc,abc,abc,def,abc,abc,def,abc +abcd,abcd,abcd,xyzw,xyz,abcd,xyzw,xyz,abcd +123,123,123,123,xyz,123,123,xyz,123 +123,123,123,123,xyz,123,123,xyz,123 ++1,+1,+1,+1,xyz,+1,+1,xyz,+1 +1x,1x,1x,1x,xyz,1x,1x,xyz,1x +abcd,abcdefghi,abcd,xyzw,xyz,abcdefghi,abcdefghi,xyz,xyz +xxx,abcdefghij,xxx,xxx,xyz,abcdefghij,abcdefghij,xyz,jklmnopqr ]) AT_CLEANUP @@ -210,16 +210,16 @@ AT_CHECK([pspp -O format=csv recode.sps], [0], [Table: Data List s,t,ns0,ns1,ns2,nt0,nt1,nt2 ,,.,0,3,.,0,3 -a ,a ,.,.,3,.,.,3 -ab ,ab ,.,.,3,.,.,3 -abc ,abc ,.,.,3,.,.,3 -abcd,abcd ,1,1,2,1,1,2 -123 ,123 ,123,123,3,123,123,3 -123,123 ,123,123,3,123,123,3 -+1 ,+1 ,1,1,3,1,1,3 -1x ,1x ,.,.,1,.,.,1 -abcd,abcdefghi ,1,1,2,.,.,3 -xxx ,abcdefghij,.,.,3,.,.,3 +a,a,.,.,3,.,.,3 +ab,ab,.,.,3,.,.,3 +abc,abc,.,.,3,.,.,3 +abcd,abcd,1,1,2,1,1,2 +123,123,123,123,3,123,123,3 +123,123,123,123,3,123,123,3 ++1,+1,1,1,3,1,1,3 +1x,1x,.,.,1,.,.,1 +abcd,abcdefghi,1,1,2,.,.,3 +xxx,abcdefghij,.,.,3,.,.,3 ]) AT_CLEANUP @@ -235,17 +235,17 @@ LIST x sx0 TO sx2. AT_CHECK([pspp -O format=csv recode.sps], [0], [Table: Data List x,sx0,sx1,sx2 -0,,xxx ,foobar @&t@ -1,abcdefghij,xxx ,foobar @&t@ -2,abcdefghij,,xyz @&t@ -3,abcdefghij,xxx ,xyz @&t@ -4,abcdefghij,,xyz @&t@ -5,abcdefghij,xxx ,xyz @&t@ -6,abcdefghij,,xyz @&t@ -7,abcdefghij,xxx ,foobar @&t@ -8,abcdefghij,,foobar @&t@ -9,abcdefghij,xxx ,foobar @&t@ -.,,xxx ,xyz @&t@ +0,,xxx,foobar +1,abcdefghij,xxx,foobar +2,abcdefghij,,xyz +3,abcdefghij,xxx,xyz +4,abcdefghij,,xyz +5,abcdefghij,xxx,xyz +6,abcdefghij,,xyz +7,abcdefghij,xxx,foobar +8,abcdefghij,,foobar +9,abcdefghij,xxx,foobar +.,,xxx,xyz ]) AT_CLEANUP @@ -334,10 +334,10 @@ AT_CHECK([pspp -O format=csv recode.sps], [1], [dnl Table: Data List x,y,z -a,a ,2.00 -a,two ,2.00 -b,three ,2.00 -c,b ,2.00 +a,a,2.00 +a,two,2.00 +b,three,2.00 +c,b,2.00 ]) AT_CLEANUP diff --git a/tests/output/ascii.at b/tests/output/ascii.at index 3f13ea8e8d..934de64662 100644 --- a/tests/output/ascii.at +++ b/tests/output/ascii.at @@ -620,7 +620,7 @@ DATA LIST LIST /x * y * a (a23). Reading free-form data from INLINE. +--------+------+ |Variable|Format| -#========#======# ++--------+------+ |x |F8.0 | |y |F8.0 | |a |A23 | @@ -660,12 +660,14 @@ DESCRIPTIVES X. AT_CHECK([pspp -O box=unicode uc.sps], [0], [dnl -Valid cases = 3; cases with missing value(s) = 0. -╭────────╥─┬──────┬───────┬───────┬───────╮ -│Variable║N│ Mean │Std Dev│Minimum│Maximum│ -╞════════╬═╪══════╪═══════╪═══════╪═══════╡ -│x ║3│2.0000│ 1.0000│ 1.0000│ 3.0000│ -╰────────╨─┴──────┴───────┴───────┴───────╯ + Descriptive Statistics +╭────────────────────┬─┬──────┬───────┬───────┬───────╮ +│ │N│ Mean │Std Dev│Minimum│Maximum│ +├────────────────────┼─┼──────┼───────┼───────┼───────┤ +│x │3│2.0000│ 1.0000│ 1.0000│ 3.0000│ +│Valid N (listwise) │3│ │ │ │ │ +│Missing N (listwise)│0│ │ │ │ │ +╰────────────────────┴─┴──────┴───────┴───────┴───────╯ ]) AT_CLEANUP diff --git a/tests/output/render.at b/tests/output/render.at index d60c427a38..bc23280639 100644 --- a/tests/output/render.at +++ b/tests/output/render.at @@ -1387,11 +1387,13 @@ LIST. ]) AT_CHECK([pspp list.sps], [0], [dnl Data List -x y z ------ -1 2 3 -4 5 6 -7 8 9 ++-+-+-+ +|x|y|z| ++-+-+-+ +|1|2|3| +|4|5|6| +|7|8|9| ++-+-+-+ ]) AT_CLEANUP diff --git a/tests/output/tables.at b/tests/output/tables.at index 623d366c0c..be911d1563 100644 --- a/tests/output/tables.at +++ b/tests/output/tables.at @@ -46,33 +46,33 @@ t-test /PAIRS a with b (PAIRED). AT_CHECK([pspp -O format=csv prec.sps], [0], [dnl Table: Paired Sample Statistics -,,Mean,N,Std. Deviation,S.E. Mean -Pair 1,A,2.00,5,.71,.32 -,B,4.00,5,1.54,.69 +,,N,Mean,Std. Deviation,S.E. Mean +Pair 1,A,5,2.00,.71,.32 +,B,5,4.00,1.54,.69 Table: Paired Samples Correlations ,,N,Correlation,Sig. -Pair 1,A & B,5,.92,.028 +Pair 1,A & B,5,.918,.028 Table: Paired Samples Test -,,Paired Differences,,,,,,, -,,,,,95% Confidence Interval of the Difference,,,, -,,Mean,Std. Deviation,Std. Error Mean,Lower,Upper,t,df,Sig. (2-tailed) +,,Paired Differences,,,,,t,df,Sig. (2-tailed) +,,Mean,Std. Deviation,S.E. Mean,95% Confidence Interval of the Difference,,,, +,,,,,Lower,Upper,,, Pair 1,A - B,-2.00,.94,.42,-3.16,-.84,-4.78,4,.009 Table: Paired Sample Statistics -,,Mean,N,Std. Deviation,S.E. Mean -Pair 1,A,2.00,5,.71,.32 -,B,4.00,5,1.54,.69 +,,N,Mean,Std. Deviation,S.E. Mean +Pair 1,A,5,2.00,.71,.32 +,B,5,4.00,1.54,.69 Table: Paired Samples Correlations ,,N,Correlation,Sig. -Pair 1,A & B,5,.92,.02801 +Pair 1,A & B,5,.918,.02801 Table: Paired Samples Test -,,Paired Differences,,,,,,, -,,,,,95% Confidence Interval of the Difference,,,, -,,Mean,Std. Deviation,Std. Error Mean,Lower,Upper,t,df,Sig. (2-tailed) +,,Paired Differences,,,,,t,df,Sig. (2-tailed) +,,Mean,Std. Deviation,S.E. Mean,95% Confidence Interval of the Difference,,,, +,,,,,Lower,Upper,,, Pair 1,A - B,-2.00,.94,.42,-3.16,-.84,-4.78,4,.00877 ]) @@ -100,4 +100,4 @@ t-test /PAIRS a with b (PAIRED). AT_CHECK([pspp -O format=csv prec.sps], [1], [ignore]) -AT_CLEANUP \ No newline at end of file +AT_CLEANUP diff --git a/tests/perl-module.at b/tests/perl-module.at index 175a09aae8..cbe2a0dd33 100644 --- a/tests/perl-module.at +++ b/tests/perl-module.at @@ -76,11 +76,11 @@ DISPLAY DOCUMENTS. DISPLAY DICTIONARY. SHOW WEIGHT. ]) -AT_CHECK([pspp -O format=csv dump-dict.sps], [0], - [File label: My Dictionary - -Documents in the active dataset: +AT_CHECK([pspp -O format=csv dump-dict.sps], [0], [dnl +Table: File Label +Label,My Dictionary +Table: Documents These Documents Table: Variables @@ -160,30 +160,30 @@ Name,Position,Label,Measurement Level,Role,Width,Alignment,Print Format,Write Fo id,1,,Scale,Input,8,Right,F2.0,F2.0, name,2,,Nominal,Input,20,Left,A20,A20, -File label: This is the file label - -Documents in the active dataset: +Table: File Label +Label,This is the file label +Table: Documents This is a document line Table: Data List id,name -34,frederick @&t@ +34,frederick Table: Variables Name,Position,Label,Measurement Level,Role,Width,Alignment,Print Format,Write Format,Missing Values id,1,,Scale,Input,8,Right,F2.0,F2.0, name,2,,Nominal,Input,20,Left,A20,A20, -File label: This is the file label - -Documents in the active dataset: +Table: File Label +Label,This is the file label +Table: Documents This is a document line Table: Data List id,name -21,wheelbarrow @&t@ +21,wheelbarrow ]) AT_CLEANUP @@ -246,13 +246,13 @@ string,2,My String,Nominal,Input,8,Left,A8,A8,"""this ""; ""that """ longstring,3,My Long String,Nominal,Input,9,Left,A9,A9, Table: Value Labels -Variable,Value,Label -integer,0,Zero +Variable Value,,Label +My Integer,0,Zero ,1,Unity ,2,Duality -string,xx ,foo -,yy ,bar -longstring,xxx ,xfoo +My String,xx,foo +,yy,bar +My Long String,xxx,xfoo ]) AT_CLEANUP @@ -461,17 +461,20 @@ dollar,5,A Dollar Variable,Scale,Input,8,Right,DOLLAR11.2,DOLLAR11.2, datetime,6,A Datetime Variable,Scale,Input,8,Right,DATETIME17.0,DATETIME17.0, Table: Value Labels -Variable,Value,Label -string,1111 ,ones -,2222 ,twos -,3333 ,threes -numeric,1,Unity +Variable Value,,Label +A Short String Variable,1111,ones +,2222,twos +,3333[a],threes +A Numeric Variable,1,Unity ,2,Duality ,3,Thripality +Footnotes: +a,User-missing value + Table: Variable and Dataset Attributes -Variable,Name,Value -numeric,colour[1],blue +Variable and Name,,Value +A Numeric Variable,colour[1],blue ,colour[2],pink ,colour[3],violet ,nationality,foreign @@ -479,11 +482,11 @@ numeric,colour[1],blue Table: Data List string,longstring,numeric,date,dollar,datetime -1111 ,One ,1,01-JAN-2001,$1.00,01-JAN-2001 01:01 -2222 ,Two ,2,02-FEB-2002,$2.00,02-FEB-2002 02:02 -3333 ,Three ,3,03-MAR-2003,$3.00,03-MAR-2003 03:03 -. ,. ,.,.,. ,. -5555 ,Five ,5,05-MAY-2005,$5.00,05-MAY-2005 05:05 +1111,One,1,01-JAN-2001,$1.00,01-JAN-2001 01:01 +2222,Two,2,02-FEB-2002,$2.00,02-FEB-2002 02:02 +3333,Three,3,03-MAR-2003,$3.00,03-MAR-2003 03:03 +.,.,.,.,. ,. +5555,Five,5,05-MAY-2005,$5.00,05-MAY-2005 05:05 Table: Variables Name,Position,Label,Measurement Level,Role,Width,Alignment,Print Format,Write Format,Missing Values @@ -495,17 +498,20 @@ dollar,5,A Dollar Variable,Scale,Input,8,Right,DOLLAR11.2,DOLLAR11.2, datetime,6,A Datetime Variable,Scale,Input,8,Right,DATETIME17.0,DATETIME17.0, Table: Value Labels -Variable,Value,Label -string,1111 ,ones -,2222 ,twos -,3333 ,threes -numeric,1,Unity +Variable Value,,Label +A Short String Variable,1111,ones +,2222,twos +,3333[a],threes +A Numeric Variable,1,Unity ,2,Duality ,3,Thripality +Footnotes: +a,User-missing value + Table: Variable and Dataset Attributes -Variable,Name,Value -numeric,colour[1],blue +Variable and Name,,Value +A Numeric Variable,colour[1],blue ,colour[2],pink ,colour[3],violet ,nationality,foreign @@ -513,11 +519,11 @@ numeric,colour[1],blue Table: Data List string,longstring,numeric,date,dollar,datetime -1111 ,One ,1,01-JAN-2001,$1.00,01-JAN-2001 01:01 -2222 ,Two ,2,02-FEB-2002,$2.00,02-FEB-2002 02:02 -3333 ,Three ,3,03-MAR-2003,$3.00,03-MAR-2003 03:03 -. ,. ,.,.,. ,. -5555 ,Five ,5,05-MAY-2005,$5.00,05-MAY-2005 05:05 +1111,One,1,01-JAN-2001,$1.00,01-JAN-2001 01:01 +2222,Two,2,02-FEB-2002,$2.00,02-FEB-2002 02:02 +3333,Three,3,03-MAR-2003,$3.00,03-MAR-2003 03:03 +.,.,.,.,. ,. +5555,Five,5,05-MAY-2005,$5.00,05-MAY-2005 05:05 ]]) AT_CLEANUP -- 2.30.2