int n_dep_var,
const struct xfactor *fctr)
{
-#if 0
int v;
for (v = 0; v < n_dep_var; ++v)
{
- struct ll *ll;
- int f = 0;
- struct chart *ch = chart_create ();
+ const struct factor_result *result;
+ struct boxplot *boxplot;
double y_min = DBL_MAX;
double y_max = -DBL_MAX;
+ char *title;
- for (ll = ll_head (&fctr->result_list);
- ll != ll_null (&fctr->result_list);
- ll = ll_next (ll))
+ ll_for_each (result, struct factor_result, ll, &fctr->result_list)
{
+ struct factor_metrics *metrics = &result->metrics[v];
+ const struct ll_list *max_list = extrema_list (metrics->maxima);
+ const struct ll_list *min_list = extrema_list (metrics->minima);
const struct extremum *max, *min;
- const struct factor_result *result =
- ll_data (ll, struct factor_result, ll);
-
- const struct ll_list *max_list =
- extrema_list (result->metrics[v].maxima);
-
- const struct ll_list *min_list =
- extrema_list (result->metrics[v].minima);
if ( ll_is_empty (max_list))
{
continue;
}
- max = (const struct extremum *)
- ll_data (ll_head(max_list), struct extremum, ll);
-
- min = (const struct extremum *)
- ll_data (ll_head (min_list), struct extremum, ll);
+ max = ll_data (ll_head(max_list), struct extremum, ll);
+ min = ll_data (ll_head (min_list), struct extremum, ll);
y_max = MAX (y_max, max->value);
y_min = MIN (y_min, min->value);
}
- boxplot_draw_yscale (ch, y_max, y_min);
-
- if ( fctr->indep_var[0])
- chart_write_title (ch, _("Boxplot of %s vs. %s"),
+ if (fctr->indep_var[0])
+ title = xasprintf (_("Boxplot of %s vs. %s"),
var_to_string (dependent_var[v]),
- var_to_string (fctr->indep_var[0]) );
+ var_to_string (fctr->indep_var[0]));
else
- chart_write_title (ch, _("Boxplot of %s"),
- var_to_string (dependent_var[v]));
+ title = xasprintf (_("Boxplot of %s"),
+ var_to_string (dependent_var[v]));
+ boxplot = boxplot_create (y_min, y_max, title);
+ free (title);
- for (ll = ll_head (&fctr->result_list);
- ll != ll_null (&fctr->result_list);
- ll = ll_next (ll))
+ ll_for_each (result, struct factor_result, ll, &fctr->result_list)
{
- const struct factor_result *result =
- ll_data (ll, struct factor_result, ll);
-
- struct string str;
- const double box_width = (ch->data_right - ch->data_left)
- / (ll_count (&fctr->result_list) * 2.0 ) ;
-
- const double box_centre = (f++ * 2 + 1) * box_width + ch->data_left;
-
- ds_init_empty (&str);
+ struct factor_metrics *metrics = &result->metrics[v];
+ struct string str = DS_EMPTY_INITIALIZER;
factor_to_string_concise (fctr, result, &str);
-
- boxplot_draw_boxplot (ch,
- box_centre, box_width,
- (const struct box_whisker *)
- result->metrics[v].box_whisker,
- ds_cstr (&str));
-
+ boxplot_add_box (boxplot,
+ (struct box_whisker *) metrics->box_whisker,
+ ds_cstr (&str));
+ metrics->box_whisker = NULL;
ds_destroy (&str);
}
- chart_submit (ch);
+ chart_submit (boxplot_get_chart (boxplot));
}
-#endif
}
)
{
-#if 0
+ const struct factor_result *result;
int v;
- struct ll *ll;
- const struct ll_list *result_list = &fctr->result_list;
-
- for (ll = ll_head (result_list);
- ll != ll_null (result_list);
- ll = ll_next (ll))
+ ll_for_each (result, struct factor_result, ll, &fctr->result_list)
{
struct string title;
- struct chart *ch = chart_create ();
double y_min = DBL_MAX;
double y_max = -DBL_MAX;
-
- const struct factor_result *result =
- ll_data (ll, struct factor_result, ll);
-
- const double box_width = (ch->data_right - ch->data_left)
- / (n_dep_var * 2.0 ) ;
+ struct boxplot *boxplot;
for (v = 0; v < n_dep_var; ++v)
{
- const struct ll *max_ll =
- ll_head (extrema_list (result->metrics[v].maxima));
- const struct ll *min_ll =
- ll_head (extrema_list (result->metrics[v].minima));
-
- const struct extremum *max =
- (const struct extremum *) ll_data (max_ll, struct extremum, ll);
-
- const struct extremum *min =
- (const struct extremum *) ll_data (min_ll, struct extremum, ll);
+ const struct factor_metrics *metrics = &result->metrics[v];
+ const struct ll *max_ll = ll_head (extrema_list (metrics->maxima));
+ const struct ll *min_ll = ll_head (extrema_list (metrics->minima));
+ const struct extremum *max = ll_data (max_ll, struct extremum, ll);
+ const struct extremum *min = ll_data (min_ll, struct extremum, ll);
y_max = MAX (y_max, max->value);
y_min = MIN (y_min, min->value);
}
-
- boxplot_draw_yscale (ch, y_max, y_min);
-
ds_init_empty (&title);
factor_to_string (fctr, result, &title);
-
-#if 0
- ds_put_format (&title, "%s = ", var_get_name (fctr->indep_var[0]));
- var_append_value_name (fctr->indep_var[0], &result->value[0], &title);
-#endif
-
- chart_write_title (ch, "%s", ds_cstr (&title));
+ boxplot = boxplot_create (y_min, y_max, ds_cstr (&title));
ds_destroy (&title);
for (v = 0; v < n_dep_var; ++v)
{
- struct string str;
- const double box_centre = (v * 2 + 1) * box_width + ch->data_left;
-
- ds_init_empty (&str);
- ds_init_cstr (&str, var_get_name (dependent_var[v]));
-
- boxplot_draw_boxplot (ch,
- box_centre, box_width,
- (const struct box_whisker *) result->metrics[v].box_whisker,
- ds_cstr (&str));
-
- ds_destroy (&str);
+ struct factor_metrics *metrics = &result->metrics[v];
+ boxplot_add_box (boxplot,
+ (struct box_whisker *) metrics->box_whisker,
+ var_get_name (dependent_var[v]));
+ metrics->box_whisker = NULL;
}
- chart_submit (ch);
+ chart_submit (boxplot_get_chart (boxplot));
}
-#endif
}
if ( cmd.sbc_percentiles)
show_percentiles (dependent_vars, n_dependent_vars, factor);
- if (cmd.a_plot[XMN_PLT_BOXPLOT] &&
- cmd.cmp == XMN_GROUPS)
- show_boxplot_groups (dependent_vars, n_dependent_vars, factor);
-
-
- if (cmd.a_plot[XMN_PLT_BOXPLOT] &&
- cmd.cmp == XMN_VARIABLES)
- show_boxplot_variables (dependent_vars, n_dependent_vars,
- factor);
-
+ if (cmd.a_plot[XMN_PLT_BOXPLOT])
+ {
+ if (cmd.cmp == XMN_GROUPS)
+ show_boxplot_groups (dependent_vars, n_dependent_vars, factor);
+ else if (cmd.cmp == XMN_VARIABLES)
+ show_boxplot_variables (dependent_vars, n_dependent_vars, factor);
+ }
+
if (cmd.a_plot[XMN_PLT_HISTOGRAM])
show_histogram (dependent_vars, n_dependent_vars, factor);
noinst_LTLIBRARIES += src/output/charts/libcharts.la
chart_sources = \
+ src/output/charts/box-whisker.c \
+ src/output/charts/box-whisker.h \
src/output/charts/cartesian.c \
src/output/charts/cartesian.h \
src/output/charts/piechart.c \
#include <config.h>
+#include <output/charts/box-whisker.h>
+
#include <math.h>
#include <assert.h>
-#include <libpspp/misc.h>
-
-#include <output/charts/box-whisker.h>
-#include <output/charts/plot-chart.h>
-#include <output/chart.h>
+#include <libpspp/misc.h>
#include <math/chart-geometry.h>
#include <math/box-whisker.h>
+#include <output/chart.h>
+#include <output/chart-provider.h>
+#include <output/charts/plot-chart.h>
/* Draw a box-and-whiskers plot
*/
+struct box
+ {
+ struct box_whisker *bw;
+ char *label;
+ };
+
+struct boxplot
+ {
+ struct chart chart;
+ double y_min;
+ double y_max;
+ char *title;
+ struct box *boxes;
+ size_t n_boxes, boxes_allocated;
+ };
+
+static const struct chart_class boxplot_chart_class;
+
+struct boxplot *
+boxplot_create (double y_min, double y_max, const char *title)
+{
+ struct boxplot *boxplot = xmalloc (sizeof *boxplot);
+ chart_init (&boxplot->chart, &boxplot_chart_class);
+ boxplot->y_min = y_min;
+ boxplot->y_max = y_max;
+ boxplot->title = xstrdup (title);
+ boxplot->boxes = NULL;
+ boxplot->n_boxes = boxplot->boxes_allocated = 0;
+ return boxplot;
+}
+
+void
+boxplot_add_box (struct boxplot *boxplot,
+ struct box_whisker *bw, const char *label)
+{
+ struct box *box;
+ if (boxplot->n_boxes >= boxplot->boxes_allocated)
+ boxplot->boxes = x2nrealloc (boxplot->boxes, &boxplot->boxes_allocated,
+ sizeof *boxplot->boxes);
+ box = &boxplot->boxes[boxplot->n_boxes++];
+ box->bw = bw;
+ box->label = xstrdup (label);
+}
+
+struct chart *
+boxplot_get_chart (struct boxplot *boxplot)
+{
+ return &boxplot->chart;
+}
+
/* Draw an OUTLIER on the plot CH
* at CENTRELINE
*/
static void
-draw_case (struct chart *ch, double centreline,
+draw_case (plPlotter *lp, const struct chart_geometry *geom, double centreline,
const struct outlier *outlier)
{
#define MARKER_CIRCLE 4
#define MARKER_STAR 3
- pl_fmarker_r(ch->lp,
+ pl_fmarker_r(lp,
centreline,
- ch->data_bottom + (outlier->value - ch->y_min) * ch->ordinate_scale,
+ geom->data_bottom + (outlier->value - geom->y_min) * geom->ordinate_scale,
outlier->extreme ? MARKER_STAR : MARKER_CIRCLE,
20);
- pl_moverel_r(ch->lp, 10,0);
+ pl_moverel_r(lp, 10,0);
- pl_alabel_r(ch->lp, 'l', 'c', ds_cstr (&outlier->label));
+ pl_alabel_r(lp, 'l', 'c', ds_cstr (&outlier->label));
}
-
-void
-boxplot_draw_boxplot (struct chart *ch,
- double box_centre,
- double box_width,
- const struct box_whisker *bw,
- const char *name)
+static void
+boxplot_draw_box (plPlotter *lp, const struct chart_geometry *geom,
+ double box_centre,
+ double box_width,
+ const struct box_whisker *bw,
+ const char *name)
{
double whisker[2];
double hinge[3];
box_whisker_whiskers (bw, whisker);
box_whisker_hinges (bw, hinge);
- box_bottom = ch->data_bottom + (hinge[0] - ch->y_min ) * ch->ordinate_scale;
+ box_bottom = geom->data_bottom + (hinge[0] - geom->y_min ) * geom->ordinate_scale;
- box_top = ch->data_bottom + (hinge[2] - ch->y_min ) * ch->ordinate_scale;
+ box_top = geom->data_bottom + (hinge[2] - geom->y_min ) * geom->ordinate_scale;
- bottom_whisker = ch->data_bottom + (whisker[0] - ch->y_min) *
- ch->ordinate_scale;
+ bottom_whisker = geom->data_bottom + (whisker[0] - geom->y_min) *
+ geom->ordinate_scale;
- top_whisker = ch->data_bottom + (whisker[1] - ch->y_min) * ch->ordinate_scale;
+ top_whisker = geom->data_bottom + (whisker[1] - geom->y_min) * geom->ordinate_scale;
- pl_savestate_r(ch->lp);
+ pl_savestate_r(lp);
/* Draw the box */
- pl_savestate_r (ch->lp);
- pl_fillcolorname_r (ch->lp, ch->fill_colour);
- pl_filltype_r (ch->lp,1);
- pl_fbox_r (ch->lp,
+ pl_savestate_r (lp);
+ pl_fillcolorname_r (lp, geom->fill_colour);
+ pl_filltype_r (lp,1);
+ pl_fbox_r (lp,
box_left,
box_bottom,
box_right,
box_top);
- pl_restorestate_r (ch->lp);
+ pl_restorestate_r (lp);
/* Draw the median */
- pl_savestate_r (ch->lp);
- pl_linewidth_r (ch->lp, 5);
- pl_fline_r (ch->lp,
+ pl_savestate_r (lp);
+ pl_linewidth_r (lp, 5);
+ pl_fline_r (lp,
box_left,
- ch->data_bottom + (hinge[1] - ch->y_min) * ch->ordinate_scale,
+ geom->data_bottom + (hinge[1] - geom->y_min) * geom->ordinate_scale,
box_right,
- ch->data_bottom + (hinge[1] - ch->y_min) * ch->ordinate_scale);
- pl_restorestate_r (ch->lp);
+ geom->data_bottom + (hinge[1] - geom->y_min) * geom->ordinate_scale);
+ pl_restorestate_r (lp);
/* Draw the bottom whisker */
- pl_fline_r (ch->lp,
+ pl_fline_r (lp,
box_left,
bottom_whisker,
box_right,
bottom_whisker);
/* Draw top whisker */
- pl_fline_r (ch->lp,
+ pl_fline_r (lp,
box_left,
top_whisker,
box_right,
/* Draw centre line.
(bottom half) */
- pl_fline_r (ch->lp,
+ pl_fline_r (lp,
box_centre, bottom_whisker,
box_centre, box_bottom);
/* (top half) */
- pl_fline_r (ch->lp,
+ pl_fline_r (lp,
box_centre, top_whisker,
box_centre, box_top);
ll != ll_null (outliers); ll = ll_next (ll))
{
const struct outlier *outlier = ll_data (ll, struct outlier, ll);
- draw_case (ch, box_centre, outlier);
+ draw_case (lp, geom, box_centre, outlier);
}
/* Draw tick mark on x axis */
- draw_tick(ch, TICK_ABSCISSA, box_centre - ch->data_left, "%s", name);
+ draw_tick(lp, geom, TICK_ABSCISSA, box_centre - geom->data_left, "%s", name);
- pl_restorestate_r(ch->lp);
+ pl_restorestate_r(lp);
}
-void
-boxplot_draw_yscale (struct chart *ch, double y_max, double y_min)
+static void
+boxplot_draw_yscale (plPlotter *lp, struct chart_geometry *geom,
+ double y_max, double y_min)
{
double y_tick;
double d;
- if ( !ch )
- return ;
-
- ch->y_max = y_max;
- ch->y_min = y_min;
+ geom->y_max = y_max;
+ geom->y_min = y_min;
- y_tick = chart_rounded_tick (fabs(ch->y_max - ch->y_min) / 5.0);
+ y_tick = chart_rounded_tick (fabs (geom->y_max - geom->y_min) / 5.0);
- ch->y_min = (ceil( ch->y_min / y_tick ) - 1.0 ) * y_tick;
+ geom->y_min = (ceil (geom->y_min / y_tick) - 1.0) * y_tick;
- ch->y_max = ( floor( ch->y_max / y_tick ) + 1.0 ) * y_tick;
+ geom->y_max = (floor (geom->y_max / y_tick) + 1.0) * y_tick;
- ch->ordinate_scale = fabs(ch->data_top - ch->data_bottom)
- / fabs(ch->y_max - ch->y_min) ;
+ geom->ordinate_scale = (fabs (geom->data_top - geom->data_bottom)
+ / fabs (geom->y_max - geom->y_min));
/* Move to data bottom-left */
- pl_move_r(ch->lp,
- ch->data_left, ch->data_bottom);
+ pl_move_r (lp, geom->data_left, geom->data_bottom);
+
+ for (d = geom->y_min; d <= geom->y_max; d += y_tick)
+ draw_tick (lp, geom, TICK_ORDINATE,
+ (d - geom->y_min) * geom->ordinate_scale, "%g", d);
+}
+
+static void
+boxplot_chart_draw (const struct chart *chart, plPlotter *lp)
+{
+ const struct boxplot *boxplot = (struct boxplot *) chart;
+ struct chart_geometry geom;
+ double box_width;
+ size_t i;
- for ( d = ch->y_min; d <= ch->y_max ; d += y_tick )
+ chart_geometry_init (lp, &geom);
+ boxplot_draw_yscale (lp, &geom, boxplot->y_max, boxplot->y_min);
+ chart_write_title (lp, &geom, "%s", boxplot->title);
+
+ box_width = (geom.data_right - geom.data_left) / boxplot->n_boxes / 2.0;
+ for (i = 0; i < boxplot->n_boxes; i++)
+ {
+ const struct box *box = &boxplot->boxes[i];
+ const double box_centre = (i * 2 + 1) * box_width + geom.data_left;
+ boxplot_draw_box (lp, &geom, box_centre, box_width, box->bw, box->label);
+ }
+
+ chart_geometry_free (lp);
+}
+
+static void
+boxplot_chart_destroy (struct chart *chart)
+{
+ struct boxplot *boxplot = (struct boxplot *) chart;
+ size_t i;
+
+ free (boxplot->title);
+ for (i = 0; i < boxplot->n_boxes; i++)
{
- draw_tick (ch, TICK_ORDINATE, (d - ch->y_min ) * ch->ordinate_scale, "%g", d);
+ struct box *box = &boxplot->boxes[i];
+ struct statistic *statistic = &box->bw->parent.parent;
+ statistic->destroy (statistic);
+ free (box->label);
}
+ free (boxplot->boxes);
+ free (boxplot);
}
+
+static const struct chart_class boxplot_chart_class =
+ {
+ boxplot_chart_draw,
+ boxplot_chart_destroy
+ };
/* PSPP - a program for statistical analysis.
- Copyright (C) 2004 Free Software Foundation, Inc.
+ Copyright (C) 2004, 2009 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
#ifndef BOX_WHISKER_H
#define BOX_WHISKER_H
-struct chart ;
struct box_whisker;
-void boxplot_draw_boxplot (struct chart *ch,
- double box_centre,
- double box_width,
- const struct box_whisker *w,
- const char *name);
-
-
-void boxplot_draw_yscale (struct chart *ch , double y_max, double y_min);
+struct boxplot *boxplot_create (double y_min, double y_max, const char *title);
+void boxplot_add_box (struct boxplot *,
+ struct box_whisker *, const char *label);
+struct chart *boxplot_get_chart (struct boxplot *);
#endif