Changes since 0.8.4:
+ * The FREQUENCIES command can now generate barcharts.
+
* The FACTOR command can now perform PROMAX rotations.
* SPSS/PC+ system files are now supported on GET and other commands
[@{FREQ[(@var{y_max})],PERCENT[(@var{y_max})]@}] [@{NONORMAL,NORMAL@}]
/PIECHART=[MINIMUM(@var{x_min})] [MAXIMUM(@var{x_max})]
[@{FREQ,PERCENT@}] [@{NOMISSING,MISSING@}]
+ /BARCHART=[MINIMUM(@var{x_min})] [MAXIMUM(@var{x_max})]
+ [@{FREQ,PERCENT@}]
+
(These options are not currently implemented.)
- /BARCHART=@dots{}
/HBAR=@dots{}
/GROUPED=@dots{}
@end display
/*
PSPP - a program for statistical analysis.
- Copyright (C) 1997-9, 2000, 2007, 2009, 2010, 2011, 2014 Free Software Foundation, Inc.
+ Copyright (C) 1997-9, 2000, 2007, 2009, 2010, 2011, 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
#include "output/chart-item.h"
+#include "output/charts/barchart.h"
#include "output/charts/piechart.h"
#include "output/charts/plot-hist.h"
#include "output/tab.h"
int n_stats;
/* Histogram and pie chart settings. */
- struct frq_chart *hist, *pie;
+ struct frq_chart *hist, *pie, *bar;
};
const struct variable *var,
const struct freq_tab *frq_tab);
+static void do_barchart(const struct frq_chart *bar,
+ const struct variable *var,
+ const struct freq_tab *frq_tab);
+
static void dump_statistics (const struct frq_proc *frq,
const struct var_freqs *vf,
const struct variable *wv);
if (frq->pie)
do_piechart(frq->pie, vf->var, &vf->tab);
+ if (frq->bar)
+ do_barchart(frq->bar, vf->var, &vf->tab);
+
cleanup_freq_tab (vf);
}
}
double pie_max = DBL_MAX;
bool pie_missing = false;
+ double bar_min = -DBL_MAX;
+ double bar_max = DBL_MAX;
+ bool bar_freq = true;
+
double hi_min = -DBL_MAX;
double hi_max = DBL_MAX;
int hi_scale = FRQ_FREQ;
frq.hist = NULL;
frq.pie = NULL;
+ frq.bar = NULL;
/* Accept an optional, completely pointless "/VARIABLES=" */
}
sbc_piechart = true;
}
+ else if (lex_match_id (lexer, "BARCHART"))
+ {
+ lex_match (lexer, T_EQUALS);
+ while (lex_token (lexer) != T_ENDCMD
+ && lex_token (lexer) != T_SLASH)
+ {
+ if (lex_match_id (lexer, "MINIMUM"))
+ {
+ lex_force_match (lexer, T_LPAREN);
+ if (lex_force_num (lexer))
+ {
+ bar_min = lex_number (lexer);
+ lex_get (lexer);
+ }
+ lex_force_match (lexer, T_RPAREN);
+ }
+ else if (lex_match_id (lexer, "MAXIMUM"))
+ {
+ lex_force_match (lexer, T_LPAREN);
+ if (lex_force_num (lexer))
+ {
+ bar_max = lex_number (lexer);
+ lex_get (lexer);
+ }
+ lex_force_match (lexer, T_RPAREN);
+ }
+ else if (lex_match_id (lexer, "FREQ"))
+ {
+ if ( lex_match (lexer, T_LPAREN))
+ {
+ if (lex_force_num (lexer))
+ {
+ lex_number (lexer);
+ lex_get (lexer);
+ }
+ lex_force_match (lexer, T_RPAREN);
+ }
+ bar_freq = true;
+ }
+ else if (lex_match_id (lexer, "PERCENT"))
+ {
+ if ( lex_match (lexer, T_LPAREN))
+ {
+ if (lex_force_num (lexer))
+ {
+ lex_number (lexer);
+ lex_get (lexer);
+ }
+ lex_force_match (lexer, T_RPAREN);
+ }
+ bar_freq = false;
+ }
+ else
+ {
+ lex_error (lexer, NULL);
+ goto error;
+ }
+ }
+ sbc_barchart = true;
+ }
else if (lex_match_id (lexer, "MISSING"))
{
lex_match (lexer, T_EQUALS);
/* Figure out which charts the user requested. */
{
- if (sbc_barchart)
- msg (SW, _("Bar charts are not implemented."));
-
if (sbc_histogram)
{
struct frq_chart *hist;
frq.n_percentiles+=2;
}
+ if (sbc_barchart)
+ {
+ frq.bar = xmalloc (sizeof *frq.bar);
+ frq.bar->x_min = bar_min;
+ frq.bar->x_max = bar_max;
+ frq.bar->include_missing = true;
+ frq.bar->y_scale = bar_freq ? FRQ_FREQ : FRQ_PERCENT;
+ }
+
if (sbc_piechart)
{
struct frq_chart *pie;
The caller is responsible for freeing slices
*/
static struct slice *
-freq_tab_to_slice_array(const struct frq_chart *pie,
+freq_tab_to_slice_array(const struct frq_chart *catchart,
const struct freq_tab *frq_tab,
const struct variable *var,
int *n_slicesp)
struct slice *slices;
int n_slices;
int i;
+ double total = 0;
slices = xnmalloc (frq_tab->n_valid + frq_tab->n_missing, sizeof *slices);
n_slices = 0;
+
for (i = 0; i < frq_tab->n_valid; i++)
- n_slices += add_slice (pie, &frq_tab->valid[i], var, &slices[n_slices]);
+ {
+ const struct freq *f = &frq_tab->valid[i];
+ total += f->count;
+ if (f->count > catchart->x_max)
+ continue;
+
+ if (f->count < catchart->x_min)
+ continue;
+
+ n_slices += add_slice (catchart, f, var, &slices[n_slices]);
+ }
+
+ if (catchart->y_scale == FRQ_PERCENT)
+ for (i = 0; i < frq_tab->n_valid; i++)
+ {
+ slices[i].magnitude /= total;
+ slices[i].magnitude *= 100.00;
+ }
+
for (i = 0; i < frq_tab->n_missing; i++)
- n_slices += add_slice (pie, &frq_tab->missing[i], var, &slices[n_slices]);
+ n_slices += add_slice (catchart, &frq_tab->missing[i], var, &slices[n_slices]);
*n_slicesp = n_slices;
return slices;
free (slices);
}
+
+static void
+do_barchart(const struct frq_chart *bar, const struct variable *var,
+ const struct freq_tab *frq_tab)
+{
+ struct slice *slices;
+ int n_slices, i;
+
+ slices = freq_tab_to_slice_array (bar, frq_tab, var, &n_slices);
+
+ chart_item_submit (barchart_create (var_to_string (var),
+ (bar->y_scale == FRQ_FREQ) ? _("Count") : _("Percent"),
+ slices, n_slices));
+
+ for (i = 0; i < n_slices; i++)
+ ds_destroy (&slices[i].label);
+ free (slices);
+}
+
+
/* Calculates all the pertinent statistics for VF, putting them in array
D[]. */
static void
src/output/charts/boxplot.h \
src/output/charts/np-plot.c \
src/output/charts/np-plot.h \
+ src/output/charts/barchart.c \
+ src/output/charts/barchart.h \
src/output/charts/piechart.c \
src/output/charts/piechart.h \
src/output/charts/plot-hist.c \
src/output/cairo.h \
src/output/charts/boxplot-cairo.c \
src/output/charts/np-plot-cairo.c \
+ src/output/charts/barchart-cairo.c \
src/output/charts/piechart-cairo.c \
src/output/charts/plot-hist-cairo.c \
src/output/charts/roc-chart-cairo.c \
#include "output/charts/boxplot.h"
#include "output/charts/np-plot.h"
#include "output/charts/piechart.h"
+#include "output/charts/barchart.h"
#include "output/charts/plot-hist.h"
#include "output/charts/roc-chart.h"
#include "output/charts/spreadlevel-plot.h"
xrchart_draw_np_plot (chart_item, cr, &geom);
else if (is_piechart (chart_item))
xrchart_draw_piechart (chart_item, cr, &geom);
+ else if (is_barchart (chart_item))
+ xrchart_draw_barchart (chart_item, cr, &geom);
else if (is_roc_chart (chart_item))
xrchart_draw_roc (chart_item, cr, &geom);
else if (is_scree (chart_item))
--- /dev/null
+/* PSPP - a program for statistical analysis.
+ Copyright (C) 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
+ 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 "output/charts/barchart.h"
+#include "output/charts/piechart.h"
+
+#include <math.h>
+
+#include "output/cairo-chart.h"
+
+#include "gl/minmax.h"
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+
+
+static void
+draw_bar (cairo_t *cr, const struct xrchart_geometry *geom,
+ const struct barchart *bc, int bar)
+{
+ const double width =
+ (geom->axis[SCALE_ABSCISSA].data_max - geom->axis[SCALE_ABSCISSA].data_min)
+ /
+ (double) bc->n_bars ;
+
+ const double x_pos =
+ (geom->axis[SCALE_ABSCISSA].data_max - geom->axis[SCALE_ABSCISSA].data_min) *
+ bar
+ /
+ (double) bc->n_bars ;
+
+
+ double height = geom->axis[SCALE_ORDINATE].scale * bc->bars[bar].magnitude;
+
+ cairo_rectangle (cr,
+ geom->axis[SCALE_ABSCISSA].data_min + x_pos + width * 0.1,
+ geom->axis[SCALE_ORDINATE].data_min,
+ width * 0.8, height);
+ cairo_save (cr);
+ cairo_set_source_rgb (cr,
+ geom->fill_colour.red / 255.0,
+ geom->fill_colour.green / 255.0,
+ geom->fill_colour.blue / 255.0);
+ cairo_fill_preserve (cr);
+ cairo_restore (cr);
+ cairo_stroke (cr);
+
+ draw_tick (cr, geom, SCALE_ABSCISSA, true,
+ x_pos + width / 2.0, "%s", ds_cstr (&bc->bars[bar].label));
+}
+
+
+void
+xrchart_draw_barchart (const struct chart_item *chart_item, cairo_t *cr,
+ struct xrchart_geometry *geom)
+{
+ struct barchart *bc = to_barchart (chart_item);
+ int i;
+
+ xrchart_write_title (cr, geom, _("BARCHART"));
+
+ xrchart_write_ylabel (cr, geom, bc->ylabel);
+ xrchart_write_xlabel (cr, geom, chart_item_get_title (chart_item));
+
+ xrchart_write_yscale (cr, geom, 0, bc->largest);
+
+ for (i = 0; i < bc->n_bars; i++)
+ {
+ draw_bar (cr, geom, bc, i);
+ }
+}
+
--- /dev/null
+/* PSPP - a program for statistical analysis.
+ Copyright (C) 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
+ 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 "output/charts/barchart.h"
+#include "output/charts/piechart.h"
+
+#include <stdlib.h>
+
+#include "libpspp/cast.h"
+#include "libpspp/str.h"
+#include "output/chart-item-provider.h"
+
+#include "gl/xalloc.h"
+
+/* Creates and returns a chart that will render a barchart with
+ the given TITLE and the N_BARS described in BARS. */
+struct chart_item *
+barchart_create (const char *title, const char *ylabel, const struct slice *bars, int n_bars)
+{
+ struct barchart *bar;
+ int i;
+
+ bar = xmalloc (sizeof *bar);
+ chart_item_init (&bar->chart_item, &barchart_class, title);
+ bar->bars = xnmalloc (n_bars, sizeof *bar->bars);
+ bar->largest = 0;
+ bar->ylabel = strdup (ylabel);
+ for (i = 0; i < n_bars; i++)
+ {
+ const struct slice *src = &bars[i];
+ struct slice *dst = &bar->bars[i];
+
+ ds_init_string (&dst->label, &src->label);
+ dst->magnitude = src->magnitude;
+ if (dst->magnitude > bar->largest)
+ bar->largest = dst->magnitude;
+ }
+ bar->n_bars = n_bars;
+ return &bar->chart_item;
+}
+
+static void
+barchart_destroy (struct chart_item *chart_item)
+{
+ struct barchart *bar = to_barchart (chart_item);
+ int i;
+
+ for (i = 0; i < bar->n_bars; i++)
+ {
+ struct slice *slice = &bar->bars[i];
+ ds_destroy (&slice->label);
+ }
+ free (bar->ylabel);
+ free (bar->bars);
+ free (bar);
+}
+
+const struct chart_item_class barchart_class =
+ {
+ barchart_destroy
+ };
--- /dev/null
+/* PSPP - a program for statistical analysis.
+ Copyright (C) 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
+ 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/>. */
+
+#ifndef BARCHART_H
+#define BARCHART_H
+
+#include "libpspp/str.h"
+#include "output/chart-item.h"
+
+struct barchart
+ {
+ struct chart_item chart_item;
+ struct slice *bars;
+ int n_bars;
+ double largest;
+ char *ylabel;
+ };
+
+struct chart_item *barchart_create (const char *title, const char *ylabel,
+ const struct slice *, int n_bars);
+\f
+/* This boilerplate for barchart, a subclass of chart_item, was
+ autogenerated by mk-class-boilerplate. */
+
+#include <assert.h>
+#include "libpspp/cast.h"
+
+extern const struct chart_item_class barchart_class;
+
+/* Returns true if SUPER is a barchart, otherwise false. */
+static inline bool
+is_barchart (const struct chart_item *super)
+{
+ return super->class == &barchart_class;
+}
+
+/* Returns SUPER converted to barchart. SUPER must be a barchart, as
+ reported by is_barchart. */
+static inline struct barchart *
+to_barchart (const struct chart_item *super)
+{
+ assert (is_barchart (super));
+ return UP_CAST (super, struct barchart, chart_item);
+}
+
+/* Returns INSTANCE converted to chart_item. */
+static inline struct chart_item *
+barchart_super (const struct barchart *instance)
+{
+ return CONST_CAST (struct chart_item *, &instance->chart_item);
+}
+
+/* Increments INSTANCE's reference count and returns INSTANCE. */
+static inline struct barchart *
+barchart_ref (const struct barchart *instance)
+{
+ return to_barchart (chart_item_ref (&instance->chart_item));
+}
+
+/* Decrements INSTANCE's reference count, then destroys INSTANCE if
+ the reference count is now zero. */
+static inline void
+barchart_unref (struct barchart *instance)
+{
+ chart_item_unref (&instance->chart_item);
+}
+
+/* Returns true if INSTANCE's reference count is greater than 1,
+ false otherwise. */
+static inline bool
+barchart_is_shared (const struct barchart *instance)
+{
+ return chart_item_is_shared (&instance->chart_item);
+}
+
+static inline void
+barchart_submit (struct barchart *instance)
+{
+ chart_item_submit (&instance->chart_item);
+}
+\f
+#endif /* output/charts/barchart.h */
AT_CHECK([pspp --testing-mode -O format=csv histogram.sps], [0], [ignore])
AT_CLEANUP
+
+
+AT_SETUP([FREQUENCIES charts])
+AT_DATA([xxx.sps],[
+DATA LIST LIST /nationality (A10) religion (A20) gender (A8).
+BEGIN DATA.
+Australian Sikh Male
+Australian Sikh Male
+Australian Sikh Male
+Australian Sikh Male
+British Zoroastrian Female
+British Buddist Female
+British Buddist Female
+British Zoroastrian Female
+German Muslim Male
+German Christian Male
+German Christian Female
+German Christian Male
+German Zoroastrian Female
+German Sikh Female
+German Muslim Female
+German Pastafarian Female
+German "Jedi Knight" Female
+Belgian Sikh Male
+French Muslim Male
+French Muslim Male
+French Christian Male
+END DATA.
+
+
+FREQUENCIES /VARIABLES=religion nationality /BARCHART /PIECHART.
+])
+
+
+AT_CHECK([pspp -O format=csv xxx.sps], [0], [ignore])
+
+AT_CLEANUP