Added files in src/output
authorJohn Darrington <john@darrington.wattle.id.au>
Sat, 4 Mar 2006 02:00:57 +0000 (02:00 +0000)
committerJohn Darrington <john@darrington.wattle.id.au>
Sat, 4 Mar 2006 02:00:57 +0000 (02:00 +0000)
19 files changed:
src/output/automake.mk [new file with mode: 0644]
src/output/charts/ChangeLog [new file with mode: 0644]
src/output/charts/Makefile [new file with mode: 0644]
src/output/charts/automake.mk [new file with mode: 0644]
src/output/charts/barchart.c [new file with mode: 0644]
src/output/charts/barchart.h [new file with mode: 0644]
src/output/charts/box-whisker.c [new file with mode: 0644]
src/output/charts/box-whisker.h [new file with mode: 0644]
src/output/charts/cartesian.c [new file with mode: 0644]
src/output/charts/cartesian.h [new file with mode: 0644]
src/output/charts/chart-geometry.c [new file with mode: 0644]
src/output/charts/chart-geometry.h [new file with mode: 0644]
src/output/charts/dummy-chart.c [new file with mode: 0644]
src/output/charts/piechart.c [new file with mode: 0644]
src/output/charts/piechart.h [new file with mode: 0644]
src/output/charts/plot-chart.c [new file with mode: 0644]
src/output/charts/plot-chart.h [new file with mode: 0644]
src/output/charts/plot-hist.c [new file with mode: 0644]
src/output/charts/plot-hist.h [new file with mode: 0644]

diff --git a/src/output/automake.mk b/src/output/automake.mk
new file mode 100644 (file)
index 0000000..0d3a109
--- /dev/null
@@ -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 (file)
index 0000000..4a96aeb
--- /dev/null
@@ -0,0 +1,3 @@
+Thu Mar  2 08:40:33 WST 2006 John Darrington <john@darrington.wattle.id.au>
+       
+       * Moved files from src directory
diff --git a/src/output/charts/Makefile b/src/output/charts/Makefile
new file mode 100644 (file)
index 0000000..c1a052e
--- /dev/null
@@ -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 (file)
index 0000000..cf3a409
--- /dev/null
@@ -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 (file)
index 0000000..efa0ce8
--- /dev/null
@@ -0,0 +1,253 @@
+/* PSPP - computes sample statistics.
+   Copyright (C) 2004 Free Software Foundation, Inc.
+   Written by John Darrington <john@darrington.wattle.id.au>
+
+   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 <stdio.h>
+#include <plot.h>
+#include <stdarg.h>
+#include <math.h>
+#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 (file)
index 0000000..97fd758
--- /dev/null
@@ -0,0 +1,34 @@
+/* PSPP - computes sample statistics.
+   Copyright (C) 2004 Free Software Foundation, Inc.
+   Written by John Darrington <john@darrington.wattle.id.au>
+
+   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 (file)
index 0000000..1739066
--- /dev/null
@@ -0,0 +1,243 @@
+/* PSPP - computes sample statistics.
+   Copyright (C) 2004 Free Software Foundation, Inc.
+   Written by John Darrington <john@darrington.wattle.id.au>
+
+   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 <math.h>
+#include <assert.h>
+#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 (file)
index 0000000..cf4d2e6
--- /dev/null
@@ -0,0 +1,48 @@
+/* PSPP - computes sample statistics.
+   Copyright (C) 2004 Free Software Foundation, Inc.
+   Written by John Darrington <john@darrington.wattle.id.au>
+
+   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 <config.h>
+
+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 (file)
index 0000000..1350a15
--- /dev/null
@@ -0,0 +1,196 @@
+/* PSPP - computes sample statistics.
+   Copyright (C) 2004 Free Software Foundation, Inc.
+   Written by John Darrington <john@darrington.wattle.id.au>
+
+   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 <math.h>
+#include "chart.h"
+#include <assert.h>
+#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 (file)
index 0000000..9f68ba1
--- /dev/null
@@ -0,0 +1,52 @@
+/* PSPP - computes sample statistics.
+   Copyright (C) 2004 Free Software Foundation, Inc.
+   Written by John Darrington <john@darrington.wattle.id.au>
+
+   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 (file)
index 0000000..2a2a5ef
--- /dev/null
@@ -0,0 +1,25 @@
+/* PSPP - computes sample statistics.
+   Copyright (C) 2004 Free Software Foundation, Inc.
+   Written by John Darrington <john@darrington.wattle.id.au>
+
+   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 <math.h>
+#include <float.h>
+
+#include "chart-geometry.h"
+
diff --git a/src/output/charts/chart-geometry.h b/src/output/charts/chart-geometry.h
new file mode 100644 (file)
index 0000000..d2ed648
--- /dev/null
@@ -0,0 +1,24 @@
+/* PSPP - computes sample statistics.
+   Copyright (C) 2004 Free Software Foundation, Inc.
+   Written by John Darrington <john@darrington.wattle.id.au>
+
+   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 (file)
index 0000000..963015e
--- /dev/null
@@ -0,0 +1,117 @@
+/* PSPP - computes sample statistics.
+   Copyright (C) 2005 Free Software Foundation, Inc.
+   Written by John Darrington <john@darrington.wattle.id.au>
+
+   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 <gsl/gsl_histogram.h>
+
+
+#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 (file)
index 0000000..3fceaf2
--- /dev/null
@@ -0,0 +1,210 @@
+/* PSPP - draws pie charts of sample statistics
+
+Copyright (C) 2004 Free Software Foundation, Inc.
+Written by John Darrington <john@darrington.wattle.id.au>
+
+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 <float.h>
+#include <assert.h>
+#include <math.h>
+#include <stdio.h>
+#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 (file)
index 0000000..c09b487
--- /dev/null
@@ -0,0 +1,34 @@
+/* PSPP - draws pie charts of sample statistics
+
+Copyright (C) 2004 Free Software Foundation, Inc.
+Written by John Darrington <john@darrington.wattle.id.au>
+
+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 (file)
index 0000000..f965a6f
--- /dev/null
@@ -0,0 +1,173 @@
+/* PSPP - computes sample statistics.
+   Copyright (C) 2004 Free Software Foundation, Inc.
+   Written by John Darrington <john@darrington.wattle.id.au>
+
+   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 <stdio.h>
+#include <plot.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdio.h>
+#include <float.h>
+#include <assert.h>
+#include <math.h>
+
+#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 (file)
index 0000000..ffcf3b0
--- /dev/null
@@ -0,0 +1,71 @@
+/* PSPP - computes sample statistics.
+   Copyright (C) 2004 Free Software Foundation, Inc.
+   Written by John Darrington <john@darrington.wattle.id.au>
+
+   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 <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdio.h>
+#include <float.h>
+#include <assert.h>
+#include <math.h>
+
+
+#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 (file)
index 0000000..68c0a6a
--- /dev/null
@@ -0,0 +1,183 @@
+/* PSPP - computes sample statistics.
+   Copyright (C) 2004 Free Software Foundation, Inc.
+   Written by John Darrington <john@darrington.wattle.id.au>
+
+   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 <stdio.h>
+#include "plot-hist.h"
+#include "plot-chart.h"
+#include <plot.h>
+#include <math.h>
+#include <gsl/gsl_histogram.h>
+#include <gsl/gsl_randist.h>
+#include <assert.h>
+#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, &not_used);
+    range = not_used - x_min;
+    gsl_histogram_get_range(hist, bins - 1, &not_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 (file)
index 0000000..071145d
--- /dev/null
@@ -0,0 +1,43 @@
+/* PSPP - computes sample statistics.
+   Copyright (C) 2004 Free Software Foundation, Inc.
+   Written by John Darrington <john@darrington.wattle.id.au>
+
+   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 <config.h>
+#include <gsl/gsl_histogram.h>
+
+
+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