From 000e3e8c5818476c3afbc75fad9347aefb6e902a Mon Sep 17 00:00:00 2001 From: John Darrington Date: Sat, 4 Mar 2006 02:00:57 +0000 Subject: [PATCH] Added files in src/output --- src/output/automake.mk | 40 +++++ src/output/charts/ChangeLog | 3 + src/output/charts/Makefile | 2 + src/output/charts/automake.mk | 39 +++++ src/output/charts/barchart.c | 253 +++++++++++++++++++++++++++++ src/output/charts/barchart.h | 34 ++++ src/output/charts/box-whisker.c | 243 +++++++++++++++++++++++++++ src/output/charts/box-whisker.h | 48 ++++++ src/output/charts/cartesian.c | 196 ++++++++++++++++++++++ src/output/charts/cartesian.h | 52 ++++++ src/output/charts/chart-geometry.c | 25 +++ src/output/charts/chart-geometry.h | 24 +++ src/output/charts/dummy-chart.c | 117 +++++++++++++ src/output/charts/piechart.c | 210 ++++++++++++++++++++++++ src/output/charts/piechart.h | 34 ++++ src/output/charts/plot-chart.c | 173 ++++++++++++++++++++ src/output/charts/plot-chart.h | 71 ++++++++ src/output/charts/plot-hist.c | 183 +++++++++++++++++++++ src/output/charts/plot-hist.h | 43 +++++ 19 files changed, 1790 insertions(+) create mode 100644 src/output/automake.mk create mode 100644 src/output/charts/ChangeLog create mode 100644 src/output/charts/Makefile create mode 100644 src/output/charts/automake.mk create mode 100644 src/output/charts/barchart.c create mode 100644 src/output/charts/barchart.h create mode 100644 src/output/charts/box-whisker.c create mode 100644 src/output/charts/box-whisker.h create mode 100644 src/output/charts/cartesian.c create mode 100644 src/output/charts/cartesian.h create mode 100644 src/output/charts/chart-geometry.c create mode 100644 src/output/charts/chart-geometry.h create mode 100644 src/output/charts/dummy-chart.c create mode 100644 src/output/charts/piechart.c create mode 100644 src/output/charts/piechart.h create mode 100644 src/output/charts/plot-chart.c create mode 100644 src/output/charts/plot-chart.h create mode 100644 src/output/charts/plot-hist.c create mode 100644 src/output/charts/plot-hist.h diff --git a/src/output/automake.mk b/src/output/automake.mk new file mode 100644 index 00000000..0d3a1097 --- /dev/null +++ b/src/output/automake.mk @@ -0,0 +1,40 @@ +## Process this file with automake to produce Makefile.in -*- makefile -*- + + +include $(top_srcdir)/src/output/charts/automake.mk + + +src/output/%: AM_CPPFLAGS += \ + -I$(top_srcdir)/src/math \ + -I$(top_srcdir)/src/libpspp \ + -I$(top_srcdir)/src/data + +noinst_LIBRARIES += src/output/liboutput.a + + + + +output_sources = \ + src/output/ascii.c \ + src/output/font.h \ + src/output/groff-font.c \ + src/output/html.c \ + src/output/htmlP.h \ + src/output/output.c \ + src/output/output.h \ + src/output/postscript.c \ + src/output/manager.c \ + src/output/manager.h \ + src/output/chart.h \ + src/output/table.c src/output/table.h + + +if WITHCHARTS +src_output_liboutput_a_SOURCES = $(output_sources) src/output/chart.c + EXTRA_DIST += src/output/dummy-chart.c +else +src_output_liboutput_a_SOURCES = $(output_sources) src/output/dummy-chart.c + EXTRA_DIST += src/output/chart.c +endif + + diff --git a/src/output/charts/ChangeLog b/src/output/charts/ChangeLog new file mode 100644 index 00000000..4a96aeb9 --- /dev/null +++ b/src/output/charts/ChangeLog @@ -0,0 +1,3 @@ +Thu Mar 2 08:40:33 WST 2006 John Darrington + + * Moved files from src directory diff --git a/src/output/charts/Makefile b/src/output/charts/Makefile new file mode 100644 index 00000000..c1a052e8 --- /dev/null +++ b/src/output/charts/Makefile @@ -0,0 +1,2 @@ +all: + $(MAKE) -C /home/res/jmd/PSPP/pspp diff --git a/src/output/charts/automake.mk b/src/output/charts/automake.mk new file mode 100644 index 00000000..cf3a4099 --- /dev/null +++ b/src/output/charts/automake.mk @@ -0,0 +1,39 @@ +## Process this file with automake to produce Makefile.in -*- makefile -*- + + + +noinst_LIBRARIES += src/output/charts/libcharts.a + + +src/output/charts/%: AM_CPPFLAGS += \ + -I$(top_srcdir)/src/libpspp \ + -I$(top_srcdir)/src/output \ + -I$(top_srcdir)/src/data \ + -I$(top_srcdir)/src/math + +chart_sources = \ + src/output/charts/barchart.c \ + src/output/charts/barchart.h \ + 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 \ + src/output/charts/piechart.h \ + src/output/charts/plot-chart.h \ + src/output/charts/plot-chart.c \ + src/output/charts/plot-hist.c \ + src/output/charts/plot-hist.h + +if WITHCHARTS +src_output_charts_libcharts_a_SOURCES = \ + $(chart_sources) + +EXTRA_DIST += src/output/charts/dummy-chart.c +else +src_output_charts_libcharts_a_SOURCES = \ + src/output/charts/dummy-chart.c + +EXTRA_DIST += $(chart_sources) + +endif diff --git a/src/output/charts/barchart.c b/src/output/charts/barchart.c new file mode 100644 index 00000000..efa0ce82 --- /dev/null +++ b/src/output/charts/barchart.c @@ -0,0 +1,253 @@ +/* PSPP - computes sample statistics. + Copyright (C) 2004 Free Software Foundation, Inc. + Written by John Darrington + + 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 2 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, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. */ + + +#include +#include +#include +#include +#include "barchart.h" +#include "chart.h" +#include "plot-chart.h" + +#define CATAGORIES 6 +#define SUB_CATAGORIES 3 + +static const double x_min = 0; +static const double x_max = 15.0; + +static const char *cat_labels[] = + { + "Age", + "Intelligence", + "Wealth", + "Emotional", + "cat 5", + "cat 6", + "cat 7", + "cat 8", + "cat 9", + "cat 10", + "cat 11" + }; + + + + +/* Subcatagories */ +static const double data1[] = +{ + 28,83, + 34, + 29,13, + 9,4, + 3,3, + 2,0, + 1,0, + 0, + 1,1 +}; + + +static const double data2[] = +{ + 45,13, + 9,4, + 3,43, + 2,0, + 1,20, + 0,0, + 1,1, + 0,0 +}; + +static const double data3[] = + { + 23,18, + 0, 45,23, 9, 40, 24,4, 8 + }; + + +static const char subcat_name[]="Gender"; + + +struct subcat { + const double *data; + const char *label; +}; + +static const struct subcat sub_catagory[SUB_CATAGORIES] = + { + {data1, "male"}, + {data2, "female"}, + {data3, "47xxy"} + }; + + + +static const double y_min = 0; +static const double y_max = 120.0; +static const double y_tick = 20.0; + + + +static void write_legend(struct chart *chart) ; + + +void +draw_barchart(struct chart *ch, const char *title, + const char *xlabel, const char *ylabel, enum bar_opts opt) +{ + double d; + int i; + + double interval_size = fabs(ch->data_right - ch->data_left) / ( CATAGORIES ); + + double bar_width = interval_size / 1.1 ; + + double ordinate_scale = fabs(ch->data_top - ch->data_bottom) / + fabs(y_max - y_min) ; + + if ( opt != BAR_STACKED ) + bar_width /= SUB_CATAGORIES; + + /* Move to data bottom-left */ + pl_move_r(ch->lp, ch->data_left, ch->data_bottom); + + pl_savestate_r(ch->lp); + pl_filltype_r(ch->lp,1); + + /* Draw the data */ + for (i = 0 ; i < CATAGORIES ; ++i ) + { + int sc; + double ystart=0.0; + double x = i * interval_size; + + pl_savestate_r(ch->lp); + + draw_tick (ch, TICK_ABSCISSA, x + (interval_size/2 ), + cat_labels[i]); + + for(sc = 0 ; sc < SUB_CATAGORIES ; ++sc ) + { + + pl_savestate_r(ch->lp); + pl_fillcolorname_r(ch->lp,data_colour[sc]); + + switch ( opt ) + { + case BAR_GROUPED: + pl_fboxrel_r(ch->lp, + x + (sc * bar_width ), 0, + x + (sc + 1) * bar_width, + sub_catagory[sc].data[i] * ordinate_scale ); + break; + + + case BAR_STACKED: + + pl_fboxrel_r(ch->lp, + x, ystart, + x + bar_width, + ystart + sub_catagory[sc].data[i] * ordinate_scale ); + + ystart += sub_catagory[sc].data[i] * ordinate_scale ; + + break; + + default: + break; + } + pl_restorestate_r(ch->lp); + } + + pl_restorestate_r(ch->lp); + } + pl_restorestate_r(ch->lp); + + for ( d = y_min; d <= y_max ; d += y_tick ) + { + + draw_tick (ch, TICK_ORDINATE, + (d - y_min ) * ordinate_scale, "%g", d); + + } + + /* Write the abscissa label */ + pl_move_r(ch->lp,ch->data_left, ch->abscissa_top); + pl_alabel_r(ch->lp,0,'t',xlabel); + + + /* Write the ordinate label */ + pl_savestate_r(ch->lp); + pl_move_r(ch->lp,ch->data_bottom, ch->ordinate_right); + pl_textangle_r(ch->lp,90); + pl_alabel_r(ch->lp,0,0,ylabel); + pl_restorestate_r(ch->lp); + + + chart_write_title(ch, title); + + write_legend(ch); + + +} + + + + + +static void +write_legend(struct chart *chart) +{ + int sc; + + pl_savestate_r(chart->lp); + + pl_filltype_r(chart->lp,1); + + pl_move_r(chart->lp, chart->legend_left, + chart->data_bottom + chart->font_size * SUB_CATAGORIES * 1.5); + + pl_alabel_r(chart->lp,0,'b',subcat_name); + + for (sc = 0 ; sc < SUB_CATAGORIES ; ++sc ) + { + pl_fmove_r(chart->lp, + chart->legend_left, + chart->data_bottom + chart->font_size * sc * 1.5); + + pl_savestate_r(chart->lp); + pl_fillcolorname_r(chart->lp,data_colour[sc]); + pl_fboxrel_r (chart->lp, + 0,0, + chart->font_size, chart->font_size); + pl_restorestate_r(chart->lp); + + pl_fmove_r(chart->lp, + chart->legend_left + chart->font_size * 1.5, + chart->data_bottom + chart->font_size * sc * 1.5); + + pl_alabel_r(chart->lp,'l','b',sub_catagory[sc].label); + } + + + pl_restorestate_r(chart->lp); +} diff --git a/src/output/charts/barchart.h b/src/output/charts/barchart.h new file mode 100644 index 00000000..97fd758b --- /dev/null +++ b/src/output/charts/barchart.h @@ -0,0 +1,34 @@ +/* PSPP - computes sample statistics. + Copyright (C) 2004 Free Software Foundation, Inc. + Written by John Darrington + + 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 2 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, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. */ + +#ifndef BARCHART_H +#define BARCHART_H + +#include "chart.h" + +enum bar_opts { + BAR_GROUPED = 0, + BAR_STACKED, + BAR_RANGE +}; + +void draw_barchart(struct chart *ch, const char *title, + const char *xlabel, const char *ylabel, enum bar_opts opt); + +#endif diff --git a/src/output/charts/box-whisker.c b/src/output/charts/box-whisker.c new file mode 100644 index 00000000..17390664 --- /dev/null +++ b/src/output/charts/box-whisker.c @@ -0,0 +1,243 @@ +/* PSPP - computes sample statistics. + Copyright (C) 2004 Free Software Foundation, Inc. + Written by John Darrington + + 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 2 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, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. */ + + +#include "chart.h" +#include "chart-geometry.h" +#include +#include +#include "misc.h" + +#include "factor-stats.h" +#include "box-whisker.h" +#include "plot-chart.h" + + +/* Draw a box-and-whiskers plot +*/ + +/* Draw an outlier on the plot CH + * at CENTRELINE + * The outlier is in (*wvp)[idx] + * If EXTREME is non zero, then consider it to be an extreme + * value + */ +void +draw_outlier(struct chart *ch, double centreline, + struct weighted_value **wvp, + int idx, + short extreme); + + +void +draw_outlier(struct chart *ch, double centreline, + struct weighted_value **wvp, + int idx, + short extreme + ) +{ + char label[10]; + +#define MARKER_CIRCLE 4 +#define MARKER_STAR 3 + + pl_fmarker_r(ch->lp, + centreline, + ch->data_bottom + + (wvp[idx]->v.f - ch->y_min ) * ch->ordinate_scale, + extreme?MARKER_STAR:MARKER_CIRCLE, + 20); + + pl_moverel_r(ch->lp, 10,0); + + snprintf(label, 10, "%d", wvp[idx]->case_nos->num); + + pl_alabel_r(ch->lp, 'l', 'c', label); + +} + + +void +boxplot_draw_boxplot(struct chart *ch, + double box_centre, + double box_width, + struct metrics *m, + const char *name) +{ + double whisker[2]; + int i; + + const double *hinge = m->hinge; + struct weighted_value **wvp = m->wvp; + const int n_data = m->n_data; + + const double step = (hinge[2] - hinge[0]) * 1.5; + + + const double box_left = box_centre - box_width / 2.0; + + const double box_right = box_centre + box_width / 2.0; + + + const double box_bottom = + ch->data_bottom + ( hinge[0] - ch->y_min ) * ch->ordinate_scale; + + + const double box_top = + ch->data_bottom + ( hinge[2] - ch->y_min ) * ch->ordinate_scale; + + assert(m); + + /* Can't really draw a boxplot if there's no data */ + if ( n_data == 0 ) + return ; + + whisker[1] = hinge[2]; + whisker[0] = wvp[0]->v.f; + + for ( i = 0 ; i < n_data ; ++i ) + { + if ( hinge[2] + step > wvp[i]->v.f) + whisker[1] = wvp[i]->v.f; + + if ( hinge[0] - step > wvp[i]->v.f) + whisker[0] = wvp[i]->v.f; + + } + + { + const double bottom_whisker = + ch->data_bottom + ( whisker[0] - ch->y_min ) * ch->ordinate_scale; + + const double top_whisker = + ch->data_bottom + ( whisker[1] - ch->y_min ) * ch->ordinate_scale; + + + pl_savestate_r(ch->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, + box_left, + box_bottom, + box_right, + box_top); + + pl_restorestate_r(ch->lp); + + + + /* Draw the median */ + pl_savestate_r(ch->lp); + pl_linewidth_r(ch->lp,5); + pl_fline_r(ch->lp, + box_left, + ch->data_bottom + ( hinge[1] - ch->y_min ) * ch->ordinate_scale, + box_right, + ch->data_bottom + ( hinge[1] - ch->y_min ) * ch->ordinate_scale); + pl_restorestate_r(ch->lp); + + + /* Draw the bottom whisker */ + pl_fline_r(ch->lp, + box_left, + bottom_whisker, + box_right, + bottom_whisker); + + /* Draw top whisker */ + pl_fline_r(ch->lp, + box_left, + top_whisker, + box_right, + top_whisker); + + + + /* Draw centre line. + (bottom half) */ + pl_fline_r(ch->lp, + box_centre, bottom_whisker, + box_centre, box_bottom); + + /* (top half) */ + pl_fline_r(ch->lp, + box_centre, top_whisker, + box_centre, box_top); + } + + /* Draw outliers */ + for ( i = 0 ; i < n_data ; ++i ) + { + if ( wvp[i]->v.f >= hinge[2] + step ) + draw_outlier(ch, box_centre, wvp, i, + ( wvp[i]->v.f > hinge[2] + 2 * step ) + ); + + if ( wvp[i]->v.f <= hinge[0] - step ) + draw_outlier(ch, box_centre, wvp, i, + ( wvp[i]->v.f < hinge[0] - 2 * step ) + ); + } + + + /* Draw tick mark on x axis */ + draw_tick(ch, TICK_ABSCISSA, box_centre - ch->data_left, name); + + pl_restorestate_r(ch->lp); + +} + + + +void +boxplot_draw_yscale(struct chart *ch , double y_max, double y_min) +{ + double y_tick; + double d; + + if ( !ch ) + return ; + + ch->y_max = y_max; + ch->y_min = y_min; + + y_tick = chart_rounded_tick(fabs(ch->y_max - ch->y_min) / 5.0); + + ch->y_min = (ceil( ch->y_min / y_tick ) - 1.0 ) * y_tick; + + ch->y_max = ( floor( ch->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) ; + + + /* Move to data bottom-left */ + pl_move_r(ch->lp, + ch->data_left, ch->data_bottom); + + for ( d = ch->y_min; d <= ch->y_max ; d += y_tick ) + { + draw_tick (ch, TICK_ORDINATE, (d - ch->y_min ) * ch->ordinate_scale, "%g", d); + } + +} diff --git a/src/output/charts/box-whisker.h b/src/output/charts/box-whisker.h new file mode 100644 index 00000000..cf4d2e68 --- /dev/null +++ b/src/output/charts/box-whisker.h @@ -0,0 +1,48 @@ +/* PSPP - computes sample statistics. + Copyright (C) 2004 Free Software Foundation, Inc. + Written by John Darrington + + 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 2 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, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. */ + +#ifndef BOX_WHISKER_H +#define BOX_WHISKER_H + +#include + +struct chart ; + +/* Draw an outlier on the plot CH + * at CENTRELINE + * The outlier is in (*wvp)[idx] + * If EXTREME is non zero, then consider it to be an extreme + * value + */ +void draw_outlier(struct chart *ch, double centreline, + struct weighted_value **wvp, + int idx, + short extreme); + + +void boxplot_draw_boxplot(struct chart *ch, + double box_centre, + double box_width, + struct metrics *m, + const char *name); + + +void boxplot_draw_yscale(struct chart *ch , double y_max, double y_min); + +#endif diff --git a/src/output/charts/cartesian.c b/src/output/charts/cartesian.c new file mode 100644 index 00000000..1350a155 --- /dev/null +++ b/src/output/charts/cartesian.c @@ -0,0 +1,196 @@ +/* PSPP - computes sample statistics. + Copyright (C) 2004 Free Software Foundation, Inc. + Written by John Darrington + + 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 2 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, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. */ + + +#include +#include "chart.h" +#include +#include "plot-chart.h" +#include "cartesian.h" + + + +struct dataset +{ + int n_data; + const char *label; +}; + + +#define DATASETS 2 + +static const struct dataset dataset[DATASETS] = + { + { 13, "male"}, + { 11, "female"}, + }; + + + + +static void +write_legend(struct chart *chart, const char *heading, int n); + + + +/* Write the abscissa label */ +void +chart_write_xlabel(struct chart *ch, const char *label) +{ + if ( ! ch ) + return ; + + pl_savestate_r(ch->lp); + + pl_move_r(ch->lp,ch->data_left, ch->abscissa_top); + pl_alabel_r(ch->lp,0,'t',label); + + pl_restorestate_r(ch->lp); + +} + + + +/* Write the ordinate label */ +void +chart_write_ylabel(struct chart *ch, const char *label) +{ + if ( ! ch ) + return ; + + pl_savestate_r(ch->lp); + + pl_move_r(ch->lp, ch->data_bottom, ch->ordinate_right); + pl_textangle_r(ch->lp, 90); + pl_alabel_r(ch->lp, 0, 0, label); + + pl_restorestate_r(ch->lp); +} + + + +static void +write_legend(struct chart *chart, const char *heading, + int n) +{ + int ds; + + if ( ! chart ) + return ; + + + pl_savestate_r(chart->lp); + + pl_filltype_r(chart->lp,1); + + pl_move_r(chart->lp, chart->legend_left, + chart->data_bottom + chart->font_size * n * 1.5); + + pl_alabel_r(chart->lp,0,'b',heading); + + for (ds = 0 ; ds < n ; ++ds ) + { + pl_fmove_r(chart->lp, + chart->legend_left, + chart->data_bottom + chart->font_size * ds * 1.5); + + pl_savestate_r(chart->lp); + pl_fillcolorname_r(chart->lp,data_colour[ds]); + pl_fboxrel_r (chart->lp, + 0,0, + chart->font_size, chart->font_size); + pl_restorestate_r(chart->lp); + + pl_fmove_r(chart->lp, + chart->legend_left + chart->font_size * 1.5, + chart->data_bottom + chart->font_size * ds * 1.5); + + pl_alabel_r(chart->lp,'l','b',dataset[ds].label); + } + + + pl_restorestate_r(chart->lp); +} + + +/* Plot a data point */ +void +chart_datum(struct chart *ch, int dataset UNUSED, double x, double y) +{ + if ( ! ch ) + return ; + + { + const double x_pos = + (x - ch->x_min) * ch->abscissa_scale + ch->data_left ; + + const double y_pos = + (y - ch->y_min) * ch->ordinate_scale + ch->data_bottom ; + + pl_savestate_r(ch->lp); + + pl_fmarker_r(ch->lp, x_pos, y_pos, 6, 15); + + pl_restorestate_r(ch->lp); + } +} + +/* Draw a line with slope SLOPE and intercept INTERCEPT. + between the points limit1 and limit2. + If lim_dim is CHART_DIM_Y then the limit{1,2} are on the + y axis otherwise the x axis +*/ +void +chart_line(struct chart *ch, double slope, double intercept, + double limit1, double limit2, enum CHART_DIM lim_dim) +{ + double x1, y1; + double x2, y2 ; + + if ( ! ch ) + return ; + + + if ( lim_dim == CHART_DIM_Y ) + { + x1 = ( limit1 - intercept ) / slope ; + x2 = ( limit2 - intercept ) / slope ; + y1 = limit1; + y2 = limit2; + } + else + { + x1 = limit1; + x2 = limit2; + y1 = slope * x1 + intercept; + y2 = slope * x2 + intercept; + } + + y1 = (y1 - ch->y_min) * ch->ordinate_scale + ch->data_bottom ; + y2 = (y2 - ch->y_min) * ch->ordinate_scale + ch->data_bottom ; + x1 = (x1 - ch->x_min) * ch->abscissa_scale + ch->data_left ; + x2 = (x2 - ch->x_min) * ch->abscissa_scale + ch->data_left ; + + pl_savestate_r(ch->lp); + + pl_fline_r(ch->lp, x1, y1, x2, y2); + + pl_restorestate_r(ch->lp); + +} diff --git a/src/output/charts/cartesian.h b/src/output/charts/cartesian.h new file mode 100644 index 00000000..9f68ba14 --- /dev/null +++ b/src/output/charts/cartesian.h @@ -0,0 +1,52 @@ +/* PSPP - computes sample statistics. + Copyright (C) 2004 Free Software Foundation, Inc. + Written by John Darrington + + 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 2 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, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. */ + + + +#ifndef CARTESIAN_H +#define CARTESIAN_H + + +enum CHART_DIM + { + CHART_DIM_X, + CHART_DIM_Y + }; + + +/* Write the abscissa label */ +void chart_write_xlabel(struct chart *ch, const char *label); + + +/* Write the ordinate label */ +void chart_write_ylabel(struct chart *ch, const char *label); + +/* Plot a data point */ +void chart_datum(struct chart *ch, int dataset UNUSED, double x, double y); + +/* Draw a line with slope SLOPE and intercept INTERCEPT. + between the points limit1 and limit2. + If lim_dim is CHART_DIM_Y then the limit{1,2} are on the + y axis otherwise the x axis +*/ +void chart_line(struct chart *ch, double slope, double intercept, + double limit1, double limit2, enum CHART_DIM lim_dim); + + +#endif diff --git a/src/output/charts/chart-geometry.c b/src/output/charts/chart-geometry.c new file mode 100644 index 00000000..2a2a5ef7 --- /dev/null +++ b/src/output/charts/chart-geometry.c @@ -0,0 +1,25 @@ +/* PSPP - computes sample statistics. + Copyright (C) 2004 Free Software Foundation, Inc. + Written by John Darrington + + 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 2 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, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. */ + + +#include +#include + +#include "chart-geometry.h" + diff --git a/src/output/charts/chart-geometry.h b/src/output/charts/chart-geometry.h new file mode 100644 index 00000000..d2ed648c --- /dev/null +++ b/src/output/charts/chart-geometry.h @@ -0,0 +1,24 @@ +/* PSPP - computes sample statistics. + Copyright (C) 2004 Free Software Foundation, Inc. + Written by John Darrington + + 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 2 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, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. */ + + +#ifndef CHART_GEOMETRY_H +#define CHART_GEOMETRY_H + +#endif diff --git a/src/output/charts/dummy-chart.c b/src/output/charts/dummy-chart.c new file mode 100644 index 00000000..963015e6 --- /dev/null +++ b/src/output/charts/dummy-chart.c @@ -0,0 +1,117 @@ +/* PSPP - computes sample statistics. + Copyright (C) 2005 Free Software Foundation, Inc. + Written by John Darrington + + 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 2 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, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. */ + + +/* Stubs for plotting routines. + This module is linked only when charts are not supported */ + +#include "config.h" +#include "chart.h" +#include "plot-chart.h" +#include "cartesian.h" +#include + + +#ifndef NO_CHARTS +#error This file should be used only when compiling without charts. +#endif + +struct chart * +chart_create(void) +{ + return 0; +} + + +void +chart_write_title(struct chart *chart, const char *title, ...) +{ +} + + +void +chart_submit(struct chart *chart) +{ +} + + +void +chart_write_xscale(struct chart *ch, double min, double max, int ticks) +{ +} + + +void +chart_write_yscale(struct chart *ch, double smin, double smax, int ticks) +{ +} + + +void +chart_write_xlabel(struct chart *ch, const char *label) +{ +} + +void +chart_write_ylabel(struct chart *ch, const char *label) +{ +} + + +void +chart_line(struct chart *ch, double slope, double intercept, + double limit1, double limit2, enum CHART_DIM lim_dim) +{ +} + + +void +chart_datum(struct chart *ch, int dataset UNUSED, double x, double y) +{ +} + +struct normal_curve; + +void +histogram_plot(const gsl_histogram *hist, + const char *factorname, + const struct normal_curve *norm, short show_normal) +{ +} + +void +boxplot_draw_yscale(struct chart *ch , double y_max, double y_min) +{ +} + +void +boxplot_draw_boxplot(struct chart *ch, + double box_centre, + double box_width, + struct metrics *m, + const char *name) +{ +} + + + +void +piechart_plot(const char *title, const struct slice *slices, int n_slices) +{ +} diff --git a/src/output/charts/piechart.c b/src/output/charts/piechart.c new file mode 100644 index 00000000..3fceaf20 --- /dev/null +++ b/src/output/charts/piechart.c @@ -0,0 +1,210 @@ +/* PSPP - draws pie charts of sample statistics + +Copyright (C) 2004 Free Software Foundation, Inc. +Written by John Darrington + +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 2 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, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301, USA. */ + + +#include "config.h" +#include "piechart.h" +#include "chart.h" +#include +#include +#include +#include +#include "str.h" +#include "value-labels.h" +#include "misc.h" +#include "plot-chart.h" + +/* Pie charts of course need to know Pi :) */ +#ifndef M_PI +#define M_PI ( 22.0 / 7.0 ) +#endif + + + +/* Draw a single slice of the pie */ +static void +draw_segment(struct chart *ch, + double centre_x, double centre_y, + double radius, + double start_angle, double segment_angle, + const char *colour) ; + + + +/* Draw a piechart */ +void +piechart_plot(const char *title, const struct slice *slices, int n_slices) +{ + int i; + double total_magnetude=0; + + struct chart *ch = chart_create(); + + const double left_label = ch->data_left + + (ch->data_right - ch->data_left)/10.0; + + const double right_label = ch->data_right - + (ch->data_right - ch->data_left)/10.0; + + const double centre_x = (ch->data_right + ch->data_left ) / 2.0 ; + const double centre_y = (ch->data_top + ch->data_bottom ) / 2.0 ; + + const double radius = min( + 5.0 / 12.0 * (ch->data_top - ch->data_bottom), + 1.0 / 4.0 * (ch->data_right - ch->data_left) + ); + + + chart_write_title(ch, title); + + for (i = 0 ; i < n_slices ; ++i ) + total_magnetude += slices[i].magnetude; + + for (i = 0 ; i < n_slices ; ++i ) + { + static double angle=0.0; + + const double segment_angle = + slices[i].magnetude / total_magnetude * 2 * M_PI ; + + const double label_x = centre_x - + radius * sin(angle + segment_angle/2.0); + + const double label_y = centre_y + + radius * cos(angle + segment_angle/2.0); + + /* Fill the segment */ + draw_segment(ch, + centre_x, centre_y, radius, + angle, segment_angle, + data_colour[i]); + + /* Now add the labels */ + if ( label_x < centre_x ) + { + pl_line_r(ch->lp, label_x, label_y, + left_label, label_y ); + pl_moverel_r(ch->lp,0,5); + pl_alabel_r(ch->lp,0,0,slices[i].label); + } + else + { + pl_line_r(ch->lp, + label_x, label_y, + right_label, label_y + ); + pl_moverel_r(ch->lp,0,5); + pl_alabel_r(ch->lp,'r',0,slices[i].label); + } + + angle += segment_angle; + + } + + /* Draw an outline to the pie */ + pl_filltype_r(ch->lp,0); + pl_fcircle_r (ch->lp, centre_x, centre_y, radius); + + chart_submit(ch); +} + +static void +fill_segment(struct chart *ch, + double x0, double y0, + double radius, + double start_angle, double segment_angle) ; + + +/* Fill a segment with the current fill colour */ +static void +fill_segment(struct chart *ch, + double x0, double y0, + double radius, + double start_angle, double segment_angle) +{ + + const double start_x = x0 - radius * sin(start_angle); + const double start_y = y0 + radius * cos(start_angle); + + const double stop_x = + x0 - radius * sin(start_angle + segment_angle); + + const double stop_y = + y0 + radius * cos(start_angle + segment_angle); + + assert(segment_angle <= 2 * M_PI); + assert(segment_angle >= 0); + + if ( segment_angle > M_PI ) + { + /* Then we must draw it in two halves */ + fill_segment(ch, x0, y0, radius, start_angle, segment_angle / 2.0 ); + fill_segment(ch, x0, y0, radius, start_angle + segment_angle / 2.0, + segment_angle / 2.0 ); + } + else + { + pl_move_r(ch->lp, x0, y0); + + pl_cont_r(ch->lp, stop_x, stop_y); + pl_cont_r(ch->lp, start_x, start_y); + + pl_arc_r(ch->lp, + x0, y0, + stop_x, stop_y, + start_x, start_y + ); + + pl_endpath_r(ch->lp); + } +} + + + +/* Draw a single slice of the pie */ +static void +draw_segment(struct chart *ch, + double x0, double y0, + double radius, + double start_angle, double segment_angle, + const char *colour) +{ + const double start_x = x0 - radius * sin(start_angle); + const double start_y = y0 + radius * cos(start_angle); + + pl_savestate_r(ch->lp); + + pl_savestate_r(ch->lp); + pl_colorname_r(ch->lp, colour); + + pl_pentype_r(ch->lp,1); + pl_filltype_r(ch->lp,1); + + fill_segment(ch, x0, y0, radius, start_angle, segment_angle); + pl_restorestate_r(ch->lp); + + /* Draw line dividing segments */ + pl_pentype_r(ch->lp, 1); + pl_fline_r(ch->lp, x0, y0, start_x, start_y); + + + pl_restorestate_r(ch->lp); +} + diff --git a/src/output/charts/piechart.h b/src/output/charts/piechart.h new file mode 100644 index 00000000..c09b4876 --- /dev/null +++ b/src/output/charts/piechart.h @@ -0,0 +1,34 @@ +/* PSPP - draws pie charts of sample statistics + +Copyright (C) 2004 Free Software Foundation, Inc. +Written by John Darrington + +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 2 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, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301, USA. */ + +#ifndef PIECHART_H +#define PIECHART_H + +struct slice { + const char *label; + double magnetude; +}; + +/* Draw a piechart */ +void piechart_plot(const char *title, + const struct slice *slices, int n_slices); + +#endif + diff --git a/src/output/charts/plot-chart.c b/src/output/charts/plot-chart.c new file mode 100644 index 00000000..f965a6fe --- /dev/null +++ b/src/output/charts/plot-chart.c @@ -0,0 +1,173 @@ +/* PSPP - computes sample statistics. + Copyright (C) 2004 Free Software Foundation, Inc. + Written by John Darrington + + 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 2 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, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "chart-geometry.h" +#include "plot-chart.h" +#include "str.h" +#include "alloc.h" +#include "manager.h" +#include "output.h" +#include "plot-chart.h" + +const char *data_colour[] = { + "brown", + "red", + "orange", + "yellow", + "green", + "blue", + "violet", + "grey", + "pink" +}; + + + +/* Draw a tick mark at position + If label is non zero, then print it at the tick mark +*/ +void +draw_tick(struct chart *chart, + enum tick_orientation orientation, + double position, + const char *label, ...) +{ + const int tickSize = 10; + + assert(chart); + + pl_savestate_r(chart->lp); + + pl_move_r(chart->lp, chart->data_left, chart->data_bottom); + + if ( orientation == TICK_ABSCISSA ) + pl_flinerel_r(chart->lp, position, 0, position, -tickSize); + else if (orientation == TICK_ORDINATE ) + pl_flinerel_r(chart->lp, 0, position, -tickSize, position); + else + assert(0); + + if ( label ) { + char buf[10]; + va_list ap; + va_start(ap,label); + vsnprintf(buf,10,label,ap); + + if ( orientation == TICK_ABSCISSA ) + pl_alabel_r(chart->lp, 'c','t', buf); + else if (orientation == TICK_ORDINATE ) + { + if ( fabs(position) < DBL_EPSILON ) + pl_moverel_r(chart->lp, 0, 10); + + pl_alabel_r(chart->lp, 'r','c', buf); + } + + va_end(ap); + } + + pl_restorestate_r(chart->lp); +} + + +/* Write the title on a chart*/ +void +chart_write_title(struct chart *chart, const char *title, ...) +{ + va_list ap; + char buf[100]; + + if ( ! chart ) + return ; + + pl_savestate_r(chart->lp); + pl_ffontsize_r(chart->lp,chart->font_size * 1.5); + pl_move_r(chart->lp,chart->data_left, chart->title_bottom); + + va_start(ap,title); + vsnprintf(buf,100,title,ap); + pl_alabel_r(chart->lp,0,0,buf); + va_end(ap); + + pl_restorestate_r(chart->lp); +} + + +/* Set the scale for the abscissa */ +void +chart_write_xscale(struct chart *ch, double min, double max, int ticks) +{ + double x; + + const double tick_interval = + chart_rounded_tick( (max - min) / (double) ticks); + + assert ( ch ); + + + ch->x_max = ceil( max / tick_interval ) * tick_interval ; + ch->x_min = floor ( min / tick_interval ) * tick_interval ; + + + ch->abscissa_scale = fabs(ch->data_right - ch->data_left) / + fabs(ch->x_max - ch->x_min); + + for(x = ch->x_min ; x <= ch->x_max; x += tick_interval ) + { + draw_tick (ch, TICK_ABSCISSA, + (x - ch->x_min) * ch->abscissa_scale, "%g", x); + } + +} + + +/* Set the scale for the ordinate */ +void +chart_write_yscale(struct chart *ch, double smin, double smax, int ticks) +{ + double y; + + const double tick_interval = + chart_rounded_tick( (smax - smin) / (double) ticks); + + if ( !ch ) + return; + + ch->y_max = ceil ( smax / tick_interval ) * tick_interval ; + ch->y_min = floor ( smin / tick_interval ) * tick_interval ; + + ch->ordinate_scale = + fabs(ch->data_top - ch->data_bottom) / fabs(ch->y_max - ch->y_min) ; + + for(y = ch->y_min ; y <= ch->y_max; y += tick_interval ) + { + draw_tick (ch, TICK_ORDINATE, + (y - ch->y_min) * ch->ordinate_scale, "%g", y); + } +} diff --git a/src/output/charts/plot-chart.h b/src/output/charts/plot-chart.h new file mode 100644 index 00000000..ffcf3b01 --- /dev/null +++ b/src/output/charts/plot-chart.h @@ -0,0 +1,71 @@ +/* PSPP - computes sample statistics. + Copyright (C) 2004 Free Software Foundation, Inc. + Written by John Darrington + + 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 2 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, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. */ + +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "chart-geometry.h" +#include "chart.h" +#include "str.h" +#include "alloc.h" +#include "manager.h" +#include "output.h" + + +#ifndef PLOT_CHART_H +#define PLOT_CHART_H + + +extern const char *data_colour[]; + +enum tick_orientation { + TICK_ABSCISSA=0, + TICK_ORDINATE +}; + + +/* Draw a tick mark at position + If label is non zero, then print it at the tick mark +*/ +void draw_tick(struct chart *chart, + enum tick_orientation orientation, + double position, + const char *label, ...); + + +/* Write the title on a chart*/ +void chart_write_title(struct chart *chart, const char *title, ...); + + +/* Set the scale for the abscissa */ +void chart_write_xscale(struct chart *ch, double min, double max, int ticks); + + +/* Set the scale for the ordinate */ +void chart_write_yscale(struct chart *ch, double smin, double smax, int ticks); + + +#endif diff --git a/src/output/charts/plot-hist.c b/src/output/charts/plot-hist.c new file mode 100644 index 00000000..68c0a6a8 --- /dev/null +++ b/src/output/charts/plot-hist.c @@ -0,0 +1,183 @@ +/* PSPP - computes sample statistics. + Copyright (C) 2004 Free Software Foundation, Inc. + Written by John Darrington + + 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 2 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, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. */ + + +#include + +#include +#include "plot-hist.h" +#include "plot-chart.h" +#include +#include +#include +#include +#include +#include "hash.h" +#include "variable.h" +#include "chart.h" + +#include "gettext.h" +#define _(msgid) gettext (msgid) + +/* Write the legend of the chart */ +void +histogram_write_legend(struct chart *ch, const struct normal_curve *norm) +{ + char buf[100]; + if ( !ch ) + return ; + + pl_savestate_r(ch->lp); + + sprintf(buf,"N = %.2f",norm->N); + pl_move_r(ch->lp, ch->legend_left, ch->data_bottom); + pl_alabel_r(ch->lp,0,'b',buf); + + sprintf(buf,"Mean = %.1f",norm->mean); + pl_fmove_r(ch->lp,ch->legend_left,ch->data_bottom + ch->font_size * 1.5); + pl_alabel_r(ch->lp,0,'b',buf); + + sprintf(buf,"Std. Dev = %.2f",norm->stddev); + pl_fmove_r(ch->lp,ch->legend_left,ch->data_bottom + ch->font_size * 1.5 * 2); + pl_alabel_r(ch->lp,0,'b',buf); + + pl_restorestate_r(ch->lp); +} + +static void hist_draw_bar(struct chart *ch, const gsl_histogram *hist, int bar); + + +static void +hist_draw_bar(struct chart *ch, const gsl_histogram *hist, int bar) +{ + if ( !ch ) + return ; + + + { + double upper; + double lower; + double height; + + const size_t bins = gsl_histogram_bins(hist); + const double x_pos = (ch->data_right - ch->data_left) * bar / (double) bins ; + const double width = (ch->data_right - ch->data_left) / (double) bins ; + + + assert ( 0 == gsl_histogram_get_range(hist, bar, &lower, &upper)); + + assert( upper >= lower); + + height = gsl_histogram_get(hist, bar) * + (ch->data_top - ch->data_bottom) / gsl_histogram_max_val(hist); + + pl_savestate_r(ch->lp); + pl_move_r(ch->lp,ch->data_left, ch->data_bottom); + pl_fillcolorname_r(ch->lp, ch->fill_colour); + pl_filltype_r(ch->lp,1); + + + pl_fboxrel_r(ch->lp, + x_pos, 0, + x_pos + width, height); + + pl_restorestate_r(ch->lp); + + { + char buf[5]; + snprintf(buf,5,"%g",(upper + lower) / 2.0); + draw_tick(ch, TICK_ABSCISSA, + x_pos + width / 2.0, buf); + } + } +} + + + + +void +histogram_plot(const gsl_histogram *hist, + const char *factorname, + const struct normal_curve *norm, short show_normal) +{ + int i; + int bins; + + struct chart *ch; + + ch = chart_create(); + chart_write_title(ch, _("HISTOGRAM")); + + chart_write_ylabel(ch, _("Frequency")); + chart_write_xlabel(ch, factorname); + + if ( ! hist ) /* If this happens, probably all values are SYSMIS */ + { + chart_submit(ch); + return ; + } + else + { + bins = gsl_histogram_bins(hist); + } + + chart_write_yscale(ch, 0, gsl_histogram_max_val(hist), 5); + + for ( i = 0 ; i < bins ; ++i ) + hist_draw_bar(ch, hist, i); + + histogram_write_legend(ch, norm); + + if ( show_normal ) + { + /* Draw the normal curve */ + + double d ; + double x_min, x_max, not_used ; + double abscissa_scale ; + double ordinate_scale ; + double range ; + + gsl_histogram_get_range(hist, 0, &x_min, ¬_used); + range = not_used - x_min; + gsl_histogram_get_range(hist, bins - 1, ¬_used, &x_max); + assert(range == x_max - not_used); + + abscissa_scale = (ch->data_right - ch->data_left) / (x_max - x_min); + ordinate_scale = (ch->data_top - ch->data_bottom) / + gsl_histogram_max_val(hist) ; + + pl_move_r(ch->lp, ch->data_left, ch->data_bottom); + for( d = ch->data_left; + d <= ch->data_right ; + d += (ch->data_right - ch->data_left) / 100.0) + { + const double x = (d - ch->data_left) / abscissa_scale + x_min ; + const double y = norm->N * range * + gsl_ran_gaussian_pdf(x - norm->mean, norm->stddev); + + pl_fcont_r(ch->lp, d, ch->data_bottom + y * ordinate_scale); + + } + pl_endpath_r(ch->lp); + + } + chart_submit(ch); +} + diff --git a/src/output/charts/plot-hist.h b/src/output/charts/plot-hist.h new file mode 100644 index 00000000..071145dd --- /dev/null +++ b/src/output/charts/plot-hist.h @@ -0,0 +1,43 @@ +/* PSPP - computes sample statistics. + Copyright (C) 2004 Free Software Foundation, Inc. + Written by John Darrington + + 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 2 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, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. */ + +#ifndef PLOT_HIST_H +#define PLOT_HIST_H + +#include +#include + + +struct normal_curve +{ + double N ; + double mean ; + double stddev ; +}; +struct chart; + +/* Write the legend of the chart */ +void histogram_write_legend(struct chart *ch, const struct normal_curve *norm); + +void histogram_plot(const gsl_histogram *hist, + const char *factorname, + const struct normal_curve *norm, short show_normal); + + +#endif -- 2.30.2