New top level menu for Graphs.
authorJohn Darrington <john@darrington.wattle.id.au>
Wed, 11 Nov 2015 18:09:15 +0000 (19:09 +0100)
committerJohn Darrington <john@darrington.wattle.id.au>
Wed, 11 Nov 2015 18:10:28 +0000 (19:10 +0100)
Added a new top level menu to assist with the generation of graphics.
Currently it has only scatterplot, histogram and barchart.

19 files changed:
NEWS
doc/statistics.texi
src/language/stats/automake.mk
src/language/stats/chart-category.h [new file with mode: 0644]
src/language/stats/graph.c
src/ui/gui/automake.mk
src/ui/gui/barchart.ui [new file with mode: 0644]
src/ui/gui/data-editor.ui
src/ui/gui/histogram.ui [new file with mode: 0644]
src/ui/gui/psppire-dialog-action-barchart.c [new file with mode: 0644]
src/ui/gui/psppire-dialog-action-barchart.h [new file with mode: 0644]
src/ui/gui/psppire-dialog-action-histogram.c [new file with mode: 0644]
src/ui/gui/psppire-dialog-action-histogram.h [new file with mode: 0644]
src/ui/gui/psppire-dialog-action-scatterplot.c [new file with mode: 0644]
src/ui/gui/psppire-dialog-action-scatterplot.h [new file with mode: 0644]
src/ui/gui/scatterplot.ui [new file with mode: 0644]
src/ui/gui/widgets.c
tests/language/dictionary/split-file.at
tests/language/stats/graph.at

diff --git a/NEWS b/NEWS
index 14000fe95802b4832ef928c29ae5d7afa513cf98..d7d0a4102b7efb42aeda6d0585a2ba0019ab48f0 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -13,6 +13,11 @@ Changes from 0.8.5 to 0.9.0:
 
  * A Russian localisation has been contributed.
 
+ * The graphic user interface now has a Graphs menu to access the GRAPH
+   command.
+
+ * The GRAPH command now has a /BAR subcommand to draw barcharts.
+
  * The graphical user interface uses Gtk+ version 3 instead of version 2.
    Accordingly, it has a somewhat different look and feel.
 
index 85217cd636fef532832114c5182e1aac4d30fee9..a9adb2afc6462a1c272bc33352ebff9b6f43999e 100644 (file)
@@ -411,8 +411,9 @@ large quantity of output.
 
 @display
 GRAPH
-        /HISTOGRAM = @var{var}
-        /SCATTERPLOT [(BIVARIATE)] = @var{var1} WITH @var{var2} [BY @var{var3}] 
+        /HISTOGRAM [(NORMAL)]= @var{var}
+        /SCATTERPLOT [(BIVARIATE)] = @var{var1} WITH @var{var2} [BY @var{var3}]
+        /BAR = @{@var{summary-function}(@var{var1}) | @var{count-function}@} BY @var{var2} [BY @var{var3}] 
         [ /MISSING=@{LISTWISE, VARIABLE@} [@{EXCLUDE, INCLUDE@}] ] 
                [@{NOREPORT,REPORT@}]
 
@@ -441,6 +442,8 @@ this plot it is possible to analyze gender differences for @var{height} vs.@: @v
 
 The subcommand @subcmd{HISTOGRAM} produces a histogram. Only one variable is allowed for
 the histogram plot.
+The keyword @subcmd{NORMAL} may be specified in parentheses, to indicate that the ideal normal curve
+should be superimposed over the histogram.
 For an alternative method to produce histograms @pxref{EXAMINE}. The
 following example produces a histogram plot for the variable @var{weight}.
 
@@ -449,6 +452,57 @@ GRAPH
         /HISTOGRAM = @var{weight}.
 @end example
 
+@cindex bar chart
+The subcommand @subcmd{BAR} produces a bar chart.
+This subcommand requires that a @var{count-function} be specified (with no arguments) or a @var{summary-function} with a variable @var{var1} in parentheses.
+Following the summary or count function, the keyword @subcmd{BY} should be specified and then a catagorical variable, @var{var2}.
+The values of the variable @var{var2} determine the labels of the bars to be plotted.
+Optionally a second categorical variable @var{var3} may be specified in which case a clustered (grouped) bar chart is produced.
+
+Valid count functions are
+@table @subcmd
+@item COUNT
+The weighted counts of the cases in each category.
+@item PCT
+The weighted counts of the cases in each category expressed as a percentage of the total weights of the cases.
+@item CUFREQ
+The cumulative weighted counts of the cases in each category.
+@item CUPCT
+The cumulative weighted counts of the cases in each category expressed as a percentage of the total weights of the cases.
+@end table
+
+The summary function is applied to @var{var1} across all cases in each category.
+The recognised summary functions are:
+@table @subcmd
+@item SUM
+The sum.
+@item MEAN
+The arithmetic mean.
+@item MAXIMUM
+The maximum value.
+@item MINIMUM
+The minimum value.
+@end table
+
+The following examples assume a dataset which is the results of a survey.
+Each respondent has indicated annual income, their sex and city of residence.
+One could create a bar chart showing how the mean income varies between of residents of different cities, thus:
+@example
+GRAPH  /BAR  = MEAN(@var{income}) BY @var{city}.
+@end example
+
+This can be extended to also indicate how income in each city differs between the sexes.
+@example
+GRAPH  /BAR  = MEAN(@var{income}) BY @var{city} BY @var{sex}.
+@end example
+
+One might also want to see how many respondents there are from each city.  This can be achieved as follows:
+@example
+GRAPH  /BAR  = COUNT BY @var{city}.
+@end example
+
+Bar charts can also be produced using the @ref{FREQUENCIES} and @ref{CROSSTABS} commands.
+
 @node CORRELATIONS
 @section CORRELATIONS
 
index bfe379e3452d05ada1139968b87ce5e0e68d9535..6388e148d6a2c809d9d81d1ca49be27ebe07ea1e 100644 (file)
@@ -11,6 +11,7 @@ language_stats_sources = \
        src/language/stats/autorecode.c \
        src/language/stats/binomial.c \
        src/language/stats/binomial.h \
+       src/language/stats/chart-category.h  \
        src/language/stats/chisquare.c  \
        src/language/stats/chisquare.h \
        src/language/stats/cochran.c \
diff --git a/src/language/stats/chart-category.h b/src/language/stats/chart-category.h
new file mode 100644 (file)
index 0000000..afe88b9
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef BARCHART_DEF_H
+#define BARCHART_DEF_H 1
+
+struct ag_func
+{
+  const char *name;
+  const char *description;
+  
+  int arity;
+  bool cumulative;
+  double (*pre) (void);
+  double (*calc) (double acc, double x, double w);
+  double (*post) (double acc, double cc);
+  double (*ppost) (double acc, double ccc);
+};
+
+extern const struct ag_func ag_func[];
+
+extern const int N_AG_FUNCS;
+
+#endif
index a0dffbd3d13c8cb2d9d54c6644649724764f13e5..8af6a1515fefbdf1f2c363187d8f6fbf501b0ccb 100644 (file)
@@ -23,6 +23,7 @@
 #include <config.h>
 
 #include <math.h>
+#include "gl/xalloc.h"
 #include <gsl/gsl_cdf.h>
 
 #include "libpspp/assertion.h"
 #include "math/order-stats.h"
 #include "output/charts/plot-hist.h"
 #include "output/charts/scatterplot.h"
+#include "output/charts/barchart.h"
 
 #include "language/command.h"
 #include "language/lexer/lexer.h"
 #include "language/lexer/value-parser.h"
 #include "language/lexer/variable-parser.h"
+#include "language/stats/freq.h"
+#include "language/stats/chart-category.h"
 
 #include "output/tab.h"
 
@@ -81,6 +85,15 @@ enum scatter_type
     ST_XYZ
   };
 
+enum  bar_type
+  {
+    CBT_SIMPLE,
+    CBT_GROUPED,
+    CBT_STACKED,
+    CBT_RANGE
+  };
+
+
 /* Variable index for histogram case */
 enum
   {
@@ -122,14 +135,152 @@ struct graph
   bool missing_pw;
 
   /* ------------ Graph ---------------- */
+  bool normal; /* For histograms, draw the normal curve */
+
   enum chart_type chart_type;
   enum scatter_type scatter_type;
-  const struct variable *byvar;
+  enum bar_type bar_type;
+  const struct variable *by_var[2];
+  size_t n_by_vars;
+  
+  struct subcase ordering; /* Ordering for aggregation */
+  int agr; /* Index into ag_func */
+  
   /* A caseproto that contains the plot data */
   struct caseproto *gr_proto;
 };
 
 
+
+
+static double
+calc_mom1 (double acc, double x, double w)
+{
+  return acc + x * w;
+}
+
+static double
+calc_mom0 (double acc, double x UNUSED, double w)
+{
+  return acc + w;
+}
+
+static double
+pre_low_extreme (void)
+{
+  return -DBL_MAX;
+}
+
+static double
+calc_max (double acc, double x, double w UNUSED)
+{
+  return (acc > x) ? acc : x;
+}
+
+static double
+pre_high_extreme (void)
+{
+  return DBL_MAX;
+}
+
+static double
+calc_min (double acc, double x, double w UNUSED)
+{
+  return (acc < x) ? acc : x;
+}
+
+static double
+post_normalise (double acc, double cc)
+{
+  return acc / cc;
+}
+
+static double
+post_percentage (double acc, double ccc)
+{
+  return acc / ccc * 100.0;
+}
+
+
+const struct ag_func ag_func[] =
+  {
+    {"COUNT",   N_("Count"),      0, 0, NULL, calc_mom0, 0, 0},
+    {"PCT",     N_("Percentage"), 0, 0, NULL, calc_mom0, 0, post_percentage},
+    {"CUFREQ",  N_("Cumulative Count"),   0, 1, NULL, calc_mom0, 0, 0},
+    {"CUPCT",   N_("Cumulative Percent"), 0, 1, NULL, calc_mom0, 0, post_percentage},
+
+    {"MEAN",    N_("Mean"),    1, 0, NULL, calc_mom1, post_normalise, 0},
+    {"SUM",     N_("Sum"),     1, 0, NULL, calc_mom1, 0, 0},
+    {"MAXIMUM", N_("Maximum"), 1, 0, pre_low_extreme, calc_max, 0, 0},
+    {"MINIMUM", N_("Minimum"), 1, 0, pre_high_extreme, calc_min, 0, 0},
+  };
+
+const int N_AG_FUNCS = sizeof (ag_func) / sizeof (ag_func[0]);
+
+static bool
+parse_function (struct lexer *lexer, struct graph *graph)
+{
+  int i;
+  for (i = 0 ; i < N_AG_FUNCS; ++i)
+    {
+      if (lex_match_id (lexer, ag_func[i].name))
+       {
+         graph->agr = i;
+         break;
+       }
+    }
+  if (i == N_AG_FUNCS)
+    {
+      goto error;
+    }
+
+  graph->n_dep_vars = ag_func[i].arity;
+  if (ag_func[i].arity > 0)
+    {
+      int v;
+      if (!lex_force_match (lexer, T_LPAREN))
+       goto error;
+
+      graph->dep_vars = xzalloc (sizeof (graph->dep_vars) * graph->n_dep_vars);
+      for (v = 0; v < ag_func[i].arity; ++v)
+       {
+         graph->dep_vars[v] = parse_variable (lexer, graph->dict);
+       }
+
+      if (!lex_force_match (lexer, T_RPAREN))
+       goto error;
+    }
+
+  if (!lex_force_match (lexer, T_BY))
+    goto error;
+
+  graph->by_var[0] = parse_variable (lexer, graph->dict);
+  if (!graph->by_var[0])
+    {
+      goto error;
+    }
+  subcase_add_var (&graph->ordering, graph->by_var[0], SC_ASCEND);
+  graph->n_by_vars++;
+
+  if (lex_match (lexer, T_BY))
+    {
+      graph->by_var[1] = parse_variable (lexer, graph->dict);
+      if (!graph->by_var[1])
+       {
+         goto error;
+       }
+      subcase_add_var (&graph->ordering, graph->by_var[1], SC_ASCEND);
+      graph->n_by_vars++;
+    }
+
+  return true;
+  
+ error:
+  lex_error (lexer, NULL);
+  return false;
+}
+
+
 static void
 show_scatterplot (const struct graph *cmd, struct casereader *input)
 {
@@ -139,12 +290,12 @@ show_scatterplot (const struct graph *cmd, struct casereader *input)
 
   ds_init_empty (&title);
 
-  if (cmd->byvar)
+  if (cmd->n_by_vars > 0)
     {
       ds_put_format (&title, _("%s vs. %s by %s"),
                           var_to_string (cmd->dep_vars[1]),
                           var_to_string (cmd->dep_vars[0]),
-                          var_to_string (cmd->byvar));
+                          var_to_string (cmd->by_var[0]));
     }
   else
     {
@@ -152,12 +303,11 @@ show_scatterplot (const struct graph *cmd, struct casereader *input)
                     var_to_string (cmd->dep_vars[1]),
                     var_to_string (cmd->dep_vars[0]));
     }
-                
 
   scatterplot = scatterplot_create (input,
                                    var_to_string(cmd->dep_vars[0]),
                                    var_to_string(cmd->dep_vars[1]),
-                                   cmd->byvar,
+                                   (cmd->n_by_vars > 0) ? cmd->by_var[0] : NULL,
                                    &byvar_overflow,
                                    ds_cstr (&title),
                                    cmd->es[0].minimum, cmd->es[0].maximum,
@@ -218,7 +368,7 @@ show_histogr (const struct graph *cmd, struct casereader *input)
     chart_item_submit
       ( histogram_chart_create (histogram->gsl_hist,
                                ds_cstr (&label), n, mean,
-                               sqrt (var), false));
+                               sqrt (var), cmd->normal));
 
     statistic_destroy (&histogram->parent);      
     ds_destroy (&label);
@@ -237,6 +387,122 @@ cleanup_exploratory_stats (struct graph *cmd)
 }
 
 
+static void
+run_barchart (struct graph *cmd, struct casereader *input)
+{
+  struct casegrouper *grouper;
+  struct casereader *group;
+  double ccc = 0.0;
+
+  if ( cmd->missing_pw == false) 
+    input = casereader_create_filter_missing (input,
+                                              cmd->dep_vars,
+                                              cmd->n_dep_vars,
+                                              cmd->dep_excl,
+                                              NULL,
+                                              NULL);
+
+
+  input = sort_execute (input, &cmd->ordering);
+
+  struct freq **freqs = NULL;
+  int n_freqs = 0;
+
+  for (grouper = casegrouper_create_vars (input, cmd->by_var,
+                                          cmd->n_by_vars);
+       casegrouper_get_next_group (grouper, &group);
+       casereader_destroy (group))
+    {
+      int v;
+      struct ccase *c = casereader_peek (group, 0);
+
+      /* Deal with missing values in the categorical variables */
+      for (v = 0; v < cmd->n_by_vars; ++v)
+       {
+         if (var_is_value_missing (cmd->by_var[v], case_data (c, cmd->by_var[v]), cmd->fctr_excl) )
+           break;
+       }
+
+      if (v < cmd->n_by_vars)
+       {
+         case_unref (c);
+         continue;
+       }
+
+      freqs = xrealloc (freqs, sizeof (*freqs) * ++n_freqs);
+      freqs[n_freqs - 1] = xzalloc (sizeof (**freqs) +
+                                   sizeof (union value) * (cmd->n_by_vars - 1) );
+
+      if (ag_func[cmd->agr].cumulative && n_freqs >= 2)
+       freqs[n_freqs - 1]->count = freqs[n_freqs - 2]->count;
+      else
+       freqs[n_freqs - 1]->count = 0;
+      if (ag_func[cmd->agr].pre)
+       freqs[n_freqs - 1]->count = ag_func[cmd->agr].pre();
+
+
+      for (v = 0; v < cmd->n_by_vars; ++v)
+       {
+         value_clone (&freqs[n_freqs - 1]->values[v], case_data (c, cmd->by_var[v]),
+                      var_get_width (cmd->by_var[v])
+                      );
+       }
+      case_unref (c);
+
+      double cc = 0;
+      for (;(c = casereader_read (group)) != NULL; case_unref (c))
+       {
+         const double weight = dict_get_case_weight (cmd->dict,c,NULL);
+         const double x =  (cmd->n_dep_vars > 0) ? case_data (c, cmd->dep_vars[0])->f : SYSMIS;
+
+         cc += weight;
+         
+         freqs[n_freqs - 1]->count
+           = ag_func[cmd->agr].calc (freqs[n_freqs - 1]->count, x, weight);
+       }
+
+      if (ag_func[cmd->agr].post)
+       freqs[n_freqs - 1]->count
+         = ag_func[cmd->agr].post (freqs[n_freqs - 1]->count, cc);
+
+      ccc += cc;
+    }
+
+  casegrouper_destroy (grouper);
+
+  for (int i = 0; i < n_freqs; ++i)
+    {
+      if (ag_func[cmd->agr].ppost)
+       freqs[i]->count = ag_func[cmd->agr].ppost (freqs[i]->count, ccc);
+    }
+
+
+  {
+    struct string label;
+    ds_init_empty (&label);
+
+    if (cmd->n_dep_vars > 0)
+      ds_put_format (&label, _("%s of %s"),
+                    ag_func[cmd->agr].description,
+                    var_get_name (cmd->dep_vars[0]));
+    else
+      ds_put_cstr (&label, 
+                    ag_func[cmd->agr].description);
+      
+    chart_item_submit (barchart_create (cmd->by_var, cmd->n_by_vars,
+                                       ds_cstr (&label),
+                                       freqs, n_freqs));
+
+    ds_destroy (&label);
+  }
+
+  for (int i = 0; i < n_freqs; ++i)
+    free (freqs[i]);
+  
+  free (freqs);
+}
+
+
 static void
 run_graph (struct graph *cmd, struct casereader *input)
 {
@@ -278,10 +544,10 @@ run_graph (struct graph *cmd, struct casereader *input)
       const double weight = dict_get_case_weight (cmd->dict,c,NULL);
       if (cmd->chart_type == CT_HISTOGRAM)
        case_data_rw_idx (outcase, HG_IDX_WT)->f = weight;
-      if (cmd->chart_type == CT_SCATTERPLOT && cmd->byvar)
+      if (cmd->chart_type == CT_SCATTERPLOT && cmd->n_by_vars > 0)
        value_copy (case_data_rw_idx (outcase, SP_IDX_BY),
-                   case_data (c, cmd->byvar),
-                   var_get_width (cmd->byvar));
+                   case_data (c, cmd->by_var[0]),
+                   var_get_width (cmd->by_var[0]));
       for(int v=0;v<cmd->n_dep_vars;v++)
        {
          const struct variable *var = cmd->dep_vars[v];
@@ -347,14 +613,14 @@ cmd_graph (struct lexer *lexer, struct dataset *ds)
   
   graph.dict = dataset_dict (ds);
   
-
-  /* ---------------- graph ------------------ */
   graph.dep_vars = NULL;
   graph.chart_type = CT_NONE;
   graph.scatter_type = ST_BIVARIATE;
-  graph.byvar = NULL;
+  graph.n_by_vars = 0;
   graph.gr_proto = caseproto_create ();
 
+  subcase_init_empty (&graph.ordering);
+  
   while (lex_token (lexer) != T_ENDCMD)
     {
       lex_match (lexer, T_SLASH);
@@ -366,6 +632,17 @@ cmd_graph (struct lexer *lexer, struct dataset *ds)
              lex_error (lexer, _("Only one chart type is allowed."));
              goto error;
            }
+          graph.normal = false;
+          if (lex_match (lexer, T_LPAREN))
+            {
+              if (!lex_force_match_id (lexer, "NORMAL"))
+                goto error;
+              
+              if (!lex_force_match (lexer, T_RPAREN))
+                goto error;
+
+              graph.normal = true;
+            }
          if (!lex_force_match (lexer, T_EQUALS))
            goto error;
          graph.chart_type = CT_HISTOGRAM;
@@ -379,6 +656,54 @@ cmd_graph (struct lexer *lexer, struct dataset *ds)
              goto error;
            }
        }
+      else if (lex_match_id (lexer, "BAR"))
+       {
+         if (graph.chart_type != CT_NONE)
+           {
+             lex_error (lexer, _("Only one chart type is allowed."));
+             goto error;
+           }
+         graph.chart_type = CT_BAR;
+         graph.bar_type = CBT_SIMPLE;
+         
+         if (lex_match (lexer, T_LPAREN)) 
+           {
+             if (lex_match_id (lexer, "SIMPLE"))
+               {
+                 /* This is the default anyway */
+               }
+             else if (lex_match_id (lexer, "GROUPED"))  
+               {
+                 graph.bar_type = CBT_GROUPED; 
+                 goto error;
+               }
+             else if (lex_match_id (lexer, "STACKED"))  
+               {
+                 graph.bar_type = CBT_STACKED; 
+                 lex_error (lexer, _("%s is not yet implemented."), "STACKED");
+                 goto error;
+               }
+             else if (lex_match_id (lexer, "RANGE"))  
+               {
+                 graph.bar_type = CBT_RANGE; 
+                 lex_error (lexer, _("%s is not yet implemented."), "RANGE");
+                 goto error;
+               }
+             else
+               {
+                 lex_error (lexer, NULL);
+                 goto error;
+               }
+             if (!lex_force_match (lexer, T_RPAREN))
+               goto error;
+           }
+         
+         if (!lex_force_match (lexer, T_EQUALS))
+           goto error;
+
+         if (! parse_function (lexer, &graph))
+           goto error;
+       }
       else if (lex_match_id (lexer, "SCATTERPLOT"))
        {
          if (graph.chart_type != CT_NONE)
@@ -452,14 +777,9 @@ cmd_graph (struct lexer *lexer, struct dataset *ds)
                  lex_error (lexer, _("Variable expected"));
                  goto error;
                }
-             graph.byvar = v;
+             graph.by_var[0] = v;
            }
        }
-      else if (lex_match_id (lexer, "BAR"))
-       {
-         lex_error (lexer, _("%s is not yet implemented."),"BAR");
-         goto error;
-       }
       else if (lex_match_id (lexer, "LINE"))
        {
          lex_error (lexer, _("%s is not yet implemented."),"LINE");
@@ -547,16 +867,18 @@ cmd_graph (struct lexer *lexer, struct dataset *ds)
       /* See scatterplot.h for the setup of the case prototype */
       graph.gr_proto = caseproto_add_width (graph.gr_proto, 0); /* x value - SP_IDX_X*/
       graph.gr_proto = caseproto_add_width (graph.gr_proto, 0); /* y value - SP_IDX_Y*/
-      /* The byvar contains the plot categories for the different xy plot colors */
-      if (graph.byvar) /* SP_IDX_BY */
-       graph.gr_proto = caseproto_add_width (graph.gr_proto, var_get_width(graph.byvar));
+      /* The by_var contains the plot categories for the different xy plot colors */
+      if (graph.n_by_vars > 0) /* SP_IDX_BY */
+       graph.gr_proto = caseproto_add_width (graph.gr_proto, var_get_width(graph.by_var[0]));
       break;
     case CT_HISTOGRAM:
       graph.gr_proto = caseproto_add_width (graph.gr_proto, 0); /* x value      */
       graph.gr_proto = caseproto_add_width (graph.gr_proto, 0); /* weight value */
       break;
+    case CT_BAR:
+      break;
     case CT_NONE:
-      lex_error_expecting (lexer,"HISTOGRAM","SCATTERPLOT",NULL);
+      lex_error_expecting (lexer, "HISTOGRAM", "SCATTERPLOT", "BAR", NULL);
       goto error;
     default:
       NOT_REACHED ();
@@ -570,11 +892,17 @@ cmd_graph (struct lexer *lexer, struct dataset *ds)
     
     grouper = casegrouper_create_splits (proc_open (ds), graph.dict);
     while (casegrouper_get_next_group (grouper, &group))
-      run_graph (&graph, group);
+      {
+       if (graph.chart_type == CT_BAR)
+         run_barchart (&graph, group);
+       else
+         run_graph (&graph, group);
+      }
     ok = casegrouper_destroy (grouper);
     ok = proc_commit (ds) && ok;
   }
 
+  subcase_destroy (&graph.ordering);
   free (graph.dep_vars);
   pool_destroy (graph.pool);
   caseproto_unref (graph.gr_proto);
@@ -582,6 +910,7 @@ cmd_graph (struct lexer *lexer, struct dataset *ds)
   return CMD_SUCCESS;
 
  error:
+  subcase_destroy (&graph.ordering);
   caseproto_unref (graph.gr_proto);
   free (graph.dep_vars);
   pool_destroy (graph.pool);
index 59200b09a7dd6c6454ec2031eb6fb2ef1792ddc5..ad581e8b034bbb419efc0bb2069cab11820d791f 100644 (file)
@@ -5,6 +5,7 @@ UI_FILES = \
        src/ui/gui/autorecode.ui \
        src/ui/gui/binomial.ui \
        src/ui/gui/compute.ui \
+       src/ui/gui/barchart.ui \
        src/ui/gui/correlation.ui \
        src/ui/gui/count.ui \
        src/ui/gui/crosstabs.ui \
@@ -17,6 +18,7 @@ UI_FILES = \
        src/ui/gui/factor.ui \
        src/ui/gui/find.ui \
        src/ui/gui/frequencies.ui \
+       src/ui/gui/histogram.ui \
        src/ui/gui/indep-samples.ui \
        src/ui/gui/k-means.ui \
        src/ui/gui/k-related.ui \
@@ -35,6 +37,7 @@ UI_FILES = \
        src/ui/gui/regression.ui \
        src/ui/gui/reliability.ui \
        src/ui/gui/roc.ui \
+       src/ui/gui/scatterplot.ui \
        src/ui/gui/select-cases.ui \
        src/ui/gui/t-test.ui \
        src/ui/gui/text-data-import.ui \
@@ -189,6 +192,8 @@ src_ui_gui_psppire_SOURCES = \
        src/ui/gui/psppire-dialog-action.h \
        src/ui/gui/psppire-dialog-action-1sks.c \
        src/ui/gui/psppire-dialog-action-1sks.h \
+       src/ui/gui/psppire-dialog-action-barchart.c \
+       src/ui/gui/psppire-dialog-action-barchart.h \
        src/ui/gui/psppire-dialog-action-binomial.c \
        src/ui/gui/psppire-dialog-action-binomial.h \
        src/ui/gui/psppire-dialog-action-chisquare.c \
@@ -211,6 +216,8 @@ src_ui_gui_psppire_SOURCES = \
        src/ui/gui/psppire-dialog-action-flip.h \
        src/ui/gui/psppire-dialog-action-frequencies.c \
        src/ui/gui/psppire-dialog-action-frequencies.h \
+       src/ui/gui/psppire-dialog-action-histogram.c \
+       src/ui/gui/psppire-dialog-action-histogram.h \
        src/ui/gui/psppire-dialog-action-indep-samps.c \
        src/ui/gui/psppire-dialog-action-indep-samps.h \
        src/ui/gui/psppire-dialog-action-kmeans.c \
@@ -235,6 +242,8 @@ src_ui_gui_psppire_SOURCES = \
        src/ui/gui/psppire-dialog-action-roc.h \
        src/ui/gui/psppire-dialog-action-runs.c \
        src/ui/gui/psppire-dialog-action-runs.h \
+       src/ui/gui/psppire-dialog-action-scatterplot.c \
+       src/ui/gui/psppire-dialog-action-scatterplot.h \
        src/ui/gui/psppire-dialog-action-sort.c \
        src/ui/gui/psppire-dialog-action-sort.h \
        src/ui/gui/psppire-dialog-action-tt1s.c \
diff --git a/src/ui/gui/barchart.ui b/src/ui/gui/barchart.ui
new file mode 100644 (file)
index 0000000..e27e6c3
--- /dev/null
@@ -0,0 +1,388 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.18.3 -->
+<interface>
+  <requires lib="gtk+" version="3.0"/>
+  <requires lib="psppire" version="2054.17080"/>
+  <object class="PsppireDialog" id="barchart-dialog">
+    <property name="can_focus">False</property>
+    <property name="title" translatable="yes">Barchart</property>
+    <property name="modal">True</property>
+    <property name="help_page">GRAPH</property>
+    <child>
+      <object class="GtkBox" id="dialog-hbox1">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+        <property name="spacing">2</property>
+        <child>
+          <object class="GtkGrid" id="table1">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <property name="hexpand">True</property>
+            <property name="vexpand">True</property>
+            <child>
+              <object class="PsppireSelector" id="indep-selector">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="no_show_all">True</property>
+                <property name="hexpand">False</property>
+                <property name="vexpand">False</property>
+                <property name="border_width">5</property>
+                <property name="primary">True</property>
+                <property name="source_widget">dict-view</property>
+                <property name="dest_widget">entry1</property>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="top_attach">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkScrolledWindow" id="variables">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="hscrollbar_policy">never</property>
+                <property name="shadow_type">etched-in</property>
+                <child>
+                  <object class="PsppireDictView" id="dict-view">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="border_width">0</property>
+                    <property name="headers_visible">False</property>
+                    <child internal-child="selection">
+                      <object class="GtkTreeSelection" id="psppire-dictview-selection1"/>
+                    </child>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">0</property>
+                <property name="height">3</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkFrame" id="frame1">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="hexpand">True</property>
+                <property name="label_xalign">0</property>
+                <property name="shadow_type">none</property>
+                <child>
+                  <object class="GtkAlignment" id="alignment2">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="left_padding">12</property>
+                    <child>
+                      <object class="GtkEntry" id="entry1">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="invisible_char">•</property>
+                        <property name="primary_icon_activatable">False</property>
+                        <property name="secondary_icon_activatable">False</property>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+                <child type="label">
+                  <object class="GtkLabel" id="label2">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="label" translatable="yes">Category A_xis:</property>
+                    <property name="use_markup">True</property>
+                    <property name="use_underline">True</property>
+                    <property name="mnemonic_widget">entry1</property>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="left_attach">2</property>
+                <property name="top_attach">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkFrame" id="frame2">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="hexpand">True</property>
+                <property name="vexpand">True</property>
+                <property name="label_xalign">0</property>
+                <child>
+                  <object class="GtkGrid" id="table2">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="margin_right">5</property>
+                    <child>
+                      <object class="GtkRadioButton" id="radiobutton-count">
+                        <property name="label" translatable="yes">_N of cases</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">False</property>
+                        <property name="hexpand">True</property>
+                        <property name="vexpand">True</property>
+                        <property name="use_underline">True</property>
+                        <property name="xalign">0</property>
+                        <property name="active">True</property>
+                        <property name="draw_indicator">True</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">0</property>
+                        <property name="top_attach">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkRadioButton" id="radiobutton-cum-count">
+                        <property name="label" translatable="yes">_Cum. n of cases</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">False</property>
+                        <property name="use_underline">True</property>
+                        <property name="xalign">0</property>
+                        <property name="draw_indicator">True</property>
+                        <property name="group">radiobutton-count</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">0</property>
+                        <property name="top_attach">1</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkRadioButton" id="radiobutton3">
+                        <property name="label" translatable="yes">Other _summary function</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">False</property>
+                        <property name="vexpand">True</property>
+                        <property name="use_underline">True</property>
+                        <property name="xalign">0</property>
+                        <property name="draw_indicator">True</property>
+                        <property name="group">radiobutton-count</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">0</property>
+                        <property name="top_attach">2</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkRadioButton" id="radiobutton-percent">
+                        <property name="label" translatable="yes">% of c_ases</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">False</property>
+                        <property name="use_underline">True</property>
+                        <property name="xalign">0</property>
+                        <property name="draw_indicator">True</property>
+                        <property name="group">radiobutton-count</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="top_attach">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkRadioButton" id="radiobutton-cum-percent">
+                        <property name="label" translatable="yes">C_um. % of cases</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">False</property>
+                        <property name="hexpand">True</property>
+                        <property name="use_underline">True</property>
+                        <property name="xalign">0</property>
+                        <property name="draw_indicator">True</property>
+                        <property name="group">radiobutton-count</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="top_attach">1</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkBox" id="hbox1">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <child>
+                          <object class="GtkAspectFrame" id="aspectframe1">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="label_xalign">0.5</property>
+                            <property name="shadow_type">none</property>
+                            <property name="ratio">9.9999997473787516e-05</property>
+                            <child>
+                              <object class="PsppireSelector" id="psppire-selector1">
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="receives_default">True</property>
+                                <property name="border_width">5</property>
+                                <property name="source_widget">dict-view</property>
+                                <property name="dest_widget">entry2</property>
+                              </object>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">False</property>
+                            <property name="position">0</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkFrame" id="frame3">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="label_xalign">0</property>
+                            <property name="shadow_type">none</property>
+                            <child>
+                              <object class="GtkAlignment" id="alignment3">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="left_padding">12</property>
+                                <child>
+                                  <object class="GtkEntry" id="entry2">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="invisible_char">•</property>
+                                    <property name="primary_icon_activatable">False</property>
+                                    <property name="secondary_icon_activatable">False</property>
+                                  </object>
+                                </child>
+                              </object>
+                            </child>
+                            <child type="label">
+                              <object class="GtkLabel" id="label3">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="label" translatable="yes">_Variable:</property>
+                                <property name="use_markup">True</property>
+                                <property name="use_underline">True</property>
+                                <property name="mnemonic_widget">entry1</property>
+                              </object>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="expand">True</property>
+                            <property name="fill">True</property>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="left_attach">0</property>
+                        <property name="top_attach">3</property>
+                        <property name="width">2</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkComboBox" id="combobox1">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="valign">center</property>
+                        <property name="vexpand">False</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="top_attach">2</property>
+                      </packing>
+                    </child>
+                  </object>
+                </child>
+                <child type="label">
+                  <object class="GtkLabel" id="label1">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="label" translatable="yes">Bars Represent</property>
+                    <property name="use_markup">True</property>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="top_attach">0</property>
+                <property name="width">2</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkFrame" id="frame4">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="hexpand">True</property>
+                <property name="label_xalign">0</property>
+                <property name="shadow_type">none</property>
+                <child>
+                  <object class="GtkAlignment" id="alignment1">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="left_padding">12</property>
+                    <child>
+                      <object class="GtkEntry" id="entry3">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="invisible_char">•</property>
+                        <property name="primary_icon_activatable">False</property>
+                        <property name="secondary_icon_activatable">False</property>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+                <child type="label">
+                  <object class="GtkLabel" id="label4">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="label" translatable="yes">Category C_luster:</property>
+                    <property name="use_markup">True</property>
+                    <property name="use_underline">True</property>
+                    <property name="mnemonic_widget">entry1</property>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="left_attach">2</property>
+                <property name="top_attach">2</property>
+              </packing>
+            </child>
+            <child>
+              <object class="PsppireSelector" id="indep-selector1">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="no_show_all">True</property>
+                <property name="hexpand">False</property>
+                <property name="vexpand">False</property>
+                <property name="border_width">5</property>
+                <property name="source_widget">dict-view</property>
+                <property name="dest_widget">entry3</property>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="top_attach">2</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">True</property>
+            <property name="fill">True</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="PsppireVButtonBox" id="psppire-vbuttonbox1">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="border_width">5</property>
+            <property name="orientation">vertical</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="pack_type">end</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+  </object>
+</interface>
index 10f0f5f8c4e318027ce2e774fa94ac8b7ce19333..ae4ba2b4ef52ac8a23933e4081ad6874b38a81a8 100644 (file)
            <property name="stock-id">analyze-roc-curve</property>
           </object>
         </child>
+        <child>
+          <object class="GtkAction" id="graphs">
+            <property name="name">graphs</property>
+            <property name="label" translatable="yes">_Graphs</property>
+          </object>
+        </child>
+        <child>
+          <object class="PsppireDialogActionScatterplot" id="graphs_scatterplot">
+            <property name="manager">uimanager1</property>
+            <property name="name">graphs_scatterplot</property>
+            <property name="label" translatable="yes">_Scatterplot</property>
+           <property name="stock-id">graphs-scatterplot</property>
+          </object>
+        </child>
+        <child>
+          <object class="PsppireDialogActionHistogram" id="graphs_histogram">
+            <property name="manager">uimanager1</property>
+            <property name="name">graphs_histogram</property>
+            <property name="label" translatable="yes">_Histogram</property>
+           <property name="stock-id">graphs-histogram</property>
+          </object>
+        </child>
+        <child>
+          <object class="PsppireDialogActionBarchart" id="graphs_barchart">
+            <property name="manager">uimanager1</property>
+            <property name="name">graphs_barchart</property>
+            <property name="label" translatable="yes">_Barchart</property>
+           <property name="stock-id">graphs-barchart</property>
+          </object>
+        </child>
         <child>
           <object class="GtkAction" id="utilities">
             <property name="name">utilities</property>
           </menu>
           <menuitem action="roc-curve"/>
         </menu>
+        <menu action="graphs">
+          <menuitem action="graphs_scatterplot"/>
+        </menu>
+        <menu action="graphs">
+          <menuitem action="graphs_scatterplot"/>
+          <menuitem action="graphs_histogram"/>
+         <menuitem action="graphs_barchart"/>
+        </menu>
         <menu action="utilities">
           <menuitem action="utilities_variables"/>
           <menuitem action="utilities_comments"/>
diff --git a/src/ui/gui/histogram.ui b/src/ui/gui/histogram.ui
new file mode 100644 (file)
index 0000000..35f5ea2
--- /dev/null
@@ -0,0 +1,177 @@
+<?xml version="1.0"?>
+<interface>
+  <requires lib="psppire" version="2054.17080"/>
+  <!-- interface-requires gtk+ 2.12 -->
+  <!-- interface-naming-policy project-wide -->
+  <object class="PsppireDialog" id="histogram-dialog">
+    <property name="title" translatable="yes">Histogram</property>
+    <property name="modal">True</property>
+    <property name="help-page">GRAPH</property>
+    <child>
+      <object class="GtkHBox" id="dialog-hbox1">
+        <property name="visible">True</property>
+        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+        <property name="spacing">2</property>
+        <child>
+          <object class="GtkTable" id="table1">
+            <property name="visible">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <property name="n_rows">3</property>
+            <property name="n_columns">3</property>
+            <child>
+              <object class="PsppireSelector" id="indep-selector">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="no_show_all">True</property>
+                <property name="border_width">5</property>
+                <property name="source_widget">dict-view</property>
+                <property name="dest_widget">entry1</property>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">2</property>
+                <property name="top_attach">1</property>
+                <property name="bottom_attach">2</property>
+                <property name="x_options"></property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkScrolledWindow" id="variables">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="hscrollbar_policy">never</property>
+                <property name="vscrollbar_policy">automatic</property>
+                <property name="shadow_type">etched-in</property>
+                <child>
+                  <object class="PsppireDictView" id="dict-view">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="headers_visible">False</property>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="bottom_attach">3</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkFrame" id="frame1">
+                <property name="visible">True</property>
+                <property name="label_xalign">0</property>
+                <property name="shadow_type">none</property>
+                <child>
+                  <object class="GtkAlignment" id="alignment2">
+                    <property name="visible">True</property>
+                    <property name="left_padding">12</property>
+                    <child>
+                      <object class="GtkEntry" id="entry1">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="invisible_char">&#x2022;</property>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+                <child type="label">
+                  <object class="GtkLabel" id="label2">
+                    <property name="visible">True</property>
+                    <property name="label" translatable="yes">_Variable:</property>
+                    <property name="use_markup">True</property>
+                    <property name="use_underline">True</property>
+                    <property name="mnemonic_widget">entry1</property>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="left_attach">2</property>
+                <property name="right_attach">3</property>
+                <property name="top_attach">1</property>
+                <property name="bottom_attach">2</property>
+                <property name="y_options">GTK_FILL</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkVBox" id="vbox1">
+                <property name="visible">True</property>
+                <property name="orientation">vertical</property>
+                <child>
+                  <object class="GtkFrame" id="frame3">
+                    <property name="visible">True</property>
+                    <property name="label_xalign">0</property>
+                    <child>
+                      <object class="GtkAlignment" id="alignment3">
+                        <property name="visible">True</property>
+                        <property name="left_padding">12</property>
+                        <child>
+                          <object class="GtkVButtonBox" id="vbuttonbox1">
+                            <property name="visible">True</property>
+                            <property name="orientation">vertical</property>
+                            <child>
+                              <object class="GtkCheckButton" id="curve">
+                                <property name="label" translatable="yes">_Display normal curve</property>
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="receives_default">False</property>
+                                <property name="use_underline">True</property>
+                                <property name="draw_indicator">True</property>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">False</property>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
+                          </object>
+                        </child>
+                      </object>
+                    </child>
+                    <child type="label">
+                      <object class="GtkLabel" id="label3">
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes">Display</property>
+                        <property name="use_markup">True</property>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">3</property>
+                <property name="top_attach">2</property>
+                <property name="bottom_attach">3</property>
+                <property name="y_options">GTK_FILL</property>
+                <property name="x_padding">5</property>
+                <property name="y_padding">2</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="PsppireVButtonBox" id="psppire-vbuttonbox1">
+            <property name="visible">True</property>
+            <property name="border_width">5</property>
+            <property name="orientation">vertical</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="pack_type">end</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+  </object>
+</interface>
diff --git a/src/ui/gui/psppire-dialog-action-barchart.c b/src/ui/gui/psppire-dialog-action-barchart.c
new file mode 100644 (file)
index 0000000..87b8fa1
--- /dev/null
@@ -0,0 +1,238 @@
+/* PSPPIRE - a graphical user interface for PSPP.
+   Copyright (C) 2015  Free Software Foundation
+
+   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 "psppire-dialog-action-barchart.h"
+#include "psppire-value-entry.h"
+
+#include "dialog-common.h"
+#include <ui/syntax-gen.h>
+#include "psppire-var-view.h"
+
+#include "psppire-dialog.h"
+#include "builder-wrapper.h"
+
+#include "psppire-dict.h"
+#include "libpspp/str.h"
+
+#include "language/stats/chart-category.h"
+
+static void
+psppire_dialog_action_barchart_class_init (PsppireDialogActionBarchartClass *class);
+
+G_DEFINE_TYPE (PsppireDialogActionBarchart, psppire_dialog_action_barchart, PSPPIRE_TYPE_DIALOG_ACTION);
+
+static gboolean
+dialog_state_valid (gpointer rd_)
+{
+  PsppireDialogActionBarchart *rd = PSPPIRE_DIALOG_ACTION_BARCHART (rd_);
+
+  if ( gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (rd->button_summary_func)) )
+    {
+      if (0 == g_strcmp0 ("", gtk_entry_get_text (GTK_ENTRY (rd->var))))
+       return FALSE;
+    }
+
+  if (0 == g_strcmp0 ("", gtk_entry_get_text (GTK_ENTRY (rd->variable_xaxis))))
+    return FALSE;
+
+  return TRUE;
+}
+
+static void
+refresh (PsppireDialogAction *rd_)
+{
+  PsppireDialogActionBarchart *rd = PSPPIRE_DIALOG_ACTION_BARCHART (rd_);
+
+  gtk_entry_set_text (GTK_ENTRY (rd->var), "");
+  gtk_entry_set_text (GTK_ENTRY (rd->variable_xaxis), "");
+  gtk_entry_set_text (GTK_ENTRY (rd->variable_cluster), "");
+
+  /* Set summary_func to true, then let it get unset again.
+     This ensures that the signal handler gets called.   */
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (rd->button_summary_func), TRUE);
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (rd->button_freq_func[0]), TRUE);
+                               
+  gtk_widget_set_sensitive (rd->combobox, FALSE);
+
+  gtk_combo_box_set_active (GTK_COMBO_BOX (rd->combobox), 0);
+}
+
+static void
+on_summary_toggle (PsppireDialogActionBarchart *act)
+{
+  gboolean status = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (act->button_summary_func));
+
+  gtk_widget_set_sensitive (act->summary_variables, status);
+  gtk_widget_set_sensitive (act->combobox, status);
+}
+
+static void
+populate_combo_model (GtkComboBox *cb)
+{
+  int i;
+  GtkListStore *list =  gtk_list_store_new (4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT);
+  GtkTreeIter iter;
+  GtkCellRenderer *renderer ;
+
+  for (i = 0; i < N_AG_FUNCS;  ++i)
+    {
+      const struct ag_func *af = ag_func + i;
+
+      if (af->arity == 0)
+       continue;
+
+      gtk_list_store_append (list, &iter);
+      gtk_list_store_set (list, &iter,
+                          0, af->description,
+                         1, af->name,
+                          -1);
+    }
+
+  renderer = gtk_cell_renderer_text_new ();
+  gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (cb), renderer, FALSE);
+
+  gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (cb), renderer, "text", 0);
+
+  gtk_combo_box_set_model (GTK_COMBO_BOX (cb), GTK_TREE_MODEL (list));
+  g_object_unref (list);
+}
+
+
+static void
+psppire_dialog_action_barchart_activate (GtkAction *a)
+{
+  PsppireDialogActionBarchart *act = PSPPIRE_DIALOG_ACTION_BARCHART (a);
+  PsppireDialogAction *pda = PSPPIRE_DIALOG_ACTION (a);
+
+  GtkBuilder *xml = builder_new ("barchart.ui");
+  pda->dialog = get_widget_assert (xml, "barchart-dialog");
+  pda->source = get_widget_assert (xml, "dict-view");
+
+  act->variable_xaxis = get_widget_assert (xml, "entry1");
+  act->variable_cluster = get_widget_assert (xml, "entry3");
+  act->var = get_widget_assert (xml, "entry2");
+  act->button_freq_func[0] = get_widget_assert (xml, "radiobutton-count");
+  act->button_freq_func[1] = get_widget_assert (xml, "radiobutton-percent");
+  act->button_freq_func[2] = get_widget_assert (xml, "radiobutton-cum-count");
+  act->button_freq_func[3] = get_widget_assert (xml, "radiobutton-cum-percent");
+  
+  act->button_summary_func = get_widget_assert (xml, "radiobutton3");
+  act->summary_variables = get_widget_assert (xml, "hbox1");
+  act->combobox = get_widget_assert (xml, "combobox1");
+
+  populate_combo_model (GTK_COMBO_BOX(act->combobox));
+  
+  g_object_unref (xml);
+
+  g_signal_connect_swapped (act->button_summary_func, "toggled",
+                           G_CALLBACK (on_summary_toggle), act);
+
+  psppire_dialog_action_set_refresh (pda, refresh);
+
+  psppire_dialog_action_set_valid_predicate (pda,
+                                       dialog_state_valid);
+
+  if (PSPPIRE_DIALOG_ACTION_CLASS (psppire_dialog_action_barchart_parent_class)->activate)
+    PSPPIRE_DIALOG_ACTION_CLASS (psppire_dialog_action_barchart_parent_class)->activate (pda);
+}
+
+static char *
+generate_syntax (PsppireDialogAction *a)
+{
+  PsppireDialogActionBarchart *rd = PSPPIRE_DIALOG_ACTION_BARCHART (a);
+  gchar *text;
+  const gchar *var_name_xaxis = gtk_entry_get_text (GTK_ENTRY (rd->variable_xaxis));
+  const gchar *var_name_cluster = gtk_entry_get_text (GTK_ENTRY (rd->variable_cluster));
+
+  GString *string = g_string_new ("GRAPH /BAR = ");
+
+  if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (rd->button_summary_func)))
+    {
+      GtkTreeIter iter;
+      if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (rd->combobox), &iter))
+       {
+         GValue value = {0};
+         GtkTreeModel *model = gtk_combo_box_get_model (GTK_COMBO_BOX (rd->combobox));
+         gtk_tree_model_get_value (model, &iter, 1, &value);
+         g_string_append (string, g_value_get_string (&value));
+         g_value_unset (&value);
+       }
+      g_string_append (string, " (");
+      g_string_append (string, gtk_entry_get_text (GTK_ENTRY (rd->var)));
+      g_string_append (string, ")");
+    }
+  else
+    {
+      int b;
+      for (b = 0; b < 4; ++b)
+       {
+         if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (rd->button_freq_func[b])))
+           break;
+       }
+      switch (b)
+       {
+       case 0:
+         g_string_append (string, "COUNT");
+         break;
+       case 1:
+         g_string_append (string, "PCT");
+         break;
+       case 2:
+         g_string_append (string, "CUFREQ");
+         break;
+       case 3:
+         g_string_append (string, "CUPCT");
+         break;
+       default:
+         g_assert_not_reached ();
+         break;
+       }
+    }
+
+  g_string_append (string, " BY ");
+  g_string_append (string, var_name_xaxis);
+
+  if (g_strcmp0 (var_name_cluster, ""))
+  {
+    g_string_append (string, " BY ");
+    g_string_append (string, var_name_cluster);
+  }
+  
+  g_string_append (string, ".\n");
+
+  text = string->str;
+
+  g_string_free (string, FALSE);
+
+  return text;
+}
+
+static void
+psppire_dialog_action_barchart_class_init (PsppireDialogActionBarchartClass *class)
+{
+  psppire_dialog_action_set_activation (class, psppire_dialog_action_barchart_activate);
+
+  PSPPIRE_DIALOG_ACTION_CLASS (class)->generate_syntax = generate_syntax;
+}
+
+
+static void
+psppire_dialog_action_barchart_init (PsppireDialogActionBarchart *act)
+{
+}
diff --git a/src/ui/gui/psppire-dialog-action-barchart.h b/src/ui/gui/psppire-dialog-action-barchart.h
new file mode 100644 (file)
index 0000000..4ebc8e9
--- /dev/null
@@ -0,0 +1,82 @@
+/* PSPPIRE - a graphical user interface for PSPP.
+   Copyright (C) 2015  Free Software Foundation
+
+   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 <glib-object.h>
+#include <glib.h>
+
+#include "psppire-dialog-action.h"
+
+#ifndef __PSPPIRE_DIALOG_ACTION_BARCHART_H__
+#define __PSPPIRE_DIALOG_ACTION_BARCHART_H__
+
+G_BEGIN_DECLS
+
+
+#define PSPPIRE_TYPE_DIALOG_ACTION_BARCHART (psppire_dialog_action_barchart_get_type ())
+
+#define PSPPIRE_DIALOG_ACTION_BARCHART(obj)    \
+                     (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+                                                 PSPPIRE_TYPE_DIALOG_ACTION_BARCHART, PsppireDialogActionBarchart))
+
+#define PSPPIRE_DIALOG_ACTION_BARCHART_CLASS(klass) \
+                     (G_TYPE_CHECK_CLASS_CAST ((klass), \
+                                PSPPIRE_TYPE_DIALOG_ACTION_BARCHART, \
+                                 PsppireDialogActionBarchartClass))
+
+
+#define PSPPIRE_IS_DIALOG_ACTION_BARCHART(obj) \
+                    (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PSPPIRE_TYPE_DIALOG_ACTION_BARCHART))
+
+#define PSPPIRE_IS_DIALOG_ACTION_BARCHART_CLASS(klass) \
+                     (G_TYPE_CHECK_CLASS_TYPE ((klass), PSPPIRE_TYPE_DIALOG_ACTION_BARCHART))
+
+
+#define PSPPIRE_DIALOG_ACTION_BARCHART_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+                                  PSPPIRE_TYPE_DIALOG_ACTION_BARCHART, \
+                                  PsppireDialogActionBarchartClass))
+
+typedef struct _PsppireDialogActionBarchart       PsppireDialogActionBarchart;
+typedef struct _PsppireDialogActionBarchartClass  PsppireDialogActionBarchartClass;
+
+
+struct _PsppireDialogActionBarchart
+{
+  PsppireDialogAction parent;
+
+  /*< private >*/
+
+  GtkWidget *variable_xaxis;
+  GtkWidget *variable_cluster;
+  GtkWidget *var;
+  GtkWidget *button_freq_func[4];
+  GtkWidget *button_summary_func;
+  GtkWidget *summary_variables;
+  GtkWidget *combobox;
+};
+
+
+struct _PsppireDialogActionBarchartClass
+{
+  PsppireDialogActionClass parent_class;
+};
+
+
+GType psppire_dialog_action_barchart_get_type (void) ;
+
+G_END_DECLS
+
+#endif /* __PSPPIRE_DIALOG_ACTION_BARCHART_H__ */
diff --git a/src/ui/gui/psppire-dialog-action-histogram.c b/src/ui/gui/psppire-dialog-action-histogram.c
new file mode 100644 (file)
index 0000000..5a57c2a
--- /dev/null
@@ -0,0 +1,128 @@
+/* PSPPIRE - a graphical user interface for PSPP.
+   Copyright (C) 2015  Free Software Foundation
+
+   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 "psppire-dialog-action-histogram.h"
+#include "psppire-value-entry.h"
+
+#include "dialog-common.h"
+#include <ui/syntax-gen.h>
+#include "psppire-var-view.h"
+
+#include "psppire-dialog.h"
+#include "builder-wrapper.h"
+
+#include "psppire-dict.h"
+#include "libpspp/str.h"
+
+static void
+psppire_dialog_action_histogram_class_init (PsppireDialogActionHistogramClass *class);
+
+G_DEFINE_TYPE (PsppireDialogActionHistogram, psppire_dialog_action_histogram, PSPPIRE_TYPE_DIALOG_ACTION);
+
+static gboolean
+dialog_state_valid (gpointer data)
+{
+  PsppireDialogActionHistogram *rd = data;
+
+  const gchar *var_name = gtk_entry_get_text (GTK_ENTRY (rd->variable));
+  const struct variable *var = psppire_dict_lookup_var (PSPPIRE_DIALOG_ACTION (rd)->dict, var_name);
+
+  if ( var == NULL)
+    return FALSE;
+
+
+  return TRUE;
+}
+
+static void
+refresh (PsppireDialogAction *rd_)
+{
+  PsppireDialogActionHistogram *rd = PSPPIRE_DIALOG_ACTION_HISTOGRAM (rd_);
+
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (rd->curve), FALSE);
+  gtk_entry_set_text (GTK_ENTRY (rd->variable), "");
+}
+
+static void
+psppire_dialog_action_histogram_activate (GtkAction *a)
+{
+  PsppireDialogActionHistogram *act = PSPPIRE_DIALOG_ACTION_HISTOGRAM (a);
+  PsppireDialogAction *pda = PSPPIRE_DIALOG_ACTION (a);
+
+  GtkBuilder *xml = builder_new ("histogram.ui");
+  pda->dialog = get_widget_assert (xml, "histogram-dialog");
+  pda->source = get_widget_assert (xml, "dict-view");
+
+  act->variable = get_widget_assert (xml, "entry1");
+  act->curve = get_widget_assert (xml, "curve");
+
+  g_object_unref (xml);
+
+  psppire_dialog_action_set_refresh (pda, refresh);
+
+  psppire_dialog_action_set_valid_predicate (pda,
+                                       dialog_state_valid);
+
+  if (PSPPIRE_DIALOG_ACTION_CLASS (psppire_dialog_action_histogram_parent_class)->activate)
+    PSPPIRE_DIALOG_ACTION_CLASS (psppire_dialog_action_histogram_parent_class)->activate (pda);
+}
+
+
+
+static char *
+generate_syntax (PsppireDialogAction *a)
+{
+  PsppireDialogActionHistogram *rd = PSPPIRE_DIALOG_ACTION_HISTOGRAM (a);
+  gchar *text;
+  const gchar *var_name = gtk_entry_get_text (GTK_ENTRY (rd->variable));
+  GString *string = g_string_new ("GRAPH /HISTOGRAM ");
+
+  if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (rd->curve)))
+    {
+      g_string_append (string, "(NORMAL)");
+    }
+
+  g_string_append (string, " = ");
+  g_string_append (string, var_name);
+
+  g_string_append (string, ".\n");
+
+  text = string->str;
+
+  g_string_free (string, FALSE);
+
+  return text;
+}
+
+static void
+psppire_dialog_action_histogram_class_init (PsppireDialogActionHistogramClass *class)
+{
+  GtkActionClass *action_class = GTK_ACTION_CLASS (class);
+
+  action_class->activate = psppire_dialog_action_histogram_activate;
+
+  PSPPIRE_DIALOG_ACTION_CLASS (class)->generate_syntax = generate_syntax;
+}
+
+
+static void
+psppire_dialog_action_histogram_init (PsppireDialogActionHistogram *act)
+{
+}
+
diff --git a/src/ui/gui/psppire-dialog-action-histogram.h b/src/ui/gui/psppire-dialog-action-histogram.h
new file mode 100644 (file)
index 0000000..a80910b
--- /dev/null
@@ -0,0 +1,78 @@
+/* PSPPIRE - a graphical user interface for PSPP.
+   Copyright (C) 2015  Free Software Foundation
+
+   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 <glib-object.h>
+#include <glib.h>
+
+#include "psppire-dialog-action.h"
+
+#ifndef __PSPPIRE_DIALOG_ACTION_HISTOGRAM_H__
+#define __PSPPIRE_DIALOG_ACTION_HISTOGRAM_H__
+
+G_BEGIN_DECLS
+
+
+#define PSPPIRE_TYPE_DIALOG_ACTION_HISTOGRAM (psppire_dialog_action_histogram_get_type ())
+
+#define PSPPIRE_DIALOG_ACTION_HISTOGRAM(obj)   \
+                     (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+                                                 PSPPIRE_TYPE_DIALOG_ACTION_HISTOGRAM, PsppireDialogActionHistogram))
+
+#define PSPPIRE_DIALOG_ACTION_HISTOGRAM_CLASS(klass) \
+                     (G_TYPE_CHECK_CLASS_CAST ((klass), \
+                                PSPPIRE_TYPE_DIALOG_ACTION_HISTOGRAM, \
+                                 PsppireDialogActionHistogramClass))
+
+
+#define PSPPIRE_IS_DIALOG_ACTION_HISTOGRAM(obj) \
+                    (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PSPPIRE_TYPE_DIALOG_ACTION_HISTOGRAM))
+
+#define PSPPIRE_IS_DIALOG_ACTION_HISTOGRAM_CLASS(klass) \
+                     (G_TYPE_CHECK_CLASS_TYPE ((klass), PSPPIRE_TYPE_DIALOG_ACTION_HISTOGRAM))
+
+
+#define PSPPIRE_DIALOG_ACTION_HISTOGRAM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+                                  PSPPIRE_TYPE_DIALOG_ACTION_HISTOGRAM, \
+                                  PsppireDialogActionHistogramClass))
+
+typedef struct _PsppireDialogActionHistogram       PsppireDialogActionHistogram;
+typedef struct _PsppireDialogActionHistogramClass  PsppireDialogActionHistogramClass;
+
+
+struct _PsppireDialogActionHistogram
+{
+  PsppireDialogAction parent;
+
+  /*< private >*/
+  gboolean dispose_has_run ;
+
+  GtkWidget *variable;
+  GtkWidget *curve;
+};
+
+
+struct _PsppireDialogActionHistogramClass
+{
+  PsppireDialogActionClass parent_class;
+};
+
+
+GType psppire_dialog_action_histogram_get_type (void) ;
+
+G_END_DECLS
+
+#endif /* __PSPPIRE_DIALOG_ACTION_HISTOGRAM_H__ */
diff --git a/src/ui/gui/psppire-dialog-action-scatterplot.c b/src/ui/gui/psppire-dialog-action-scatterplot.c
new file mode 100644 (file)
index 0000000..64017df
--- /dev/null
@@ -0,0 +1,129 @@
+/* PSPPIRE - a graphical user interface for PSPP.
+   Copyright (C) 2015  Free Software Foundation
+
+   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 "psppire-dialog-action-scatterplot.h"
+
+#include "psppire-var-view.h"
+
+#include "psppire-dialog.h"
+#include "builder-wrapper.h"
+#include "helper.h"
+
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+#define N_(msgid) msgid
+
+
+static void psppire_dialog_action_scatterplot_init            (PsppireDialogActionScatterplot      *act);
+static void psppire_dialog_action_scatterplot_class_init      (PsppireDialogActionScatterplotClass *class);
+
+G_DEFINE_TYPE (PsppireDialogActionScatterplot, psppire_dialog_action_scatterplot, PSPPIRE_TYPE_DIALOG_ACTION);
+
+
+static char *
+generate_syntax (PsppireDialogAction *act)
+{
+  PsppireDialogActionScatterplot *ow = PSPPIRE_DIALOG_ACTION_SCATTERPLOT (act);
+  gchar *text;
+  struct string dss;
+
+  ds_init_cstr (&dss, "GRAPH SCATTERPLOT(BIVARIATE) = ");
+
+  ds_put_cstr (&dss, gtk_entry_get_text (GTK_ENTRY (ow->y_axis)));
+  
+  ds_put_cstr (&dss, " WITH ");
+
+  ds_put_cstr (&dss, gtk_entry_get_text (GTK_ENTRY (ow->x_axis)));
+
+  ds_put_cstr (&dss, ".\n");
+
+  text = ds_steal_cstr (&dss);
+  ds_destroy (&dss);
+
+  return text;
+}
+
+
+static gboolean
+dialog_state_valid (gpointer data)
+{
+  PsppireDialogActionScatterplot *ow = PSPPIRE_DIALOG_ACTION_SCATTERPLOT (data);
+
+  const char *xvar = gtk_entry_get_text (GTK_ENTRY  (ow->x_axis));
+  const char *yvar = gtk_entry_get_text (GTK_ENTRY  (ow->y_axis));
+
+  if ( 0 == strcmp ("", xvar))
+    return FALSE;
+
+  if ( 0 == strcmp ("", yvar))
+    return FALSE;
+
+  
+  return TRUE;
+}
+
+static void
+refresh (PsppireDialogAction *rd_)
+{
+  PsppireDialogActionScatterplot *ow = PSPPIRE_DIALOG_ACTION_SCATTERPLOT (rd_);
+
+  gtk_entry_set_text (GTK_ENTRY (ow->x_axis), "");
+  gtk_entry_set_text (GTK_ENTRY (ow->y_axis), "");
+}
+
+
+
+static void
+psppire_dialog_action_scatterplot_activate (GtkAction *a)
+{
+  PsppireDialogAction *pda = PSPPIRE_DIALOG_ACTION (a);
+  PsppireDialogActionScatterplot *act = PSPPIRE_DIALOG_ACTION_SCATTERPLOT (a);
+
+  GtkBuilder *xml = builder_new ("scatterplot.ui");
+
+  pda->dialog = get_widget_assert   (xml, "scatterplot-dialog");
+  pda->source = get_widget_assert   (xml, "scatterplot-treeview1");
+
+  act->y_axis =  get_widget_assert (xml, "scatterplot-y-axis");
+  act->x_axis =  get_widget_assert (xml, "scatterplot-x-axis");
+
+  psppire_dialog_action_set_valid_predicate (pda, dialog_state_valid);
+  psppire_dialog_action_set_refresh (pda, refresh);
+
+  g_object_unref (xml);
+
+  if (PSPPIRE_DIALOG_ACTION_CLASS (psppire_dialog_action_scatterplot_parent_class)->activate)
+    PSPPIRE_DIALOG_ACTION_CLASS (psppire_dialog_action_scatterplot_parent_class)->activate (pda);
+}
+
+static void
+psppire_dialog_action_scatterplot_class_init (PsppireDialogActionScatterplotClass *class)
+{
+  GtkActionClass *action_class = GTK_ACTION_CLASS (class);
+
+  action_class->activate = psppire_dialog_action_scatterplot_activate;
+  PSPPIRE_DIALOG_ACTION_CLASS (class)->generate_syntax = generate_syntax;
+}
+
+
+static void
+psppire_dialog_action_scatterplot_init (PsppireDialogActionScatterplot *act)
+{
+}
diff --git a/src/ui/gui/psppire-dialog-action-scatterplot.h b/src/ui/gui/psppire-dialog-action-scatterplot.h
new file mode 100644 (file)
index 0000000..948ec3b
--- /dev/null
@@ -0,0 +1,78 @@
+/* PSPPIRE - a graphical user interface for PSPP.
+   Copyright (C) 2015  Free Software Foundation
+
+   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 <glib-object.h>
+#include <glib.h>
+
+#include "psppire-dialog-action.h"
+
+#ifndef __PSPPIRE_DIALOG_ACTION_SCATTERPLOT_H__
+#define __PSPPIRE_DIALOG_ACTION_SCATTERPLOT_H__
+
+G_BEGIN_DECLS
+
+
+#define PSPPIRE_TYPE_DIALOG_ACTION_SCATTERPLOT (psppire_dialog_action_scatterplot_get_type ())
+
+#define PSPPIRE_DIALOG_ACTION_SCATTERPLOT(obj) \
+                     (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+                                                 PSPPIRE_TYPE_DIALOG_ACTION_SCATTERPLOT, PsppireDialogActionScatterplot))
+
+#define PSPPIRE_DIALOG_ACTION_SCATTERPLOT_CLASS(klass) \
+                     (G_TYPE_CHECK_CLASS_CAST ((klass), \
+                                PSPPIRE_TYPE_DIALOG_ACTION_SCATTERPLOT, \
+                                 PsppireDialogActionScatterplotClass))
+
+
+#define PSPPIRE_IS_DIALOG_ACTION_SCATTERPLOT(obj) \
+                    (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PSPPIRE_TYPE_DIALOG_ACTION_SCATTERPLOT))
+
+#define PSPPIRE_IS_DIALOG_ACTION_SCATTERPLOT_CLASS(klass) \
+                     (G_TYPE_CHECK_CLASS_TYPE ((klass), PSPPIRE_TYPE_DIALOG_ACTION_SCATTERPLOT))
+
+
+#define PSPPIRE_DIALOG_ACTION_SCATTERPLOT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+                                  PSPPIRE_TYPE_DIALOG_ACTION_SCATTERPLOT, \
+                                  PsppireDialogActionScatterplotClass))
+
+typedef struct _PsppireDialogActionScatterplot       PsppireDialogActionScatterplot;
+typedef struct _PsppireDialogActionScatterplotClass  PsppireDialogActionScatterplotClass;
+
+
+struct _PsppireDialogActionScatterplot
+{
+  PsppireDialogAction parent;
+
+  /*< private >*/
+  gboolean dispose_has_run ;
+
+  GtkWidget *x_axis;
+  GtkWidget *y_axis;
+};
+
+
+struct _PsppireDialogActionScatterplotClass
+{
+  PsppireDialogActionClass parent_class;
+};
+
+
+GType psppire_dialog_action_scatterplot_get_type (void) ;
+
+G_END_DECLS
+
+#endif /* __PSPPIRE_DIALOG_ACTION_SCATTERPLOT_H__ */
diff --git a/src/ui/gui/scatterplot.ui b/src/ui/gui/scatterplot.ui
new file mode 100644 (file)
index 0000000..bada0a3
--- /dev/null
@@ -0,0 +1,223 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <requires lib="psppire" version="2054.17080"/>
+  <!-- interface-requires gtk+ 2.12 -->
+  <!-- interface-naming-policy project-wide -->
+  <object class="PsppireDialog" id="scatterplot-dialog">
+    <property name="can_focus">False</property>
+    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+    <property name="title" translatable="yes">Scatterplot</property>
+    <property name="modal">True</property>
+    <property name="help_page">GRAPH</property>
+    <child>
+      <object class="GtkHBox" id="dialog-hbox15">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+        <property name="spacing">2</property>
+        <child>
+          <object class="GtkAlignment" id="alignment2">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="top_padding">5</property>
+            <property name="bottom_padding">5</property>
+            <property name="left_padding">5</property>
+            <child>
+              <object class="GtkTable" id="table4">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="n_rows">2</property>
+                <property name="n_columns">3</property>
+                <property name="column_spacing">5</property>
+                <child>
+                  <object class="GtkVBox" id="vbox-x">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <child>
+                      <object class="GtkLabel" id="label-x-axis">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="xalign">0</property>
+                        <property name="label" translatable="yes">_X Axis:</property>
+                        <property name="use_underline">True</property>
+                        <property name="mnemonic_widget">scatterplot-x-axis</property>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">False</property>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkEntry" id="scatterplot-x-axis">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="invisible_char">●</property>
+                        <property name="primary_icon_activatable">False</property>
+                        <property name="secondary_icon_activatable">False</property>
+                        <property name="primary_icon_sensitive">True</property>
+                        <property name="secondary_icon_sensitive">True</property>
+                      </object>
+                      <packing>
+                        <property name="expand">True</property>
+                        <property name="fill">True</property>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="left_attach">2</property>
+                    <property name="right_attach">3</property>
+                    <property name="top_attach">1</property>
+                    <property name="bottom_attach">2</property>
+                    <property name="y_options"/>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkVBox" id="vbox-y">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <child>
+                      <object class="GtkLabel" id="label-y-axis">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="xalign">0</property>
+                        <property name="label" translatable="yes">_Y Axis:</property>
+                        <property name="use_underline">True</property>
+                        <property name="mnemonic_widget">scatterplot-y-axis</property>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">False</property>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkEntry" id="scatterplot-y-axis">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="invisible_char">●</property>
+                        <property name="primary_icon_activatable">False</property>
+                        <property name="secondary_icon_activatable">False</property>
+                        <property name="primary_icon_sensitive">True</property>
+                        <property name="secondary_icon_sensitive">True</property>
+                      </object>
+                      <packing>
+                        <property name="expand">True</property>
+                        <property name="fill">True</property>
+                        <property name="position">2</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="left_attach">2</property>
+                    <property name="right_attach">3</property>
+                    <property name="y_options">GTK_EXPAND</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkScrolledWindow" id="scrolledwindow2">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="hscrollbar_policy">never</property>
+                    <property name="vscrollbar_policy">automatic</property>
+                    <property name="shadow_type">etched-in</property>
+                    <child>
+                      <object class="PsppireDictView" id="scatterplot-treeview1">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="headers_visible">False</property>
+                        <property name="headers_clickable">False</property>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="bottom_attach">2</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkAlignment" id="alignment1">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="xscale">0</property>
+                    <property name="yscale">0</property>
+                    <child>
+                      <object class="PsppireSelector" id="scatterplot-selector-x">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="border_width">5</property>
+                        <property name="source_widget">scatterplot-treeview1</property>
+                        <property name="dest_widget">scatterplot-x-axis</property>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                    <property name="top_attach">1</property>
+                    <property name="bottom_attach">2</property>
+                    <property name="x_options">GTK_FILL</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkAlignment" id="alignment3">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="xscale">0</property>
+                    <property name="yscale">0</property>
+                    <child>
+                      <object class="PsppireSelector" id="scatterplot-selector-y">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="border_width">5</property>
+                        <property name="source_widget">scatterplot-treeview1</property>
+                        <property name="dest_widget">scatterplot-y-axis</property>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                    <property name="x_options">GTK_FILL</property>
+                  </packing>
+                </child>
+              </object>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">True</property>
+            <property name="fill">True</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="PsppireVButtonBox" id="psppire-vbuttonbox2">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <property name="border_width">5</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="pack_type">end</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+  </object>
+</interface>
index c8b21e69a9ffcff65ce2dcf904f5b60631991875..71c472d5487c153719740c1ea8a76ed4a8c2bf2f 100644 (file)
@@ -16,6 +16,7 @@
 #include "psppire-val-chooser.h"
 #include "psppire-checkbox-treeview.h"
 
+#include "psppire-dialog-action-barchart.h"
 #include "psppire-dialog-action-binomial.h"
 #include "psppire-dialog-action-chisquare.h"
 #include "psppire-dialog-action-compute.h"
@@ -27,6 +28,7 @@
 #include "psppire-dialog-action-flip.h"
 #include "psppire-dialog-action-factor.h"
 #include "psppire-dialog-action-frequencies.h"
+#include "psppire-dialog-action-histogram.h"
 #include "psppire-dialog-action-indep-samps.h"
 #include "psppire-dialog-action-k-related.h"
 #include "psppire-dialog-action-1sks.h"
@@ -41,6 +43,7 @@
 #include "psppire-dialog-action-reliability.h"
 #include "psppire-dialog-action-roc.h"
 #include "psppire-dialog-action-runs.h"
+#include "psppire-dialog-action-scatterplot.h"
 #include "psppire-dialog-action-sort.h"
 #include "psppire-dialog-action-tt1s.h"
 #include "psppire-dialog-action-two-sample.h"
@@ -70,6 +73,7 @@ preregister_widgets (void)
 
   psppire_dialog_action_1sks_get_type ();
   psppire_dialog_action_binomial_get_type ();
+  psppire_dialog_action_barchart_get_type ();
   psppire_dialog_action_chisquare_get_type ();
   psppire_dialog_action_compute_get_type ();
   psppire_dialog_action_correlation_get_type ();
@@ -80,6 +84,7 @@ preregister_widgets (void)
   psppire_dialog_action_factor_get_type ();
   psppire_dialog_action_flip_get_type ();
   psppire_dialog_action_frequencies_get_type ();
+  psppire_dialog_action_histogram_get_type ();
   psppire_dialog_action_logistic_get_type ();
   psppire_dialog_action_kmeans_get_type ();
   psppire_dialog_action_k_related_get_type ();
@@ -94,6 +99,7 @@ preregister_widgets (void)
   psppire_dialog_action_regression_get_type ();
   psppire_dialog_action_roc_get_type ();
   psppire_dialog_action_runs_get_type ();
+  psppire_dialog_action_scatterplot_get_type ();
   psppire_dialog_action_sort_get_type ();
   psppire_dialog_action_tt1s_get_type ();
   psppire_dialog_action_two_sample_get_type ();
index f1fc33d8a31309361d9b0df19e784879c86b5f0a..83055bbf2103c6e39d9c6b73c362b1f16c8dd313 100644 (file)
@@ -93,6 +93,8 @@ FREQUENCIES b.
 GLM c BY b.
 GRAPH /HISTOGRAM = b .
 GRAPH /SCATTERPLOT(BIVARIATE) = b with c by e .
+GRAPH /BAR (GROUPED) = MEAN(b) by c by e.
+GRAPH /BAR = COUNT BY  b.
 LIST.
 LOGISTIC REGRESSION q WITH b.
 MEANS c b.
index ae716a3b8d669a9b55f14b3eca7af5d8ad631469..e3dce9d53870f5aec33108ce4d7c7a97d88d3c8e 100644 (file)
@@ -163,3 +163,131 @@ graph
 AT_CHECK([pspp -o pspp.pdf null-hist.sps], [0], [ignore])
 dnl Ignore output -- this is just a no-crash check.
 AT_CLEANUP
+
+
+
+
+AT_SETUP([GRAPH barcharts])
+AT_CHECK([ln -s $top_srcdir/examples/physiology.sav .], [0])
+AT_CHECK([ln -s $top_srcdir/examples/repairs.sav .], [0])
+
+AT_DATA([barchart.sps], [dnl
+GET FILE="physiology.sav".
+
+GRAPH /BAR = COUNT BY SEX.
+
+GRAPH /BAR = MEAN(height) BY SEX.
+
+NEW FILE.
+
+GET FILE="repairs.sav".
+
+GRAPH /BAR = MEAN (mtbf) BY factory.
+
+COMPUTE  R = TRUNC(RV.UNIFORM(1,5)).
+
+GRAPH /BAR = MEAN (mtbf) BY factory BY R.
+])
+
+AT_CHECK([pspp -o pspp.pdf barchart.sps], [0], [ignore])
+dnl Ignore output -- this is just a no-crash check.
+
+AT_CLEANUP
+
+
+
+AT_SETUP([GRAPH barchart arity])
+
+AT_DATA([barchart.sps], [dnl
+data list notable list /x y z*.
+begin data
+1  1  3
+2  1  4
+3  1  3
+4  1  4
+5  .  3
+6  2  4
+7  2  3
+8  2  4
+9  2  3
+10  2  4
+end data.
+
+* This line is invalid
+GRAPH /BAR = COUNT(x) BY y.
+])
+
+AT_CHECK([pspp -o pspp.pdf barchart.sps], [1], [ignore])
+dnl Ignore output -- this is just a no-crash check.
+
+AT_CLEANUP
+
+
+
+
+AT_SETUP([GRAPH barchart bad syntax])
+
+AT_DATA([barchart.sps], [dnl
+data list notable list /x y z*.
+begin data
+1  1  3
+2  1  4
+3  1  3
+4  1  4
+5  .  3
+6  2  4
+7  2  3
+8  2  4
+9  2  3
+10  2  4
+end data.
+
+* This line is invalid
+GRAPH /BAR = SCROD BY y.
+])
+
+AT_CHECK([pspp -o pspp.pdf barchart.sps], [1], [ignore])
+dnl Ignore output -- this is just a no-crash check.
+
+AT_CLEANUP
+
+
+
+AT_SETUP([GRAPH barchart full])
+
+AT_DATA([barchart.sps], [dnl
+data list notable list /x y z*.
+begin data
+1  1  3
+2  1  4
+3  1  3
+4  1  4
+5  .  3
+6  2  4
+7  2  3
+8  2  4
+9  2  3
+10  2  4
+end data.
+
+* This line is invalid
+GRAPH /BAR = COUNT by z.
+GRAPH /BAR = CUFREQ by z.
+GRAPH /BAR = PCT by z.
+GRAPH /BAR = CUPCT by z.
+
+GRAPH /BAR = MEAN(y) BY z.
+GRAPH /BAR = SUM(y) BY z.
+GRAPH /BAR = MAXIMUM(y) BY z.
+GRAPH /BAR = MINIMUM(y) BY z.
+
+GRAPH /BAR = MEAN(y) BY z BY y.
+GRAPH /BAR = SUM(y) BY z BY y.
+GRAPH /BAR = MAXIMUM(y) BY z BY y.
+GRAPH /BAR = MINIMUM(y) BY z BY y.
+])
+
+AT_CHECK([pspp -o pspp.pdf barchart.sps], [0], [ignore])
+dnl Ignore output -- this is just a no-crash check.
+
+AT_CLEANUP
\ No newline at end of file