Changed all the licence notices in all the files.
[pspp-builds.git] / src / frequencies.q
index 9a69e9723d18618febdd55f27976adf67a7c6f37..d5e669e1652ceb9479596a44aa81a8d74362917b 100644 (file)
@@ -14,8 +14,8 @@
 
    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., 59 Temple Place - Suite 330, Boston, MA
-   02111-1307, USA. */
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA. */
 
 /*
   TODO:
 #include "error.h"
 #include <math.h>
 #include <stdlib.h>
+#include <gsl/gsl_histogram.h>
+
 #include "alloc.h"
 #include "bitvector.h"
 #include "case.h"
+#include "dictionary.h"
 #include "hash.h"
 #include "pool.h"
 #include "command.h"
@@ -48,6 +51,7 @@
 #include "vfm.h"
 #include "settings.h"
 #include "chart.h"
+/* (headers) */
 
 #include "debug-print.h"
 
 /* (declarations) */
 /* (functions) */
 
+/* Statistics. */
+enum
+  {
+    frq_mean = 0, frq_semean, frq_median, frq_mode, frq_stddev, frq_variance,
+    frq_kurt, frq_sekurt, frq_skew, frq_seskew, frq_range, frq_min, frq_max,
+    frq_sum, frq_n_stats
+  };
+
 /* Description of a statistic. */
 struct frq_info
   {
@@ -129,7 +141,6 @@ struct percentile
 
 static void add_percentile (double x) ;
 
-
 static struct percentile *percentiles;
 static int n_percentiles;
 
@@ -179,12 +190,74 @@ static struct variable **v_variables;
 static struct pool *int_pool;  /* Integer mode. */
 static struct pool *gen_pool;  /* General mode. */
 
-/* Easier access to a_statistics. */
-#define stat cmd.a_statistics
+/* Frequency tables. */
+
+/* Frequency table entry. */
+struct freq
+  {
+    union value v;             /* The value. */
+    double c;                  /* The number of occurrences of the value. */
+  };
+
+/* Types of frequency tables. */
+enum
+  {
+    FRQM_GENERAL,
+    FRQM_INTEGER
+  };
+
+/* Entire frequency table. */
+struct freq_tab
+  {
+    int mode;                  /* FRQM_GENERAL or FRQM_INTEGER. */
+
+    /* General mode. */
+    struct hsh_table *data;    /* Undifferentiated data. */
+
+    /* Integer mode. */
+    double *vector;            /* Frequencies proper. */
+    int min, max;              /* The boundaries of the table. */
+    double out_of_range;       /* Sum of weights of out-of-range values. */
+    double sysmis;             /* Sum of weights of SYSMIS values. */
+
+    /* All modes. */
+    struct freq *valid;         /* Valid freqs. */
+    int n_valid;               /* Number of total freqs. */
+
+    struct freq *missing;      /* Missing freqs. */
+    int n_missing;             /* Number of missing freqs. */
+
+    /* Statistics. */
+    double total_cases;                /* Sum of weights of all cases. */
+    double valid_cases;                /* Sum of weights of valid cases. */
+  };
+
+
+/* Per-variable frequency data. */
+struct var_freqs
+  {
+    /* Freqency table. */
+    struct freq_tab tab;       /* Frequencies table to use. */
+
+    /* Percentiles. */
+    int n_groups;              /* Number of groups. */
+    double *groups;            /* Groups. */
+
+    /* Statistics. */
+    double stat[frq_n_stats];
+  };
+
+static inline struct var_freqs *
+get_var_freqs (struct variable *v)
+{
+  assert (v != NULL);
+  assert (v->aux != NULL);
+  return v->aux;
+}
 
 static void determine_charts (void);
 
-static void calc_stats (struct variable * v, double d[frq_n_stats]);
+static void calc_stats (struct variable *v, double d[frq_n_stats]);
 
 static void precalc (void *);
 static int calc (struct ccase *, void *);
@@ -201,6 +274,15 @@ static hsh_compare_func compare_value_numeric_a, compare_value_alpha_a;
 static hsh_compare_func compare_value_numeric_d, compare_value_alpha_d;
 static hsh_compare_func compare_freq_numeric_a, compare_freq_alpha_a;
 static hsh_compare_func compare_freq_numeric_d, compare_freq_alpha_d;
+
+
+static void do_piechart(const struct variable *var,
+                       const struct freq_tab *frq_tab);
+
+gsl_histogram * 
+freq_tab_to_hist(const struct freq_tab *ft, const struct variable *var);
+
+
 \f
 /* Parser and outline. */
 
@@ -233,9 +315,6 @@ internal_cmd_frequencies (void)
   n_variables = 0;
   v_variables = NULL;
 
-  for (i = 0; i < dict_get_var_cnt (default_dict); i++)
-    dict_get_var(default_dict, i)->p.frq.used = 0;
-
   if (!parse_frequencies (&cmd))
     return CMD_FAILURE;
 
@@ -244,14 +323,14 @@ internal_cmd_frequencies (void)
 
   /* Figure out statistics to calculate. */
   stats = 0;
-  if (stat[FRQ_ST_DEFAULT] || !cmd.sbc_statistics)
+  if (cmd.a_statistics[FRQ_ST_DEFAULT] || !cmd.sbc_statistics)
     stats |= frq_default;
-  if (stat[FRQ_ST_ALL])
+  if (cmd.a_statistics[FRQ_ST_ALL])
     stats |= frq_all;
   if (cmd.sort != FRQ_AVALUE && cmd.sort != FRQ_DVALUE)
     stats &= ~frq_median;
   for (i = 0; i < frq_n_stats; i++)
-    if (stat[st_name[i].st_indx])
+    if (cmd.a_statistics[st_name[i].st_indx])
       stats |= BIT_INDEX (i);
   if (stats & frq_kurt)
     stats |= frq_sekurt;
@@ -294,6 +373,8 @@ internal_cmd_frequencies (void)
   /* Do it! */
   procedure_with_splits (precalc, calc, postcalc, NULL);
 
+  free_frequencies(&cmd);
+
   return CMD_SUCCESS;
 }
 
@@ -416,9 +497,9 @@ calc (struct ccase *c, void *aux UNUSED)
     {
       struct variable *v = v_variables[i];
       const union value *val = case_data (c, v->fv);
-      struct freq_tab *ft = &v->p.frq.tab;
+      struct freq_tab *ft = &get_var_freqs (v)->tab;
 
-      switch (v->p.frq.tab.mode)
+      switch (ft->mode)
        {
          case FRQM_GENERAL:
            {
@@ -439,15 +520,15 @@ calc (struct ccase *c, void *aux UNUSED)
        case FRQM_INTEGER:
          /* Integer mode. */
          if (val->f == SYSMIS)
-           v->p.frq.tab.sysmis += weight;
+           ft->sysmis += weight;
          else if (val->f > INT_MIN+1 && val->f < INT_MAX-1)
            {
              int i = val->f;
-             if (i >= v->p.frq.tab.min && i <= v->p.frq.tab.max)
-               v->p.frq.tab.vector[i - v->p.frq.tab.min] += weight;
+             if (i >= ft->min && i <= ft->max)
+               ft->vector[i - ft->min] += weight;
            }
          else
-           v->p.frq.tab.out_of_range += weight;
+           ft->out_of_range += weight;
          break;
        default:
          assert (0);
@@ -469,8 +550,9 @@ precalc (void *aux UNUSED)
   for (i = 0; i < n_variables; i++)
     {
       struct variable *v = v_variables[i];
+      struct freq_tab *ft = &get_var_freqs (v)->tab;
 
-      if (v->p.frq.tab.mode == FRQM_GENERAL)
+      if (ft->mode == FRQM_GENERAL)
        {
           hsh_hash_func *hash;
          hsh_compare_func *compare;
@@ -485,16 +567,16 @@ precalc (void *aux UNUSED)
               hash = hash_value_alpha;
               compare = compare_value_alpha_a;
             }
-         v->p.frq.tab.data = hsh_create (16, compare, hash, NULL, v);
+         ft->data = hsh_create (16, compare, hash, NULL, v);
        }
       else
        {
          int j;
 
-         for (j = (v->p.frq.tab.max - v->p.frq.tab.min); j >= 0; j--)
-           v->p.frq.tab.vector[j] = 0.0;
-         v->p.frq.tab.out_of_range = 0.0;
-         v->p.frq.tab.sysmis = 0.0;
+         for (j = (ft->max - ft->min); j >= 0; j--)
+           ft->vector[j] = 0.0;
+         ft->out_of_range = 0.0;
+         ft->sysmis = 0.0;
        }
     }
 }
@@ -509,13 +591,15 @@ postcalc (void *aux UNUSED)
   for (i = 0; i < n_variables; i++)
     {
       struct variable *v = v_variables[i];
+      struct var_freqs *vf = get_var_freqs (v);
+      struct freq_tab *ft = &vf->tab;
       int n_categories;
       int dumped_freq_tab = 1;
 
       postprocess_freq_tab (v);
 
       /* Frequencies tables. */
-      n_categories = v->p.frq.tab.n_valid + v->p.frq.tab.n_missing;
+      n_categories = ft->n_valid + ft->n_missing;
       if (cmd.table == FRQ_TABLE
          || (cmd.table == FRQ_LIMIT && n_categories <= cmd.limit))
        switch (cmd.cond)
@@ -543,37 +627,35 @@ postcalc (void *aux UNUSED)
        dump_statistics (v, !dumped_freq_tab);
 
 
+
       if ( chart == GFT_HIST) 
        {
-         struct chart ch;
          double d[frq_n_stats];
-         struct frequencies_proc *frq = &v->p.frq;
-         
          struct normal_curve norm;
-         norm.N = frq->tab.total_cases ;
+         gsl_histogram *hist ;
+
+
+         norm.N = vf->tab.valid_cases;
 
          calc_stats(v,d);
          norm.mean = d[frq_mean];
          norm.stddev = d[frq_stddev];
 
-         chart_initialise(&ch);
-         draw_histogram(&ch, v_variables[i], "HISTOGRAM",&norm,normal);
-         chart_finalise(&ch);
+         hist = freq_tab_to_hist(ft,v);
+
+         histogram_plot(hist, var_to_string(v), &norm, normal);
+
+         gsl_histogram_free(hist);
        }
 
 
       if ( chart == GFT_PIE) 
        {
-         struct chart ch;
-
-         chart_initialise(&ch);
-         
-         draw_piechart(&ch, v_variables[i]);
-
-         chart_finalise(&ch);
+         do_piechart(v_variables[i], ft);
        }
 
 
+
       cleanup_freq_tab (v);
 
     }
@@ -624,9 +706,9 @@ postprocess_freq_tab (struct variable *v)
   struct freq *freqs, *f;
   size_t i;
 
-  assert (v->p.frq.tab.mode == FRQM_GENERAL);
+  ft = &get_var_freqs (v)->tab;
+  assert (ft->mode == FRQM_GENERAL);
   compare = get_freq_comparator (cmd.sort, v->type);
-  ft = &v->p.frq.tab;
 
   /* Extract data from hash table. */
   count = hsh_count (ft->data);
@@ -672,9 +754,10 @@ postprocess_freq_tab (struct variable *v)
 static void
 cleanup_freq_tab (struct variable *v)
 {
-  assert (v->p.frq.tab.mode == FRQM_GENERAL);
-  free (v->p.frq.tab.valid);
-  hsh_destroy (v->p.frq.tab.data);
+  struct freq_tab *ft = &get_var_freqs (v)->tab;
+  assert (ft->mode == FRQM_GENERAL);
+  free (ft->valid);
+  hsh_destroy (ft->data);
 }
 
 /* Parses the VARIABLES subcommand, adding to
@@ -697,9 +780,6 @@ frq_custom_variables (struct cmd_frequencies *cmd UNUSED)
                        PV_APPEND | PV_NO_SCRATCH))
     return 0;
 
-  for (i = old_n_variables; i < n_variables; i++)
-    v_variables[i]->p.frq.tab.mode = FRQM_GENERAL;
-
   if (!lex_match ('('))
     mode = FRQM_GENERAL;
   else
@@ -728,42 +808,40 @@ frq_custom_variables (struct cmd_frequencies *cmd UNUSED)
   for (i = old_n_variables; i < n_variables; i++)
     {
       struct variable *v = v_variables[i];
+      struct var_freqs *vf;
 
-      if (v->p.frq.used != 0)
+      if (v->aux != NULL)
        {
          msg (SE, _("Variable %s specified multiple times on VARIABLES "
                     "subcommand."), v->name);
          return 0;
        }
-      
-      v->p.frq.used = 1;               /* Used simply as a marker. */
-
-      v->p.frq.tab.valid = v->p.frq.tab.missing = NULL;
+      if (mode == FRQM_INTEGER && v->type != NUMERIC)
+        {
+          msg (SE, _("Integer mode specified, but %s is not a numeric "
+                     "variable."), v->name);
+          return 0;
+        }
 
+      vf = var_attach_aux (v, xmalloc (sizeof *vf), var_dtor_free);
+      vf->tab.mode = mode;
+      vf->tab.valid = vf->tab.missing = NULL;
       if (mode == FRQM_INTEGER)
        {
-         if (v->type != NUMERIC)
-           {
-             msg (SE, _("Integer mode specified, but %s is not a numeric "
-                        "variable."), v->name);
-             return 0;
-           }
-         
-         v->p.frq.tab.min = min;
-         v->p.frq.tab.max = max;
-         v->p.frq.tab.vector = pool_alloc (int_pool,
-                                           sizeof (struct freq) * (max - min + 1));
+         vf->tab.min = min;
+         vf->tab.max = max;
+         vf->tab.vector = pool_alloc (int_pool,
+                                       sizeof (struct freq) * (max - min + 1));
        }
       else
-       v->p.frq.tab.vector = NULL;
-
-      v->p.frq.n_groups = 0;
-      v->p.frq.groups = NULL;
+       vf->tab.vector = NULL;
+      vf->n_groups = 0;
+      vf->groups = NULL;
     }
   return 1;
 }
 
-/* Parses the GROUPED subcommand, setting the frq.{n_grouped,grouped}
+/* Parses the GROUPED subcommand, setting the n_grouped, grouped
    fields of specified variables. */
 static int
 frq_custom_grouped (struct cmd_frequencies *cmd UNUSED)
@@ -790,7 +868,7 @@ frq_custom_grouped (struct cmd_frequencies *cmd UNUSED)
          {
            nl = ml = 0;
            dl = NULL;
-           while (token == T_NUM)
+           while (lex_integer ())
              {
                if (nl >= ml)
                  {
@@ -817,19 +895,22 @@ frq_custom_grouped (struct cmd_frequencies *cmd UNUSED)
           }
 
        for (i = 0; i < n; i++)
-         {
-           if (v[i]->p.frq.used == 0)
-             msg (SE, _("Variables %s specified on GROUPED but not on "
-                  "VARIABLES."), v[i]->name);
-           if (v[i]->p.frq.groups != NULL)
-             msg (SE, _("Variables %s specified multiple times on GROUPED "
-                  "subcommand."), v[i]->name);
-           else
-             {
-               v[i]->p.frq.n_groups = nl;
-               v[i]->p.frq.groups = dl;
-             }
-         }
+          if (v[i]->aux == NULL)
+            msg (SE, _("Variables %s specified on GROUPED but not on "
+                       "VARIABLES."), v[i]->name);
+          else 
+            {
+              struct var_freqs *vf = get_var_freqs (v[i]);
+                
+              if (vf->groups != NULL)
+                msg (SE, _("Variables %s specified multiple times on GROUPED "
+                           "subcommand."), v[i]->name);
+              else
+                {
+                  vf->n_groups = nl;
+                  vf->groups = dl;
+                }
+            }
        free (v);
        if (!lex_match ('/'))
          break;
@@ -1032,9 +1113,10 @@ full_dim (struct tab_table *t, struct outp_driver *d)
 
 /* Displays a full frequency table for variable V. */
 static void
-dump_full (struct variable * v)
+dump_full (struct variable *v)
 {
   int n_categories;
+  struct freq_tab *ft;
   struct freq *f;
   struct tab_table *t;
   int r;
@@ -1067,7 +1149,8 @@ dump_full (struct variable * v)
 
   int lab = cmd.labels == FRQ_LABELS;
 
-  n_categories = v->p.frq.tab.n_valid + v->p.frq.tab.n_missing;
+  ft = &get_var_freqs (v)->tab;
+  n_categories = ft->n_valid + ft->n_missing;
   t = tab_create (5 + lab, n_categories + 3, 0);
   tab_headers (t, 0, 0, 2, 0);
   tab_dim (t, full_dim);
@@ -1079,14 +1162,14 @@ dump_full (struct variable * v)
                  TAB_CENTER | TAT_TITLE, gettext (p->s));
 
   r = 2;
-  for (f = v->p.frq.tab.valid; f < v->p.frq.tab.missing; f++)
+  for (f = ft->valid; f < ft->missing; f++)
     {
       double percent, valid_percent;
 
       cum_freq += f->c;
 
-      percent = f->c / v->p.frq.tab.total_cases * 100.0;
-      valid_percent = f->c / v->p.frq.tab.valid_cases * 100.0;
+      percent = f->c / ft->total_cases * 100.0;
+      valid_percent = f->c / ft->valid_cases * 100.0;
       cum_total += valid_percent;
 
       if (lab)
@@ -1103,7 +1186,7 @@ dump_full (struct variable * v)
       tab_float (t, 4 + lab, r, TAB_NONE, cum_total, 5, 1);
       r++;
     }
-  for (; f < &v->p.frq.tab.valid[n_categories]; f++)
+  for (; f < &ft->valid[n_categories]; f++)
     {
       cum_freq += f->c;
 
@@ -1117,7 +1200,7 @@ dump_full (struct variable * v)
       tab_value (t, 0 + lab, r, TAB_NONE, &f->v, &v->print);
       tab_float (t, 1 + lab, r, TAB_NONE, f->c, 8, 0);
       tab_float (t, 2 + lab, r, TAB_NONE,
-                    f->c / v->p.frq.tab.total_cases * 100.0, 5, 1);
+                    f->c / ft->total_cases * 100.0, 5, 1);
       tab_text (t, 3 + lab, r, TAB_NONE, _("Missing"));
       r++;
     }
@@ -1159,15 +1242,17 @@ condensed_dim (struct tab_table *t, struct outp_driver *d)
 
 /* Display condensed frequency table for variable V. */
 static void
-dump_condensed (struct variable * v)
+dump_condensed (struct variable *v)
 {
   int n_categories;
+  struct freq_tab *ft;
   struct freq *f;
   struct tab_table *t;
   int r;
   double cum_total = 0.0;
 
-  n_categories = v->p.frq.tab.n_valid + v->p.frq.tab.n_missing;
+  ft = &get_var_freqs (v)->tab;
+  n_categories = ft->n_valid + ft->n_missing;
   t = tab_create (4, n_categories + 2, 0);
 
   tab_headers (t, 0, 0, 2, 0);
@@ -1179,12 +1264,12 @@ dump_condensed (struct variable * v)
   tab_dim (t, condensed_dim);
 
   r = 2;
-  for (f = v->p.frq.tab.valid; f < v->p.frq.tab.missing; f++)
+  for (f = ft->valid; f < ft->missing; f++)
     {
       double percent;
 
-      percent = f->c / v->p.frq.tab.total_cases * 100.0;
-      cum_total += f->c / v->p.frq.tab.valid_cases * 100.0;
+      percent = f->c / ft->total_cases * 100.0;
+      cum_total += f->c / ft->valid_cases * 100.0;
 
       tab_value (t, 0, r, TAB_NONE, &f->v, &v->print);
       tab_float (t, 1, r, TAB_NONE, f->c, 8, 0);
@@ -1192,12 +1277,12 @@ dump_condensed (struct variable * v)
       tab_float (t, 3, r, TAB_NONE, cum_total, 3, 0);
       r++;
     }
-  for (; f < &v->p.frq.tab.valid[n_categories]; f++)
+  for (; f < &ft->valid[n_categories]; f++)
     {
       tab_value (t, 0, r, TAB_NONE, &f->v, &v->print);
       tab_float (t, 1, r, TAB_NONE, f->c, 8, 0);
       tab_float (t, 2, r, TAB_NONE,
-                f->c / v->p.frq.tab.total_cases * 100.0, 3, 0);
+                f->c / ft->total_cases * 100.0, 3, 0);
       r++;
     }
 
@@ -1215,9 +1300,10 @@ dump_condensed (struct variable * v)
 /* Calculates all the pertinent statistics for variable V, putting
    them in array D[].  FIXME: This could be made much more optimal. */
 static void
-calc_stats (struct variable * v, double d[frq_n_stats])
+calc_stats (struct variable *v, double d[frq_n_stats])
 {
-  double W = v->p.frq.tab.valid_cases;
+  struct freq_tab *ft = &get_var_freqs (v)->tab;
+  double W = ft->valid_cases;
   struct moments *m;
   struct freq *f=0; 
   int most_often;
@@ -1255,10 +1341,10 @@ calc_stats (struct variable * v, double d[frq_n_stats])
     }
 
   rank = 0;
-  for (idx = 0; idx < v->p.frq.tab.n_valid; ++idx)
+  for (idx = 0; idx < ft->n_valid; ++idx)
     {
       static double prev_value = SYSMIS;
-      f = &v->p.frq.tab.valid[idx]; 
+      f = &ft->valid[idx]; 
       rank += f->c ;
       for (i = 0; i < n_percentiles; i++) 
         {
@@ -1267,10 +1353,10 @@ calc_stats (struct variable * v, double d[frq_n_stats])
 
          if ( get_algorithm() != COMPATIBLE ) 
            tp = 
-             (v->p.frq.tab.valid_cases - 1) *  percentiles[i].p;
+             (ft->valid_cases - 1) *  percentiles[i].p;
          else
            tp = 
-             (v->p.frq.tab.valid_cases + 1) *  percentiles[i].p - 1;
+             (ft->valid_cases + 1) *  percentiles[i].p - 1;
 
          if ( percentiles[i].flag ) 
            {
@@ -1312,17 +1398,17 @@ calc_stats (struct variable * v, double d[frq_n_stats])
 
   for (i = 0; i < n_percentiles; i++) 
     {
-      struct freq_tab *ft = &v->p.frq.tab;
+      struct freq_tab *ft = &get_var_freqs (v)->tab;
       double s;
 
       double dummy;
       if ( get_algorithm() != COMPATIBLE ) 
        {
-         s = modf((ft->valid_cases - 1) *  percentiles[i].p , &dummy);
+         s = modf((ft->valid_cases - 1) * percentiles[i].p , &dummy);
        }
       else
        {
-         s = modf((ft->valid_cases + 1) *  percentiles[i].p -1, &dummy);
+         s = modf((ft->valid_cases + 1) * percentiles[i].p -1, &dummy);
        }
 
       percentiles[i].value = percentiles[i].x1 + 
@@ -1336,7 +1422,7 @@ calc_stats (struct variable * v, double d[frq_n_stats])
   /* Calculate the mode. */
   most_often = -1;
   X_mode = SYSMIS;
-  for (f = v->p.frq.tab.valid; f < v->p.frq.tab.missing; f++)
+  for (f = ft->valid; f < ft->missing; f++)
     {
       if (most_often < f->c) 
         {
@@ -1353,17 +1439,17 @@ calc_stats (struct variable * v, double d[frq_n_stats])
 
   /* Calculate moments. */
   m = moments_create (MOMENT_KURTOSIS);
-  for (f = v->p.frq.tab.valid; f < v->p.frq.tab.missing; f++)
+  for (f = ft->valid; f < ft->missing; f++)
     moments_pass_one (m, f->v.f, f->c);
-  for (f = v->p.frq.tab.valid; f < v->p.frq.tab.missing; f++)
+  for (f = ft->valid; f < ft->missing; f++)
     moments_pass_two (m, f->v.f, f->c);
   moments_calculate (m, NULL, &d[frq_mean], &d[frq_variance],
                      &d[frq_skew], &d[frq_kurt]);
   moments_destroy (m);
                      
   /* Formulas below are taken from _SPSS Statistical Algorithms_. */
-  d[frq_min] = v->p.frq.tab.valid[0].v.f;
-  d[frq_max] = v->p.frq.tab.valid[v->p.frq.tab.n_valid - 1].v.f;
+  d[frq_min] = ft->valid[0].v.f;
+  d[frq_max] = ft->valid[ft->n_valid - 1].v.f;
   d[frq_mode] = X_mode;
   d[frq_range] = d[frq_max] - d[frq_min];
   d[frq_median] = *median_value;
@@ -1376,8 +1462,9 @@ calc_stats (struct variable * v, double d[frq_n_stats])
 
 /* Displays a table of all the statistics requested for variable V. */
 static void
-dump_statistics (struct variable * v, int show_varname)
+dump_statistics (struct variable *v, int show_varname)
 {
+  struct freq_tab *ft;
   double stat_value[frq_n_stats];
   struct tab_table *t;
   int i, r;
@@ -1389,7 +1476,8 @@ dump_statistics (struct variable * v, int show_varname)
 
   if (v->type == ALPHA)
     return;
-  if (v->p.frq.tab.n_valid == 0)
+  ft = &get_var_freqs (v)->tab;
+  if (ft->n_valid == 0)
     {
       msg (SW, _("No valid data for variable %s; statistics not displayed."),
           v->name);
@@ -1421,9 +1509,8 @@ dump_statistics (struct variable * v, int show_varname)
   tab_text (t, 1, 0, TAB_LEFT | TAT_TITLE, _("Valid"));
   tab_text (t, 1, 1, TAB_LEFT | TAT_TITLE, _("Missing"));
 
-  tab_float(t, 2, 0, TAB_NONE, v->p.frq.tab.valid_cases, 11, 0);
-  tab_float(t, 2, 1, TAB_NONE, 
-           v->p.frq.tab.total_cases - v->p.frq.tab.valid_cases, 11, 0);
+  tab_float(t, 2, 0, TAB_NONE, ft->valid_cases, 11, 0);
+  tab_float(t, 2, 1, TAB_NONE, ft->total_cases - ft->valid_cases, 11, 0);
 
 
   for (i = 0; i < n_explicit_percentiles; i++, r++) 
@@ -1452,6 +1539,96 @@ dump_statistics (struct variable * v, int show_varname)
 
   tab_submit (t);
 }
+
+
+/* Create a gsl_histogram from a freq_tab */
+gsl_histogram *
+freq_tab_to_hist(const struct freq_tab *ft, const struct variable *var)
+{
+  int i;
+  double x_min = DBL_MAX;
+  double x_max = -DBL_MAX;
+
+  gsl_histogram *hist;
+  const double bins = 11;
+
+  struct hsh_iterator hi;
+  struct hsh_table *fh = ft->data;
+  struct freq *frq;
+
+  /* Find out the extremes of the x value */
+  for ( frq = hsh_first(fh, &hi); frq != 0; frq = hsh_next(fh, &hi) ) 
+    {
+      if ( is_missing(&frq->v, var))
+       continue;
+
+      if ( frq->v.f < x_min ) x_min = frq->v.f ;
+      if ( frq->v.f > x_max ) x_max = frq->v.f ;
+    }
+
+  hist = histogram_create(bins, x_min, x_max);
+
+  for( i = 0 ; i < ft->n_valid ; ++i ) 
+    {
+      frq = &ft->valid[i];
+      gsl_histogram_accumulate(hist, frq->v.f, frq->c);
+    }
+
+  return hist;
+}
+
+
+static struct slice *
+freq_tab_to_slice_array(const struct freq_tab *frq_tab, 
+                       const struct variable *var,
+                       int *n_slices);
+
+
+/* Allocate an array of slices and fill them from the data in frq_tab
+   n_slices will contain the number of slices allocated.
+   The caller is responsible for freeing slices
+*/
+static struct slice *
+freq_tab_to_slice_array(const struct freq_tab *frq_tab, 
+                       const struct variable *var,
+                       int *n_slices)
+{
+  int i;
+  struct slice *slices;
+
+  *n_slices = frq_tab->n_valid;
+  
+  slices = xmalloc ( *n_slices * sizeof (struct slice ) );
+
+  for (i = 0 ; i < *n_slices ; ++i ) 
+    {
+      const struct freq *frq = &frq_tab->valid[i];
+
+      slices[i].label = value_to_string(&frq->v, var);
+
+      slices[i].magnetude = frq->c;
+    }
+
+  return slices;
+}
+
+
+
+
+static void
+do_piechart(const struct variable *var, const struct freq_tab *frq_tab)
+{
+  struct slice *slices;
+  int n_slices;
+
+  slices = freq_tab_to_slice_array(frq_tab, var, &n_slices);
+
+  piechart_plot(var_to_string(var), slices, n_slices);
+
+  free(slices);
+}
+
+
 /* 
    Local Variables:
    mode: c