Added the /BARCHART option to CROSSTABS
[pspp] / src / language / stats / frequencies.c
index 254bda3ef709c8fd1c6785390ed583cd9211ca6c..aa4eddfacc7831a9b8fab226f75f28e02a6b477a 100644 (file)
@@ -243,7 +243,7 @@ static void do_piechart(const struct frq_chart *pie,
                        const struct freq_tab *frq_tab);
 
 static void do_barchart(const struct frq_chart *bar,
-                       const struct variable *var,
+                       const struct variable **var,
                        const struct freq_tab *frq_tab);
 
 static void dump_statistics (const struct frq_proc *frq, 
@@ -264,7 +264,7 @@ compare_freq (const void *a_, const void *b_, const void *aux_)
     }
   else
     {
-      int cmp = value_compare_3way (&a->value, &b->value, aux->width);
+      int cmp = value_compare_3way (a->values, b->values, aux->width);
       return aux->ascending_value ? cmp : -cmp;
     }
 }
@@ -317,11 +317,11 @@ dump_freq_table (const struct var_freqs *vf, const struct variable *wv)
       valid_percent = f->count / ft->valid_cases * 100.0;
       cum_total += valid_percent;
 
-      label = var_lookup_value_label (vf->var, &f->value);
+      label = var_lookup_value_label (vf->var, f->values);
       if (label != NULL)
         tab_text (t, 0, r, TAB_LEFT, label);
 
-      tab_value (t, 1, r, TAB_NONE, &f->value, vf->var, NULL);
+      tab_value (t, 1, r, TAB_NONE, f->values, vf->var, NULL);
       tab_double (t, 2, r, TAB_NONE, f->count, NULL, RC_WEIGHT);
       tab_double (t, 3, r, TAB_NONE, percent, NULL, RC_OTHER);
       tab_double (t, 4, r, TAB_NONE, valid_percent, NULL, RC_OTHER);
@@ -334,11 +334,11 @@ dump_freq_table (const struct var_freqs *vf, const struct variable *wv)
 
       cum_freq += f->count;
 
-      label = var_lookup_value_label (vf->var, &f->value);
+      label = var_lookup_value_label (vf->var, f->values);
       if (label != NULL)
         tab_text (t, 0, r, TAB_LEFT, label);
 
-      tab_value (t, 1, r, TAB_NONE, &f->value, vf->var, NULL);
+      tab_value (t, 1, r, TAB_NONE, f->values, vf->var, NULL);
       tab_double (t, 2, r, TAB_NONE, f->count, NULL, RC_WEIGHT);
       tab_double (t, 3, r, TAB_NONE,
                  f->count / ft->total_cases * 100.0, NULL, RC_OTHER);
@@ -399,15 +399,15 @@ calc_percentiles (const struct frq_proc *frq, const struct var_freqs *vf)
             break;
 
           if (tp + 1 < rank || f + 1 >= ft->missing)
-            pc->value = f->value.f;
+            pc->value = f->values[0].f;
           else
-            pc->value = calc_percentile (pc->p, W, f->value.f, f[1].value.f);
+            pc->value = calc_percentile (pc->p, W, f->values[0].f, f[1].values[0].f);
         }
     }
   for (; percentile_idx < frq->n_percentiles; percentile_idx++)
     {
       struct percentile *pc = &frq->percentiles[percentile_idx];
-      pc->value = ft->valid[ft->n_valid - 1].value.f;
+      pc->value = ft->valid[ft->n_valid - 1].values[0].f;
     }
 }
 
@@ -419,7 +419,7 @@ not_missing (const void *f_, const void *v_)
   const struct freq *f = f_;
   const struct variable *v = v_;
 
-  return !var_is_value_missing (v, &f->value, MV_ANY);
+  return !var_is_value_missing (v, f->values, MV_ANY);
 }
 
 
@@ -569,7 +569,7 @@ postcalc (struct frq_proc *frq, const struct dataset *ds)
         do_piechart(frq->pie, vf->var, &vf->tab);
 
       if (frq->bar)
-        do_barchart(frq->bar, vf->var, &vf->tab);
+        do_barchart(frq->bar, &vf->var, &vf->tab);
 
       cleanup_freq_tab (vf);
     }
@@ -588,7 +588,7 @@ cmd_frequencies (struct lexer *lexer, struct dataset *ds)
 
   double pie_min = -DBL_MAX;
   double pie_max = DBL_MAX;
-  bool pie_missing = false;
+  bool pie_missing = true;
 
   double bar_min = -DBL_MAX;
   double bar_max = DBL_MAX;
@@ -798,7 +798,6 @@ cmd_frequencies (struct lexer *lexer, struct dataset *ds)
            {
              if (lex_match_id (lexer, "TABLE"))
                {
-                 
                }
              else if (lex_match_id (lexer, "NOTABLE"))
                {
@@ -1141,7 +1140,7 @@ cmd_frequencies (struct lexer *lexer, struct dataset *ds)
        frq.bar = xmalloc (sizeof *frq.bar);
        frq.bar->x_min = bar_min;
        frq.bar->x_max = bar_max;
-       frq.bar->include_missing = true;
+       frq.bar->include_missing = false;
        frq.bar->y_scale = bar_freq ? FRQ_FREQ : FRQ_PERCENT;
       }
 
@@ -1281,10 +1280,10 @@ freq_tab_to_hist (const struct frq_proc *frq, const struct freq_tab *ft,
   for (i = 0; i < ft->n_valid; i++)
     {
       const struct freq *f = &ft->valid[i];
-      if (chart_includes_value (frq->hist, var, &f->value))
+      if (chart_includes_value (frq->hist, var, f->values))
         {
-          x_min = MIN (x_min, f->value.f);
-          x_max = MAX (x_max, f->value.f);
+          x_min = MIN (x_min, f->values[0].f);
+          x_max = MAX (x_max, f->values[0].f);
           valid_freq += f->count;
         }
     }
@@ -1308,83 +1307,118 @@ freq_tab_to_hist (const struct frq_proc *frq, const struct freq_tab *ft,
   for (i = 0; i < ft->n_valid; i++)
     {
       const struct freq *f = &ft->valid[i];
-      if (chart_includes_value (frq->hist, var, &f->value))
-        histogram_add (histogram, f->value.f, f->count);
+      if (chart_includes_value (frq->hist, var, f->values))
+        histogram_add (histogram, f->values[0].f, f->count);
     }
 
   return histogram;
 }
 
-static int
-add_slice (const struct frq_chart *pie, const struct freq *freq,
-           const struct variable *var, struct slice *slice)
+
+/* Allocate an array of struct freqs and fill them from the data in FRQ_TAB,
+   according to the parameters of CATCHART
+   N_SLICES will contain the number of slices allocated.
+   The caller is responsible for freeing slices
+*/
+static struct freq *
+pick_cat_counts (const struct frq_chart *catchart,
+                const struct freq_tab *frq_tab,
+                int *n_slicesp)
 {
-  if (chart_includes_value (pie, var, &freq->value))
+  int n_slices = 0;
+  int i;
+  struct freq *slices = xnmalloc (frq_tab->n_valid + frq_tab->n_missing, sizeof *slices);
+  
+  for (i = 0; i < frq_tab->n_valid; i++)
+    {
+      const struct freq *f = &frq_tab->valid[i];
+      if (f->count > catchart->x_max)
+       continue;
+
+      if (f->count < catchart->x_min)
+       continue;
+      
+      slices[n_slices] = *f;
+      
+      n_slices++;
+    }
+
+  if (catchart->include_missing)
     {
-      ds_init_empty (&slice->label);
-      var_append_value_name (var, &freq->value, &slice->label);
-      slice->magnitude = freq->count;
-      return 1;
+      for (i = 0; i < frq_tab->n_missing; i++)
+       {
+         const struct freq *f = &frq_tab->missing[i];
+         slices[n_slices].count += f->count;
+         
+         if (i == 0)
+           slices[n_slices].values[0] = f->values[0];
+       }
+      
+      if (frq_tab->n_missing > 0)
+       n_slices++;
     }
-  else
-    return 0;
+
+  *n_slicesp = n_slices;
+  return slices;
 }
 
-/* Allocate an array of slices and fill them from the data in frq_tab
-   n_slices will contain the number of slices allocated.
+
+/* Allocate an array of struct freqs and fill them from the data in FRQ_TAB,
+   according to the parameters of CATCHART
+   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 frq_chart *catchart,
-                        const struct freq_tab *frq_tab,
-                       const struct variable *var,
-                       int *n_slicesp)
+static struct freq **
+pick_cat_counts_ptr (const struct frq_chart *catchart,
+                    const struct freq_tab *frq_tab,
+                    int *n_slicesp)
 {
-  struct slice *slices;
-  int n_slices;
+  int n_slices = 0;
   int i;
-  double total = 0;
-
-  slices = xnmalloc (frq_tab->n_valid + frq_tab->n_missing, sizeof *slices);
-  n_slices = 0;
-
+  struct freq **slices = xnmalloc (frq_tab->n_valid + frq_tab->n_missing, sizeof *slices);
   
   for (i = 0; i < frq_tab->n_valid; i++)
     {
-      const struct freq *f = &frq_tab->valid[i];
-      total += f->count;
+      struct freq *f = &frq_tab->valid[i];
       if (f->count > catchart->x_max)
        continue;
 
       if (f->count < catchart->x_min)
        continue;
-
-      n_slices += add_slice (catchart, f, var, &slices[n_slices]);
+      
+      slices[n_slices] = f;
+      
+      n_slices++;
     }
 
-  if (catchart->y_scale == FRQ_PERCENT) 
-    for (i = 0; i < frq_tab->n_valid; i++)
-      {
-       slices[i].magnitude /= total;
-       slices[i].magnitude *= 100.00;
-      }
-  
-  for (i = 0; i < frq_tab->n_missing; i++)
-    n_slices += add_slice (catchart, &frq_tab->missing[i], var, &slices[n_slices]);
+  if (catchart->include_missing)
+    {
+      for (i = 0; i < frq_tab->n_missing; i++)
+       {
+         const struct freq *f = &frq_tab->missing[i];
+         if (i == 0)
+           {
+             slices[n_slices] = xmalloc (sizeof (struct freq));
+             slices[n_slices]->values[0] = f->values[0];
+           }
+
+         slices[n_slices]->count += f->count;
+         
+       }
+    }
 
   *n_slicesp = n_slices;
   return slices;
 }
 
 
+
 static void
 do_piechart(const struct frq_chart *pie, const struct variable *var,
             const struct freq_tab *frq_tab)
 {
-  struct slice *slices;
-  int n_slices, i;
-
-  slices = freq_tab_to_slice_array (pie, frq_tab, var, &n_slices);
+  int n_slices;
+  struct freq *slices = pick_cat_counts (pie, frq_tab, &n_slices);
 
   if (n_slices < 2)
     msg (SW, _("Omitting pie chart for %s, which has only %d unique values."),
@@ -1393,29 +1427,22 @@ do_piechart(const struct frq_chart *pie, const struct variable *var,
     msg (SW, _("Omitting pie chart for %s, which has over 50 unique values."),
          var_get_name (var));
   else
-    chart_item_submit (piechart_create (var_to_string(var), slices, n_slices));
+    chart_item_submit (piechart_create (var, slices, n_slices));
 
-  for (i = 0; i < n_slices; i++)
-    ds_destroy (&slices[i].label);
   free (slices);
 }
 
 
 static void
-do_barchart(const struct frq_chart *bar, const struct variable *var,
+do_barchart(const struct frq_chart *bar, const struct variable **var,
             const struct freq_tab *frq_tab)
 {
-  struct slice *slices;
-  int n_slices, i;
-
-  slices = freq_tab_to_slice_array (bar, frq_tab, var, &n_slices);
+  int n_slices;
+  struct freq **slices = pick_cat_counts_ptr (bar, frq_tab, &n_slices);
 
-  chart_item_submit (barchart_create (var_to_string (var), 
+  chart_item_submit (barchart_create (var, 1,
                                      (bar->y_scale == FRQ_FREQ) ? _("Count") : _("Percent"),
                                      slices, n_slices));
-
-  for (i = 0; i < n_slices; i++)
-    ds_destroy (&slices[i].label);
   free (slices);
 }
 
@@ -1438,7 +1465,7 @@ calc_stats (const struct var_freqs *vf, double d[FRQ_ST_count])
       if (most_often < f->count)
         {
           most_often = f->count;
-          X_mode = f->value.f;
+          X_mode = f->values[0].f;
         }
       else if (most_often == f->count)
         {
@@ -1451,16 +1478,16 @@ calc_stats (const struct var_freqs *vf, double d[FRQ_ST_count])
   /* Calculate moments. */
   m = moments_create (MOMENT_KURTOSIS);
   for (f = ft->valid; f < ft->missing; f++)
-    moments_pass_one (m, f->value.f, f->count);
+    moments_pass_one (m, f->values[0].f, f->count);
   for (f = ft->valid; f < ft->missing; f++)
-    moments_pass_two (m, f->value.f, f->count);
+    moments_pass_two (m, f->values[0].f, f->count);
   moments_calculate (m, NULL, &d[FRQ_ST_MEAN], &d[FRQ_ST_VARIANCE],
                      &d[FRQ_ST_SKEWNESS], &d[FRQ_ST_KURTOSIS]);
   moments_destroy (m);
 
   /* Formulae below are taken from _SPSS Statistical Algorithms_. */
-  d[FRQ_ST_MINIMUM] = ft->valid[0].value.f;
-  d[FRQ_ST_MAXIMUM] = ft->valid[ft->n_valid - 1].value.f;
+  d[FRQ_ST_MINIMUM] = ft->valid[0].values[0].f;
+  d[FRQ_ST_MAXIMUM] = ft->valid[ft->n_valid - 1].values[0].f;
   d[FRQ_ST_MODE] = X_mode;
   d[FRQ_ST_RANGE] = d[FRQ_ST_MAXIMUM] - d[FRQ_ST_MINIMUM];
   d[FRQ_ST_SUM] = d[FRQ_ST_MEAN] * W;