Add OUTPUT MODIFY command
authorJohn Darrington <john@darrington.wattle.id.au>
Wed, 9 Jul 2014 12:23:37 +0000 (14:23 +0200)
committerJohn Darrington <john@darrington.wattle.id.au>
Wed, 9 Jul 2014 13:54:34 +0000 (15:54 +0200)
doc/utilities.texi
src/language/command.def
src/language/utilities/automake.mk
src/language/utilities/output.c [new file with mode: 0644]
src/output/tab.c
src/output/tab.h
tests/automake.mk
tests/output/tables.at [new file with mode: 0644]

index 158177b6884f6435e006099722643f66e5082e5b..da5b7b0daae7d3f5ae0e99f053b53e2d8c475af2 100644 (file)
@@ -25,6 +25,7 @@ encountered in the input.
 * HOST::                        Temporarily return to the operating system.
 * INCLUDE::                     Include a file within the current one.
 * INSERT::                      Insert a file within the current one.
+* OUTPUT::                      Modify the appearance of the output.
 * PERMISSIONS::                 Change permissions on a file.
 * PRESERVE and RESTORE::        Saving settings and restoring them later.
 * SET::                         Adjust @pspp{} runtime parameters.
@@ -334,6 +335,42 @@ When ENCODING is not specified, the default is taken from the
 @option{--syntax-encoding} command option, if it was specified, and
 otherwise it is @code{Auto}.
 
+@node OUTPUT
+@section OUTPUT
+@vindex OUTPUT
+@cindex precision, of output
+@cindex decimal places
+
+@display
+OUTPUT MODIFY
+       /SELECT TABLES
+       /TABLECELLS SELECT = [ @{SIGNIFICANCE, COUNT@} ]
+                   FORMAT = @var{fmt_spec}.
+@end display
+@note{In the above synopsis the characters @samp{[} and @samp{]} are literals.
+They must appear in the syntax to be interpreted.}
+
+@cmd{OUTPUT} changes the appearance of the tables in which results are printed.
+In particular, it can be used to set the format and precision to which results are displayed.
+
+After running this command, the default table appearance parameters will have been modified and  each 
+new output table generated will use the new parameters.
+
+Following @code{/TABLECELLS SELECT =} a list of cell classes must appear, enclosed in square
+brackets.  This list determines the classes of values should be selected for modification.
+Each class can be:
+
+@table @asis
+@item SIGNIFICANCE
+Significance of tests (p-values).
+
+@item COUNT
+Counts or sums of weights.
+@end table
+
+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.
+
 @node PERMISSIONS
 @section PERMISSIONS
 @vindex PERMISSIONS
index 5192d0cbf22601e485cb2209545eeb2d4548af44..8fe737218fa83f3755beadbc3836a454b343255c 100644 (file)
@@ -32,6 +32,7 @@ DEF_CMD (S_ANY, 0, "INSERT", cmd_insert)
 DEF_CMD (S_ANY, 0, "N OF CASES", cmd_n_of_cases)
 DEF_CMD (S_ANY, F_ABBREV, "N", cmd_n_of_cases)
 DEF_CMD (S_ANY, 0, "NEW FILE", cmd_new_file)
+DEF_CMD (S_ANY, 0, "OUTPUT", cmd_output)
 DEF_CMD (S_ANY, 0, "PERMISSIONS", cmd_permissions)
 DEF_CMD (S_ANY, 0, "PRESERVE", cmd_preserve)
 DEF_CMD (S_ANY, F_ABBREV, "Q", cmd_finish)
index cb6910678d51b59e150a91a991e7e75fba923a5c..1c745b2b7ff0b1a6997d88ed8645a1f8c26e4688 100644 (file)
@@ -12,6 +12,7 @@ language_utilities_sources = \
        src/language/utilities/host.c \
        src/language/utilities/title.c \
        src/language/utilities/include.c \
+       src/language/utilities/output.c \
        src/language/utilities/permissions.c 
 
 all_q_sources += $(src_language_utilities_built_sources:.c=.q)
diff --git a/src/language/utilities/output.c b/src/language/utilities/output.c
new file mode 100644 (file)
index 0000000..ac60663
--- /dev/null
@@ -0,0 +1,192 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 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 <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+#include <ctype.h>
+#include <stdlib.h>
+
+#include "data/dataset.h"
+#include "data/settings.h"
+#include "data/format.h"
+#include "language/command.h"
+#include "language/lexer/lexer.h"
+#include "language/lexer/format-parser.h"
+#include "libpspp/message.h"
+#include "libpspp/version.h"
+#include "output/tab.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;
+  
+  if (!lex_force_match_id (lexer, "MODIFY"))
+    {
+      lex_error (lexer, NULL);
+      goto error;
+    }
+
+  while (lex_token (lexer) != T_ENDCMD)
+    {
+      lex_match (lexer, T_SLASH);
+
+      if (lex_match_id (lexer, "SELECT"))
+       {
+         if (!lex_match_id (lexer, "TABLES"))
+           {
+             lex_error (lexer, NULL);
+             goto error;
+           }
+       }
+      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;
+         
+         while (lex_token (lexer) != T_SLASH && 
+                lex_token (lexer) != T_ENDCMD)
+           {
+             if (lex_match_id (lexer, "SELECT"))
+               {
+                 lex_force_match (lexer, T_EQUALS);
+                 lex_force_match (lexer, T_LBRACK);
+                 
+                 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;
+                       }
+                   }
+                 lex_force_match (lexer, T_RBRACK);
+               }
+             else if (lex_match_id (lexer, "FORMAT"))
+               {
+                 struct fmt_spec fmt;    
+                 char type[FMT_TYPE_LEN_MAX + 1];
+                 int width = -1;
+                 int decimals = -1;
+
+                 lex_force_match (lexer, T_EQUALS);
+                 if (! parse_abstract_format_specifier (lexer, type, &width, &decimals))
+                   {
+                     lex_error (lexer, NULL);
+                     goto error;
+                   }
+
+                 if (width <= 0)
+                   {
+                     const struct fmt_spec *dflt = settings_get_format ();
+                     width = dflt->w;
+                   }
+
+                  if (!fmt_from_name (type, &fmt.type))
+                    {
+                      lex_error (lexer, _("Unknown format type `%s'."), type);
+                     goto error;
+                    }
+
+                 fmt.w = width;
+                 fmt.d = decimals;
+
+                 os->fmt = fmt;
+               }
+             else 
+               {
+                 lex_error (lexer, NULL);
+                 goto error;
+           
+               }
+           }
+       }
+      else 
+       {
+         lex_error (lexer, NULL);
+         goto error;   
+
+       }
+    }
+
+  /* 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);
+  return CMD_SUCCESS;
+}
index f310319f590fe2833fa5828ccafac1b5efd917f8..d9872c7214e5d3d9015a92b1101eca3702e83f99 100644 (file)
@@ -56,6 +56,15 @@ 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 *
@@ -82,9 +91,9 @@ tab_create (int nc, int nr)
 
   memset (t->rv, TAL_GAP, nr * (nc + 1));
 
-  t->fmtmap[RC_PVALUE] = &F_4_3;
-  t->fmtmap[RC_INTEGER] = &F_8_0;
-  t->fmtmap[RC_OTHER] = settings_get_format ();
+  t->fmtmap[RC_PVALUE] = ugly[RC_PVALUE];
+  t->fmtmap[RC_INTEGER] = ugly[RC_INTEGER];
+  t->fmtmap[RC_OTHER] = *settings_get_format ();
 
   t->col_ofs = t->row_ofs = 0;
 
@@ -95,7 +104,7 @@ tab_create (int nc, int nr)
 void 
 tab_set_format (struct tab_table *t, enum result_class rc, const struct fmt_spec *fmt)
 {
-  t->fmtmap[rc] = fmt;
+  t->fmtmap[rc] = *fmt;
 }
 
 
@@ -417,7 +426,7 @@ tab_double (struct tab_table *table, int c, int r, unsigned char opt,
   assert (r < tab_nr (table));
 
   if (fmt == NULL)
-    fmt = table->fmtmap[rc];
+    fmt = &table->fmtmap[rc];
   
   fmt_check_output (fmt);
 
index d08cf48c2813cf8eeb1c962c187384575cded635..ae3f4aeaf8458294de8f6382cefdced83d2278f5 100644 (file)
@@ -40,6 +40,7 @@
 
 #include "libpspp/compiler.h"
 #include "output/table.h"
+#include "data/format.h"
 
 enum result_class
   {
@@ -78,7 +79,7 @@ struct tab_table
     /* X and Y offsets. */
     int col_ofs, row_ofs;
 
-    const struct fmt_spec *fmtmap [n_RC];
+    struct fmt_spec fmtmap [n_RC];
   };
 
 struct tab_table *tab_cast (const struct table *);
index 7fd773cb206baed76dafa03a14ad864c46726c59..28159d4c13b63a27c3174946ffe382408feac659 100644 (file)
@@ -371,6 +371,7 @@ TESTSUITE_AT = \
        tests/output/output.at \
        tests/output/paper-size.at \
        tests/output/render.at \
+       tests/output/tables.at \
        tests/ui/terminal/main.at \
        tests/ui/syntax-gen.at \
        tests/perl-module.at
diff --git a/tests/output/tables.at b/tests/output/tables.at
new file mode 100644 (file)
index 0000000..10b321a
--- /dev/null
@@ -0,0 +1,63 @@
+AT_BANNER([output -- tables])
+
+AT_SETUP([precision])
+
+AT_DATA([prec.sps], [[
+data list notable list /A * B *.
+begin data.
+2.0 3.0
+1.0 2.0
+2.0 4.5
+2.0 4.5
+3.0 6.0
+end data.
+
+OUTPUT MODIFY 
+       /SELECT TABLES 
+       /TABLECELLS  SELECT = [ SIGNIFICANCE ] 
+                   FORMAT = F.3.
+
+t-test /PAIRS a with b (PAIRED).
+
+OUTPUT MODIFY 
+       /SELECT TABLES 
+       /TABLECELLS  SELECT = [ SIGNIFICANCE ] 
+                   FORMAT = F12.5.
+
+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
+
+Table: Paired Samples Correlations
+,,N,Correlation,Sig.
+Pair 1,A & B,5,.92,.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)
+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
+
+Table: Paired Samples Correlations
+,,N,Correlation,Sig.
+Pair 1,A & B,5,.92,.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)
+Pair 1,A - B,-2.00,.94,.42,-3.16,-.84,-4.78,4,.00877
+])
+
+AT_CLEANUP