From 961577539cc6e149b30341f673c09cb3cd554272 Mon Sep 17 00:00:00 2001 From: Friedrich Beckmann Date: Fri, 24 Apr 2015 18:42:57 +0200 Subject: [PATCH] Allow data used by GRAPH /SCATTERPLOT to persist after the procedure has ended. Fixes bug #44877 --- src/language/stats/graph.c | 95 +++++++++++++++++++-------- src/output/charts/scatterplot-cairo.c | 12 ++-- src/output/charts/scatterplot.c | 24 +++---- src/output/charts/scatterplot.h | 18 +++-- 4 files changed, 99 insertions(+), 50 deletions(-) diff --git a/src/language/stats/graph.c b/src/language/stats/graph.c index a642be85a7..54d47d40fa 100644 --- a/src/language/stats/graph.c +++ b/src/language/stats/graph.c @@ -81,6 +81,13 @@ enum scatter_type ST_XYZ }; +/* Variable index for histogram case */ +enum + { + HG_IDX_X, + HG_IDX_WT + }; + struct exploratory_stats { double missing; @@ -118,6 +125,8 @@ struct graph enum chart_type chart_type; enum scatter_type scatter_type; const struct variable *byvar; + /* A caseproto that contains the plot data */ + struct caseproto *gr_proto; }; @@ -132,22 +141,22 @@ show_scatterplot (const struct graph *cmd, const struct casereader *input) if (cmd->byvar) { - ds_put_format (&title, _("%s vs. %s by %s"), - var_to_string (cmd->dep_vars[0]), + ds_put_format (&title, _("%s vs. %s by %s"), + var_to_string (cmd->dep_vars[0]), var_to_string (cmd->dep_vars[1]), - var_to_string (cmd->byvar)); + var_to_string (cmd->byvar)); } else { - ds_put_format (&title, _("%s vs. %s"), + ds_put_format (&title, _("%s vs. %s"), var_to_string (cmd->dep_vars[0]), - var_to_string (cmd->dep_vars[1])); + var_to_string (cmd->dep_vars[1])); } scatterplot = scatterplot_create (input, - cmd->dep_vars[0], - cmd->dep_vars[1], + var_to_string(cmd->dep_vars[0]), + var_to_string(cmd->dep_vars[1]), cmd->byvar, &byvar_overflow, ds_cstr (&title), @@ -158,12 +167,10 @@ show_scatterplot (const struct graph *cmd, const struct casereader *input) if (byvar_overflow) { - msg (MW, _("Maximum number of scatterplot categories reached." + msg (MW, _("Maximum number of scatterplot categories reached." "Your BY variable has too many distinct values." "The coloring of the plot will not be correct")); } - - } static void @@ -184,15 +191,14 @@ show_histogr (const struct graph *cmd, const struct casereader *input) } - for (reader=casereader_clone(input);(c = casereader_read (reader)) != NULL; case_unref (c)) + for (;(c = casereader_read (input)) != NULL; case_unref (c)) { - const struct variable *var = cmd->dep_vars[0]; - const double x = case_data (c, var)->f; - const double weight = dict_get_case_weight (cmd->dict,c,NULL); + const double x = case_data_idx (c, HG_IDX_X)->f; + const double weight = case_data_idx (c, HG_IDX_WT)->f; moments_pass_two (cmd->es[0].mom, x, weight); histogram_add (histogram, x, weight); } - casereader_destroy (reader); + casereader_destroy (input); { @@ -231,8 +237,7 @@ static void run_graph (struct graph *cmd, struct casereader *input) { struct ccase *c; - struct casereader *reader; - + struct casereader *reader, *writer; cmd->es = pool_calloc (cmd->pool,cmd->n_dep_vars,sizeof(struct exploratory_stats)); for(int v=0;vn_dep_vars;v++) @@ -253,10 +258,25 @@ run_graph (struct graph *cmd, struct casereader *input) NULL, NULL); - for (reader = casereader_clone (input); - (c = casereader_read (reader)) != NULL; case_unref (c)) + writer = autopaging_writer_create (cmd->gr_proto); + + /* The case data is copied to a new writer */ + /* The setup of the case depends on the Charttype */ + /* For Scatterplot x is assumed in dep_vars[0] */ + /* y is assumed in dep_vars[1] */ + /* For Histogram x is assumed in dep_vars[0] */ + assert(SP_IDX_X == 0 && SP_IDX_Y == 1 && HG_IDX_X == 0); + + for (;(c = casereader_read (input)) != NULL; case_unref (c)) { - const double weight = dict_get_case_weight (cmd->dict,c,NULL); + struct ccase *outcase = case_create (cmd->gr_proto); + 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) + value_copy (case_data_rw_idx (outcase, SP_IDX_BY), + case_data (c, cmd->byvar), + var_get_width (cmd->byvar)); for(int v=0;vn_dep_vars;v++) { const struct variable *var = cmd->dep_vars[v]; @@ -267,6 +287,8 @@ run_graph (struct graph *cmd, struct casereader *input) cmd->es[v].missing += weight; continue; } + /* Magically v value fits to SP_IDX_X, SP_IDX_Y, HG_IDX_X */ + case_data_rw_idx (outcase, v)->f = x; if (x > cmd->es[v].maximum) cmd->es[v].maximum = x; @@ -283,20 +305,18 @@ run_graph (struct graph *cmd, struct casereader *input) if (cmd->es[v].cmin > weight) cmd->es[v].cmin = weight; } + casewriter_write (writer,outcase); } - casereader_destroy (reader); + + reader = casewriter_make_reader (writer); switch (cmd->chart_type) { case CT_HISTOGRAM: - reader = casereader_clone (input); show_histogr (cmd,reader); - casereader_destroy (reader); break; case CT_SCATTERPLOT: - reader = casereader_clone (input); show_scatterplot (cmd,reader); - casereader_destroy (reader); break; default: NOT_REACHED (); @@ -304,7 +324,6 @@ run_graph (struct graph *cmd, struct casereader *input) }; casereader_destroy (input); - cleanup_exploratory_stats (cmd); } @@ -329,6 +348,7 @@ cmd_graph (struct lexer *lexer, struct dataset *ds) graph.chart_type = CT_NONE; graph.scatter_type = ST_BIVARIATE; graph.byvar = NULL; + graph.gr_proto = caseproto_create (); while (lex_token (lexer) != T_ENDCMD) { @@ -516,12 +536,27 @@ cmd_graph (struct lexer *lexer, struct dataset *ds) } } - if (graph.chart_type == CT_NONE) + switch (graph.chart_type) { + case CT_SCATTERPLOT: + /* 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)); + 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_NONE: lex_error_expecting (lexer,"HISTOGRAM","SCATTERPLOT",NULL); goto error; - } - + default: + NOT_REACHED (); + break; + }; { struct casegrouper *grouper; @@ -537,10 +572,12 @@ cmd_graph (struct lexer *lexer, struct dataset *ds) free (graph.dep_vars); pool_destroy (graph.pool); + caseproto_unref (graph.gr_proto); return CMD_SUCCESS; error: + caseproto_unref (graph.gr_proto); free (graph.dep_vars); pool_destroy (graph.pool); diff --git a/src/output/charts/scatterplot-cairo.c b/src/output/charts/scatterplot-cairo.c index 2c01429c4e..736d5e2ae7 100644 --- a/src/output/charts/scatterplot-cairo.c +++ b/src/output/charts/scatterplot-cairo.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2014 Free Software Foundation, Inc. + Copyright (C) 2014, 2015 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -52,8 +52,8 @@ xrchart_draw_scatterplot (const struct chart_item *chart_item, cairo_t *cr, xrchart_write_xscale (cr, geom, spc->x_min, spc->x_max); xrchart_write_yscale (cr, geom, spc->y_min, spc->y_max); xrchart_write_title (cr, geom, _("Scatterplot %s"), chart_item->title); - xrchart_write_xlabel (cr, geom, var_to_string(spc->xvar)); - xrchart_write_ylabel (cr, geom, var_to_string(spc->yvar)); + xrchart_write_xlabel (cr, geom, spc->xlabel); + xrchart_write_ylabel (cr, geom, spc->ylabel); cairo_save (cr); data = casereader_clone (spc->data); @@ -61,7 +61,7 @@ xrchart_draw_scatterplot (const struct chart_item *chart_item, cairo_t *cr, { if (spc->byvar) { - const union value *val = case_data (c,spc->byvar); + const union value *val = case_data_idx (c,SP_IDX_BY); for(i=0;iblue / 255.0); xrchart_datum (cr, geom, 0, - case_data (c, spc->xvar)->f, - case_data (c, spc->yvar)->f); + case_data_idx (c, SP_IDX_X)->f, + case_data_idx (c, SP_IDX_Y)->f); } casereader_destroy (data); cairo_restore (cr); diff --git a/src/output/charts/scatterplot.c b/src/output/charts/scatterplot.c index 920bc17367..2c3ffd683f 100644 --- a/src/output/charts/scatterplot.c +++ b/src/output/charts/scatterplot.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2014 Free Software Foundation, Inc. + Copyright (C) 2014, 2015 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -26,14 +26,11 @@ #include "gl/minmax.h" - -/* Creates a scatterplot - - The caller retains ownership of READER. */ +/* Creates a scatterplot */ struct scatterplot_chart * scatterplot_create (const struct casereader *reader, - const struct variable *xvar, - const struct variable *yvar, + const char *xlabel, + const char *ylabel, const struct variable *byvar, bool *byvar_overflow, const char *label, @@ -43,7 +40,7 @@ scatterplot_create (const struct casereader *reader, spc = xzalloc (sizeof *spc); chart_item_init (&spc->chart_item, &scatterplot_chart_class, label); - spc->data = casereader_clone (reader); + spc->data = reader; spc->y_min = ymin; spc->y_max = ymax; @@ -51,9 +48,10 @@ scatterplot_create (const struct casereader *reader, spc->x_min = xmin; spc->x_max = xmax; - spc->xvar = xvar; - spc->yvar = yvar; - spc->byvar = byvar; + spc->xlabel = xstrdup (xlabel); + spc->ylabel = xstrdup (ylabel); + spc->byvar = byvar != NULL ? var_clone (byvar) : NULL; + spc->byvar_overflow = byvar_overflow; return spc; @@ -64,6 +62,10 @@ scatterplot_chart_destroy (struct chart_item *chart_item) { struct scatterplot_chart *spc = to_scatterplot_chart (chart_item); casereader_destroy (spc->data); + free (spc->xlabel); + free (spc->ylabel); + if (spc->byvar) + var_destroy (spc->byvar); free (spc); } diff --git a/src/output/charts/scatterplot.h b/src/output/charts/scatterplot.h index e95562bbad..b752b7471f 100644 --- a/src/output/charts/scatterplot.h +++ b/src/output/charts/scatterplot.h @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2014 Free Software Foundation, Inc. + Copyright (C) 2014, 2015 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -19,12 +19,22 @@ #include "output/chart-item.h" +/* Indices for the scatterplot_proto members */ +enum + { + SP_IDX_X, /* x value */ + SP_IDX_Y, /* y value */ + SP_IDX_BY, /* graph category for xy plot */ + }; + /* A scatterplot. */ struct scatterplot_chart { struct chart_item chart_item; struct casereader *data; - const struct variable *xvar, *yvar, *byvar; + const struct variable *byvar; + const char *xlabel; + const char *ylabel; double y_min, y_max; double x_min, x_max; @@ -36,8 +46,8 @@ struct scatterplot_chart struct scatterplot_chart * scatterplot_create (const struct casereader *, - const struct variable *, - const struct variable *, + const char *xlabel, + const char *ylabel, const struct variable *, bool *, const char *label, -- 2.30.2