Fix bug where attempting to rendering an empty bar chart would crash
[pspp] / src / language / stats / frequencies.c
1 /*
2   PSPP - a program for statistical analysis.
3   Copyright (C) 1997-9, 2000, 2007, 2009, 2010, 2011, 2014, 2015 Free Software Foundation, Inc.
4
5   This program is free software: you can redistribute it and/or modify
6   it under the terms of the GNU General Public License as published by
7   the Free Software Foundation, either version 3 of the License, or
8   (at your option) any later version.
9
10   This program is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   GNU General Public License for more details.
14
15   You should have received a copy of the GNU General Public License
16   along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include <config.h>
20 #include <stdlib.h>
21 #include <gsl/gsl_histogram.h>
22
23
24 #include "data/case.h"
25 #include "data/casegrouper.h"
26 #include "data/casereader.h"
27 #include "data/dataset.h"
28 #include "data/dictionary.h"
29 #include "data/format.h"
30 #include "data/missing-values.h"
31 #include "data/settings.h"
32 #include "data/value-labels.h"
33 #include "data/variable.h"
34
35 #include "language/dictionary/split-file.h"
36
37 #include "language/command.h"
38 #include "language/lexer/lexer.h"
39 #include "language/lexer/variable-parser.h"
40 #include "language/stats/freq.h"
41
42 #include "libpspp/array.h"
43 #include "libpspp/bit-vector.h"
44 #include "libpspp/compiler.h"
45 #include "libpspp/hmap.h"
46 #include "libpspp/message.h"
47 #include "libpspp/misc.h"
48 #include "libpspp/pool.h"
49
50 #include "math/histogram.h"
51 #include "math/moments.h"
52 #include "math/chart-geometry.h"
53
54
55 #include "output/charts/barchart.h"
56 #include "output/charts/piechart.h"
57 #include "output/charts/plot-hist.h"
58 #include "output/pivot-table.h"
59
60 #include "gl/minmax.h"
61 #include "gl/xalloc.h"
62
63 #include "gettext.h"
64 #define _(msgid) gettext (msgid)
65 #define N_(msgid) msgid
66
67 /* Percentiles to calculate. */
68
69 struct percentile
70 {
71   double p;        /* the %ile to be calculated */
72   double value;    /* the %ile's value */
73   bool show;       /* True to show this percentile in the statistics box. */
74 };
75
76 static int
77 ptile_3way (const void *_p1, const void *_p2)
78 {
79   const struct percentile *p1 = _p1;
80   const struct percentile *p2 = _p2;
81
82   if (p1->p < p2->p)
83     return -1;
84
85   if (p1->p == p2->p)
86     {
87       if (p1->show > p2->show)
88         return -1;
89
90       return (p1->show < p2->show);
91     }
92
93   return (p1->p > p2->p);
94 }
95
96
97 enum
98   {
99     FRQ_NONORMAL,
100     FRQ_NORMAL
101   };
102
103 enum
104   {
105     FRQ_FREQ,
106     FRQ_PERCENT
107   };
108
109 enum sortprops
110   {
111     FRQ_AFREQ,
112     FRQ_DFREQ,
113     FRQ_AVALUE,
114     FRQ_DVALUE
115   };
116
117 /* Array indices for STATISTICS subcommand. */
118 enum
119   {
120     FRQ_ST_MEAN,
121     FRQ_ST_SEMEAN,
122     FRQ_ST_MEDIAN,
123     FRQ_ST_MODE,
124     FRQ_ST_STDDEV,
125     FRQ_ST_VARIANCE,
126     FRQ_ST_KURTOSIS,
127     FRQ_ST_SEKURTOSIS,
128     FRQ_ST_SKEWNESS,
129     FRQ_ST_SESKEWNESS,
130     FRQ_ST_RANGE,
131     FRQ_ST_MINIMUM,
132     FRQ_ST_MAXIMUM,
133     FRQ_ST_SUM,
134     FRQ_ST_count
135   };
136
137 /* Description of statistics. */
138 static const char *st_name[FRQ_ST_count] =
139 {
140    N_("Mean"),
141    N_("S.E. Mean"),
142    N_("Median"),
143    N_("Mode"),
144    N_("Std Dev"),
145    N_("Variance"),
146    N_("Kurtosis"),
147    N_("S.E. Kurt"),
148    N_("Skewness"),
149    N_("S.E. Skew"),
150    N_("Range"),
151    N_("Minimum"),
152    N_("Maximum"),
153    N_("Sum")
154 };
155
156 struct freq_tab
157   {
158     struct hmap data;           /* Hash table for accumulating counts. */
159     struct freq *valid;         /* Valid freqs. */
160     int n_valid;                /* Number of total freqs. */
161     const struct dictionary *dict; /* Source of entries in the table. */
162
163     struct freq *missing;       /* Missing freqs. */
164     int n_missing;              /* Number of missing freqs. */
165
166     /* Statistics. */
167     double total_cases;         /* Sum of weights of all cases. */
168     double valid_cases;         /* Sum of weights of valid cases. */
169   };
170
171 struct frq_chart
172   {
173     double x_min;               /* X axis minimum value. */
174     double x_max;               /* X axis maximum value. */
175     int y_scale;                /* Y axis scale: FRQ_FREQ or FRQ_PERCENT. */
176
177     /* Histograms only. */
178     double y_max;               /* Y axis maximum value. */
179     bool draw_normal;           /* Whether to draw normal curve. */
180
181     /* Pie charts only. */
182     bool include_missing;       /* Whether to include missing values. */
183   };
184
185 /* Per-variable frequency data. */
186 struct var_freqs
187   {
188     const struct variable *var;
189
190     /* Freqency table. */
191     struct freq_tab tab;        /* Frequencies table to use. */
192
193     /* Percentiles. */
194     int n_groups;               /* Number of groups. */
195     double *groups;             /* Groups. */
196
197     /* Statistics. */
198     double stat[FRQ_ST_count];
199
200     /* Variable attributes. */
201     int width;
202   };
203
204 struct frq_proc
205   {
206     struct pool *pool;
207
208     struct var_freqs *vars;
209     size_t n_vars;
210
211     /* Percentiles to calculate and possibly display. */
212     struct percentile *percentiles;
213     const struct percentile *median;
214     int n_percentiles;
215
216     /* Frequency table display. */
217     long int max_categories;         /* Maximum categories to show. */
218     int sort;                   /* FRQ_AVALUE or FRQ_DVALUE
219                                    or FRQ_AFREQ or FRQ_DFREQ. */
220
221     /* Statistics; number of statistics. */
222     unsigned long stats;
223     int n_stats;
224
225     /* Histogram and pie chart settings. */
226     struct frq_chart *hist, *pie, *bar;
227
228     bool warn;
229   };
230
231
232 struct freq_compare_aux
233   {
234     bool by_freq;
235     bool ascending_freq;
236
237     int width;
238     bool ascending_value;
239   };
240
241 static void calc_stats (const struct frq_proc *,
242                         const struct var_freqs *, double d[FRQ_ST_count]);
243
244 static void do_piechart(const struct frq_chart *pie,
245                         const struct variable *var,
246                         const struct freq_tab *frq_tab);
247
248 static void do_barchart(const struct frq_chart *bar,
249                         const struct variable **var,
250                         const struct freq_tab *frq_tab);
251
252 static void dump_statistics (const struct frq_proc *frq,
253                              const struct variable *wv);
254
255 static int
256 compare_freq (const void *a_, const void *b_, const void *aux_)
257 {
258   const struct freq_compare_aux *aux = aux_;
259   const struct freq *a = a_;
260   const struct freq *b = b_;
261
262   if (aux->by_freq && a->count != b->count)
263     {
264       int cmp = a->count > b->count ? 1 : -1;
265       return aux->ascending_freq ? cmp : -cmp;
266     }
267   else
268     {
269       int cmp = value_compare_3way (a->values, b->values, aux->width);
270       return aux->ascending_value ? cmp : -cmp;
271     }
272 }
273
274 /* Create a gsl_histogram from a freq_tab */
275 static struct histogram *
276 freq_tab_to_hist (const struct frq_proc *frq, const struct freq_tab *ft,
277                   const struct variable *var);
278
279 static void
280 put_freq_row (struct pivot_table *table, int var_idx,
281               double frequency, double percent,
282               double valid_percent, double cum_percent)
283 {
284   double entries[] = { frequency, percent, valid_percent, cum_percent };
285   for (size_t i = 0; i < sizeof entries / sizeof *entries; i++)
286     if (entries[i] != SYSMIS)
287       pivot_table_put2 (table, i, var_idx,
288                         pivot_value_new_number (entries[i]));
289 }
290
291 /* Displays a full frequency table for variable V. */
292 static void
293 dump_freq_table (const struct var_freqs *vf, const struct variable *wv)
294 {
295   const struct freq_tab *ft = &vf->tab;
296
297   struct pivot_table *table = pivot_table_create__ (pivot_value_new_variable (
298                                                       vf->var), "Frequencies");
299   pivot_table_set_weight_var (table, wv);
300
301   pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Statistics"),
302                           N_("Frequency"), PIVOT_RC_COUNT,
303                           N_("Percent"), PIVOT_RC_PERCENT,
304                           N_("Valid Percent"), PIVOT_RC_PERCENT,
305                           N_("Cumulative Percent"), PIVOT_RC_PERCENT);
306
307   struct pivot_dimension *variable = pivot_dimension_create__ (
308     table, PIVOT_AXIS_ROW, pivot_value_new_variable (vf->var));
309
310   double cum_freq = 0.0;
311   double cum_percent = 0.0;
312   struct pivot_category *valid = NULL;
313   for (const struct freq *f = ft->valid; f < ft->missing; f++)
314     {
315       cum_freq += f->count;
316       double valid_percent = f->count / ft->valid_cases * 100.0;
317       cum_percent += valid_percent;
318
319       if (!valid)
320         valid = pivot_category_create_group (variable->root, N_("Valid"));
321       int var_idx = pivot_category_create_leaf (
322         valid, pivot_value_new_var_value (vf->var, &f->values[0]));
323       put_freq_row (table, var_idx, f->count,
324                     f->count / ft->total_cases * 100.0,
325                     valid_percent, cum_percent);
326     }
327
328   struct pivot_category *missing = NULL;
329   size_t n_categories = ft->n_valid + ft->n_missing;
330   for (const struct freq *f = ft->missing; f < &ft->valid[n_categories]; f++)
331     {
332       cum_freq += f->count;
333
334       if (!missing)
335         missing = pivot_category_create_group (variable->root, N_("Missing"));
336       int var_idx = pivot_category_create_leaf (
337         missing, pivot_value_new_var_value (vf->var, &f->values[0]));
338       put_freq_row (table, var_idx, f->count,
339                     f->count / ft->total_cases * 100.0, SYSMIS, SYSMIS);
340     }
341
342   int var_idx = pivot_category_create_leaf (
343     variable->root, pivot_value_new_text (N_("Total")));
344   put_freq_row (table, var_idx, cum_freq, cum_percent, SYSMIS, SYSMIS);
345
346   pivot_table_submit (table);
347 }
348 \f
349 /* Statistical display. */
350
351 static double
352 calc_percentile (double p, double valid_cases, double x1, double x2)
353 {
354   double s, dummy;
355
356   s = (settings_get_algorithm () != COMPATIBLE
357        ? modf ((valid_cases - 1) * p, &dummy)
358        : modf ((valid_cases + 1) * p - 1, &dummy));
359
360   return x1 + (x2 - x1) * s;
361 }
362
363 /* Calculates all of the percentiles for VF within FRQ. */
364 static void
365 calc_percentiles (const struct frq_proc *frq, const struct var_freqs *vf)
366 {
367   const struct freq_tab *ft = &vf->tab;
368   double W = ft->valid_cases;
369   const struct freq *f;
370   int percentile_idx = 0;
371   double  rank = 0;
372
373   for (f = ft->valid; f < ft->missing; f++)
374     {
375       rank += f->count;
376       for (; percentile_idx < frq->n_percentiles; percentile_idx++)
377         {
378           struct percentile *pc = &frq->percentiles[percentile_idx];
379           double tp;
380
381           tp = (settings_get_algorithm () == ENHANCED
382                 ? (W - 1) * pc->p
383                 : (W + 1) * pc->p - 1);
384
385           if (rank <= tp)
386             break;
387
388           if (tp + 1 < rank || f + 1 >= ft->missing)
389             pc->value = f->values[0].f;
390           else
391             pc->value = calc_percentile (pc->p, W, f->values[0].f, f[1].values[0].f);
392         }
393     }
394   for (; percentile_idx < frq->n_percentiles; percentile_idx++)
395     {
396       struct percentile *pc = &frq->percentiles[percentile_idx];
397       pc->value = (ft->n_valid > 0
398                    ? ft->valid[ft->n_valid - 1].values[0].f
399                    : SYSMIS);
400     }
401 }
402
403 /* Returns true iff the value in struct freq F is non-missing
404    for variable V. */
405 static bool
406 not_missing (const void *f_, const void *v_)
407 {
408   const struct freq *f = f_;
409   const struct variable *v = v_;
410
411   return !var_is_value_missing (v, f->values, MV_ANY);
412 }
413
414
415 /* Summarizes the frequency table data for variable V. */
416 static void
417 postprocess_freq_tab (const struct frq_proc *frq, struct var_freqs *vf)
418 {
419   struct freq_tab *ft = &vf->tab;
420   struct freq_compare_aux aux;
421   size_t count;
422   struct freq *freqs, *f;
423   size_t i;
424
425   /* Extract data from hash table. */
426   count = hmap_count (&ft->data);
427   freqs = freq_hmap_extract (&ft->data);
428
429   /* Put data into ft. */
430   ft->valid = freqs;
431   ft->n_valid = partition (freqs, count, sizeof *freqs, not_missing, vf->var);
432   ft->missing = freqs + ft->n_valid;
433   ft->n_missing = count - ft->n_valid;
434
435   /* Sort data. */
436   aux.by_freq = frq->sort == FRQ_AFREQ || frq->sort == FRQ_DFREQ;
437   aux.ascending_freq = frq->sort != FRQ_DFREQ;
438   aux.width = vf->width;
439   aux.ascending_value = frq->sort != FRQ_DVALUE;
440   sort (ft->valid, ft->n_valid, sizeof *ft->valid, compare_freq, &aux);
441   sort (ft->missing, ft->n_missing, sizeof *ft->missing, compare_freq, &aux);
442
443   /* Summary statistics. */
444   ft->valid_cases = 0.0;
445   for(i = 0 ;  i < ft->n_valid ; ++i)
446     {
447       f = &ft->valid[i];
448       ft->valid_cases += f->count;
449
450     }
451
452   ft->total_cases = ft->valid_cases ;
453   for(i = 0 ;  i < ft->n_missing ; ++i)
454     {
455       f = &ft->missing[i];
456       ft->total_cases += f->count;
457     }
458
459 }
460
461 /* Frees the frequency table for variable V. */
462 static void
463 cleanup_freq_tab (struct var_freqs *vf)
464 {
465   free (vf->tab.valid);
466   freq_hmap_destroy (&vf->tab.data, vf->width);
467 }
468
469 /* Add data from case C to the frequency table. */
470 static void
471 calc (struct frq_proc *frq, const struct ccase *c, const struct dataset *ds)
472 {
473   double weight = dict_get_case_weight (dataset_dict (ds), c, &frq->warn);
474   size_t i;
475
476   for (i = 0; i < frq->n_vars; i++)
477     {
478       struct var_freqs *vf = &frq->vars[i];
479       const union value *value = case_data (c, vf->var);
480       size_t hash = value_hash (value, vf->width, 0);
481       struct freq *f;
482
483       f = freq_hmap_search (&vf->tab.data, value, vf->width, hash);
484       if (f == NULL)
485         f = freq_hmap_insert (&vf->tab.data, value, vf->width, hash);
486
487       f->count += weight;
488     }
489 }
490
491 /* Prepares each variable that is the target of FREQUENCIES by setting
492    up its hash table. */
493 static void
494 precalc (struct frq_proc *frq, struct casereader *input, struct dataset *ds)
495 {
496   struct ccase *c;
497   size_t i;
498
499   c = casereader_peek (input, 0);
500   if (c != NULL)
501     {
502       output_split_file_values (ds, c);
503       case_unref (c);
504     }
505
506   for (i = 0; i < frq->n_vars; i++)
507     hmap_init (&frq->vars[i].tab.data);
508 }
509
510 /* Finishes up with the variables after frequencies have been
511    calculated.  Displays statistics, percentiles, ... */
512 static void
513 postcalc (struct frq_proc *frq, const struct dataset *ds)
514 {
515   const struct dictionary *dict = dataset_dict (ds);
516   const struct variable *wv = dict_get_weight (dict);
517   size_t i;
518
519   for (i = 0; i < frq->n_vars; i++)
520     {
521       struct var_freqs *vf = &frq->vars[i];
522       postprocess_freq_tab (frq, vf);
523       calc_percentiles (frq, vf);
524     }
525
526   if (frq->n_stats)
527     dump_statistics (frq, wv);
528
529   for (i = 0; i < frq->n_vars; i++)
530     {
531       struct var_freqs *vf = &frq->vars[i];
532
533       /* Frequencies tables. */
534       if (vf->tab.n_valid + vf->tab.n_missing <= frq->max_categories)
535         dump_freq_table (vf, wv);
536
537
538       if (frq->hist && var_is_numeric (vf->var) && vf->tab.n_valid > 0)
539         {
540           double d[FRQ_ST_count];
541           struct histogram *histogram;
542
543           calc_stats (frq, vf, d);
544
545           histogram = freq_tab_to_hist (frq, &vf->tab, vf->var);
546
547           if (histogram)
548             {
549               chart_submit (histogram_chart_create (
550                               histogram->gsl_hist, var_to_string(vf->var),
551                               vf->tab.valid_cases,
552                               d[FRQ_ST_MEAN],
553                               d[FRQ_ST_STDDEV],
554                               frq->hist->draw_normal));
555
556               statistic_destroy (&histogram->parent);
557             }
558         }
559
560       if (frq->pie)
561         do_piechart(frq->pie, vf->var, &vf->tab);
562
563       if (frq->bar)
564         do_barchart(frq->bar, &vf->var, &vf->tab);
565
566       cleanup_freq_tab (vf);
567     }
568 }
569
570 int
571 cmd_frequencies (struct lexer *lexer, struct dataset *ds)
572 {
573   int i;
574   struct frq_proc frq;
575   const struct variable **vars = NULL;
576
577   bool sbc_barchart = false;
578   bool sbc_piechart = false;
579   bool sbc_histogram = false;
580
581   double pie_min = -DBL_MAX;
582   double pie_max = DBL_MAX;
583   bool pie_missing = true;
584
585   double bar_min = -DBL_MAX;
586   double bar_max = DBL_MAX;
587   bool bar_freq = true;
588
589   double hi_min = -DBL_MAX;
590   double hi_max = DBL_MAX;
591   int hi_scale = FRQ_FREQ;
592   int hi_freq = INT_MIN;
593   int hi_pcnt = INT_MIN;
594   int hi_norm = FRQ_NONORMAL;
595
596   frq.pool = pool_create ();
597   frq.sort = FRQ_AVALUE;
598
599   frq.vars = NULL;
600   frq.n_vars = 0;
601
602   frq.stats = BIT_INDEX (FRQ_ST_MEAN)
603     | BIT_INDEX (FRQ_ST_STDDEV)
604     | BIT_INDEX (FRQ_ST_MINIMUM)
605     | BIT_INDEX (FRQ_ST_MAXIMUM);
606
607   frq.n_stats = 4;
608
609   frq.max_categories = LONG_MAX;
610
611   frq.percentiles = NULL;
612   frq.n_percentiles = 0;
613
614   frq.hist = NULL;
615   frq.pie = NULL;
616   frq.bar = NULL;
617   frq.warn = true;
618
619
620   /* Accept an optional, completely pointless "/VARIABLES=" */
621   lex_match (lexer, T_SLASH);
622   if (lex_match_id  (lexer, "VARIABLES"))
623     {
624       if (! lex_force_match (lexer, T_EQUALS))
625         goto error;
626     }
627
628   if (!parse_variables_const (lexer, dataset_dict (ds),
629                               &vars,
630                               &frq.n_vars,
631                               PV_NO_DUPLICATE))
632     goto error;
633
634   frq.vars = xzalloc (frq.n_vars * sizeof (*frq.vars));
635   for (i = 0; i < frq.n_vars; ++i)
636     {
637       frq.vars[i].var = vars[i];
638       frq.vars[i].width = var_get_width (vars[i]);
639     }
640
641   while (lex_token (lexer) != T_ENDCMD)
642     {
643       lex_match (lexer, T_SLASH);
644
645       if (lex_match_id (lexer, "STATISTICS"))
646         {
647           frq.stats = BIT_INDEX (FRQ_ST_MEAN)
648             | BIT_INDEX (FRQ_ST_STDDEV)
649             | BIT_INDEX (FRQ_ST_MINIMUM)
650             | BIT_INDEX (FRQ_ST_MAXIMUM);
651
652           frq.n_stats = 4;
653
654           if (lex_match (lexer, T_EQUALS))
655             {
656               frq.n_stats = 0;
657               frq.stats = 0;
658             }
659
660           while (lex_token (lexer) != T_ENDCMD
661                  && lex_token (lexer) != T_SLASH)
662             {
663               if (lex_match_id (lexer, "DEFAULT"))
664                 {
665                   frq.stats = BIT_INDEX (FRQ_ST_MEAN)
666                     | BIT_INDEX (FRQ_ST_STDDEV)
667                     | BIT_INDEX (FRQ_ST_MINIMUM)
668                     | BIT_INDEX (FRQ_ST_MAXIMUM);
669
670                   frq.n_stats = 4;
671                 }
672               else if (lex_match_id (lexer, "MEAN"))
673                 {
674                   frq.stats |= BIT_INDEX (FRQ_ST_MEAN);
675                   frq.n_stats++;
676                 }
677               else if (lex_match_id (lexer, "SEMEAN"))
678                 {
679                   frq.stats |= BIT_INDEX (FRQ_ST_SEMEAN);
680                   frq.n_stats++;
681                 }
682               else if (lex_match_id (lexer, "MEDIAN"))
683                 {
684                   frq.stats |= BIT_INDEX (FRQ_ST_MEDIAN);
685                   frq.n_stats++;
686                 }
687               else if (lex_match_id (lexer, "MODE"))
688                 {
689                   frq.stats |= BIT_INDEX (FRQ_ST_MODE);
690                   frq.n_stats++;
691                 }
692               else if (lex_match_id (lexer, "STDDEV"))
693                 {
694                   frq.stats |= BIT_INDEX (FRQ_ST_STDDEV);
695                   frq.n_stats++;
696                 }
697               else if (lex_match_id (lexer, "VARIANCE"))
698                 {
699                   frq.stats |= BIT_INDEX (FRQ_ST_VARIANCE);
700                   frq.n_stats++;
701                 }
702               else if (lex_match_id (lexer, "KURTOSIS"))
703                 {
704                   frq.stats |= BIT_INDEX (FRQ_ST_KURTOSIS);
705                   frq.n_stats++;
706                 }
707               else if (lex_match_id (lexer, "SKEWNESS"))
708                 {
709                   frq.stats |= BIT_INDEX (FRQ_ST_SKEWNESS);
710                   frq.n_stats++;
711                 }
712               else if (lex_match_id (lexer, "RANGE"))
713                 {
714                   frq.stats |= BIT_INDEX (FRQ_ST_RANGE);
715                   frq.n_stats++;
716                 }
717               else if (lex_match_id (lexer, "MINIMUM"))
718                 {
719                   frq.stats |= BIT_INDEX (FRQ_ST_MINIMUM);
720                   frq.n_stats++;
721                 }
722               else if (lex_match_id (lexer, "MAXIMUM"))
723                 {
724                   frq.stats |= BIT_INDEX (FRQ_ST_MAXIMUM);
725                   frq.n_stats++;
726                 }
727               else if (lex_match_id (lexer, "SUM"))
728                 {
729                   frq.stats |= BIT_INDEX (FRQ_ST_SUM);
730                   frq.n_stats++;
731                 }
732               else if (lex_match_id (lexer, "SESKEWNESS"))
733                 {
734                   frq.stats |= BIT_INDEX (FRQ_ST_SESKEWNESS);
735                   frq.n_stats++;
736                 }
737               else if (lex_match_id (lexer, "SEKURTOSIS"))
738                 {
739                   frq.stats |= BIT_INDEX (FRQ_ST_SEKURTOSIS);
740                   frq.n_stats++;
741                 }
742               else if (lex_match_id (lexer, "NONE"))
743                 {
744                   frq.stats = 0;
745                   frq.n_stats = 0;
746                 }
747               else if (lex_match (lexer, T_ALL))
748                 {
749                   frq.stats = ~0;
750                   frq.n_stats = FRQ_ST_count;
751                 }
752               else
753                 {
754                   lex_error (lexer, NULL);
755                   goto error;
756                 }
757             }
758         }
759       else if (lex_match_id (lexer, "PERCENTILES"))
760         {
761           lex_match (lexer, T_EQUALS);
762           while (lex_token (lexer) != T_ENDCMD
763                  && lex_token (lexer) != T_SLASH)
764             {
765               if (lex_force_num (lexer))
766                 {
767                   frq.percentiles =
768                     xrealloc (frq.percentiles,
769                               (frq.n_percentiles + 1)
770                               * sizeof (*frq.percentiles));
771                   frq.percentiles[frq.n_percentiles].p = lex_number (lexer)  / 100.0;
772                   frq.percentiles[frq.n_percentiles].show = true;
773                   lex_get (lexer);
774                   frq.n_percentiles++;
775                 }
776               else
777                 {
778                   lex_error (lexer, NULL);
779                   goto error;
780                 }
781               lex_match (lexer, T_COMMA);
782             }
783         }
784       else if (lex_match_id (lexer, "FORMAT"))
785         {
786           lex_match (lexer, T_EQUALS);
787           while (lex_token (lexer) != T_ENDCMD
788                  && lex_token (lexer) != T_SLASH)
789             {
790               if (lex_match_id (lexer, "TABLE"))
791                 {
792                 }
793               else if (lex_match_id (lexer, "NOTABLE"))
794                 {
795                   frq.max_categories = 0;
796                 }
797               else if (lex_match_id (lexer, "LIMIT"))
798                 {
799                   if (!lex_force_match (lexer, T_LPAREN)
800                       || !lex_force_int (lexer))
801                     goto error;
802
803                   frq.max_categories = lex_integer (lexer);
804                   lex_get (lexer);
805
806                   if (!lex_force_match (lexer, T_RPAREN))
807                     goto error;
808                 }
809               else if (lex_match_id (lexer, "AVALUE"))
810                 {
811                   frq.sort = FRQ_AVALUE;
812                 }
813               else if (lex_match_id (lexer, "DVALUE"))
814                 {
815                   frq.sort = FRQ_DVALUE;
816                 }
817               else if (lex_match_id (lexer, "AFREQ"))
818                 {
819                   frq.sort = FRQ_AFREQ;
820                 }
821               else if (lex_match_id (lexer, "DFREQ"))
822                 {
823                   frq.sort = FRQ_DFREQ;
824                 }
825               else
826                 {
827                   lex_error (lexer, NULL);
828                   goto error;
829                 }
830             }
831         }
832       else if (lex_match_id (lexer, "NTILES"))
833         {
834           lex_match (lexer, T_EQUALS);
835
836           if (lex_force_int (lexer))
837             {
838               int i;
839               int n = lex_integer (lexer);
840               lex_get (lexer);
841               for (i = 0; i < n + 1; ++i)
842                 {
843                   frq.percentiles =
844                     xrealloc (frq.percentiles,
845                               (frq.n_percentiles + 1)
846                               * sizeof (*frq.percentiles));
847                   frq.percentiles[frq.n_percentiles].p =
848                     i / (double) n ;
849                   frq.percentiles[frq.n_percentiles].show = true;
850
851                   frq.n_percentiles++;
852                 }
853             }
854           else
855             {
856               lex_error (lexer, NULL);
857               goto error;
858             }
859         }
860       else if (lex_match_id (lexer, "ALGORITHM"))
861         {
862           lex_match (lexer, T_EQUALS);
863
864           if (lex_match_id (lexer, "COMPATIBLE"))
865             {
866               settings_set_cmd_algorithm (COMPATIBLE);
867             }
868           else if (lex_match_id (lexer, "ENHANCED"))
869             {
870               settings_set_cmd_algorithm (ENHANCED);
871             }
872           else
873             {
874               lex_error (lexer, NULL);
875               goto error;
876             }
877         }
878       else if (lex_match_id (lexer, "HISTOGRAM"))
879         {
880           lex_match (lexer, T_EQUALS);
881           sbc_histogram = true;
882
883           while (lex_token (lexer) != T_ENDCMD
884                  && lex_token (lexer) != T_SLASH)
885             {
886               if (lex_match_id (lexer, "NORMAL"))
887                 {
888                   hi_norm = FRQ_NORMAL;
889                 }
890               else if (lex_match_id (lexer, "NONORMAL"))
891                 {
892                   hi_norm = FRQ_NONORMAL;
893                 }
894               else if (lex_match_id (lexer, "FREQ"))
895                 {
896                   hi_scale = FRQ_FREQ;
897                   if (lex_match (lexer, T_LPAREN))
898                     {
899                       if (lex_force_int (lexer))
900                         {
901                           hi_freq = lex_integer (lexer);
902                           if (hi_freq <= 0)
903                             {
904                               lex_error (lexer, _("Histogram frequency must be greater than zero."));
905                             }
906                           lex_get (lexer);
907                           if (! lex_force_match (lexer, T_RPAREN))
908                             goto error;
909                         }
910                     }
911                 }
912               else if (lex_match_id (lexer, "PERCENT"))
913                 {
914                   hi_scale = FRQ_PERCENT;
915                   if (lex_match (lexer, T_LPAREN))
916                     {
917                       if (lex_force_int (lexer))
918                         {
919                           hi_pcnt = lex_integer (lexer);
920                           if (hi_pcnt <= 0)
921                             {
922                               lex_error (lexer, _("Histogram percentage must be greater than zero."));
923                             }
924                           lex_get (lexer);
925                           if (! lex_force_match (lexer, T_RPAREN))
926                             goto error;
927                         }
928                     }
929                 }
930               else if (lex_match_id (lexer, "MINIMUM"))
931                 {
932                   if (! lex_force_match (lexer, T_LPAREN))
933                     goto error;
934                   if (lex_force_num (lexer))
935                     {
936                       hi_min = lex_number (lexer);
937                       lex_get (lexer);
938                     }
939                   if (! lex_force_match (lexer, T_RPAREN))
940                     goto error;
941                 }
942               else if (lex_match_id (lexer, "MAXIMUM"))
943                 {
944                   if (! lex_force_match (lexer, T_LPAREN))
945                     goto error;
946                   if (lex_force_num (lexer))
947                     {
948                       hi_max = lex_number (lexer);
949                       lex_get (lexer);
950                     }
951                   if (! lex_force_match (lexer, T_RPAREN))
952                     goto error;
953                 }
954               else
955                 {
956                   lex_error (lexer, NULL);
957                   goto error;
958                 }
959             }
960         }
961       else if (lex_match_id (lexer, "PIECHART"))
962         {
963           lex_match (lexer, T_EQUALS);
964           while (lex_token (lexer) != T_ENDCMD
965                  && lex_token (lexer) != T_SLASH)
966             {
967               if (lex_match_id (lexer, "MINIMUM"))
968                 {
969                   if (! lex_force_match (lexer, T_LPAREN))
970                     goto error;
971                   if (lex_force_num (lexer))
972                     {
973                       pie_min = lex_number (lexer);
974                       lex_get (lexer);
975                     }
976                   if (! lex_force_match (lexer, T_RPAREN))
977                     goto error;
978                 }
979               else if (lex_match_id (lexer, "MAXIMUM"))
980                 {
981                   if (! lex_force_match (lexer, T_LPAREN))
982                     goto error;
983                   if (lex_force_num (lexer))
984                     {
985                       pie_max = lex_number (lexer);
986                       lex_get (lexer);
987                     }
988                   if (! lex_force_match (lexer, T_RPAREN))
989                     goto error;
990                 }
991               else if (lex_match_id (lexer, "MISSING"))
992                 {
993                   pie_missing = true;
994                 }
995               else if (lex_match_id (lexer, "NOMISSING"))
996                 {
997                   pie_missing = false;
998                 }
999               else
1000                 {
1001                   lex_error (lexer, NULL);
1002                   goto error;
1003                 }
1004             }
1005           sbc_piechart = true;
1006         }
1007       else if (lex_match_id (lexer, "BARCHART"))
1008         {
1009           lex_match (lexer, T_EQUALS);
1010           while (lex_token (lexer) != T_ENDCMD
1011                  && lex_token (lexer) != T_SLASH)
1012             {
1013               if (lex_match_id (lexer, "MINIMUM"))
1014                 {
1015                   if (! lex_force_match (lexer, T_LPAREN))
1016                     goto error;
1017                   if (lex_force_num (lexer))
1018                     {
1019                       bar_min = lex_number (lexer);
1020                       lex_get (lexer);
1021                     }
1022                   if (! lex_force_match (lexer, T_RPAREN))
1023                     goto error;
1024                 }
1025               else if (lex_match_id (lexer, "MAXIMUM"))
1026                 {
1027                   if (! lex_force_match (lexer, T_LPAREN))
1028                     goto error;
1029                   if (lex_force_num (lexer))
1030                     {
1031                       bar_max = lex_number (lexer);
1032                       lex_get (lexer);
1033                     }
1034                   if (! lex_force_match (lexer, T_RPAREN))
1035                     goto error;
1036                 }
1037               else if (lex_match_id (lexer, "FREQ"))
1038                 {
1039                   if (lex_match (lexer, T_LPAREN))
1040                     {
1041                       if (lex_force_num (lexer))
1042                         {
1043                           lex_number (lexer);
1044                           lex_get (lexer);
1045                         }
1046                       if (! lex_force_match (lexer, T_RPAREN))
1047                         goto error;
1048                     }
1049                   bar_freq = true;
1050                 }
1051               else if (lex_match_id (lexer, "PERCENT"))
1052                 {
1053                   if (lex_match (lexer, T_LPAREN))
1054                     {
1055                       if (lex_force_num (lexer))
1056                         {
1057                           lex_number (lexer);
1058                           lex_get (lexer);
1059                         }
1060                       if (! lex_force_match (lexer, T_RPAREN))
1061                         goto error;
1062                     }
1063                   bar_freq = false;
1064                 }
1065               else
1066                 {
1067                   lex_error (lexer, NULL);
1068                   goto error;
1069                 }
1070             }
1071           sbc_barchart = true;
1072         }
1073       else if (lex_match_id (lexer, "MISSING"))
1074         {
1075           lex_match (lexer, T_EQUALS);
1076
1077           while (lex_token (lexer) != T_ENDCMD
1078                  && lex_token (lexer) != T_SLASH)
1079             {
1080               if (lex_match_id (lexer, "EXCLUDE"))
1081                 {
1082                 }
1083               else if (lex_match_id (lexer, "INCLUDE"))
1084                 {
1085                 }
1086               else
1087                 {
1088                   lex_error (lexer, NULL);
1089                   goto error;
1090                 }
1091             }
1092         }
1093       else if (lex_match_id (lexer, "ORDER"))
1094         {
1095           lex_match (lexer, T_EQUALS);
1096           if (!lex_match_id (lexer, "ANALYSIS"))
1097             lex_match_id (lexer, "VARIABLE");
1098         }
1099       else
1100         {
1101           lex_error (lexer, NULL);
1102           goto error;
1103         }
1104     }
1105
1106   if (frq.stats & BIT_INDEX (FRQ_ST_MEDIAN))
1107     {
1108         frq.percentiles =
1109           xrealloc (frq.percentiles,
1110                     (frq.n_percentiles + 1)
1111                     * sizeof (*frq.percentiles));
1112
1113         frq.percentiles[frq.n_percentiles].p = 0.50;
1114         frq.percentiles[frq.n_percentiles].show = false;
1115
1116         frq.n_percentiles++;
1117     }
1118
1119
1120 /* Figure out which charts the user requested.  */
1121
1122   {
1123     if (sbc_histogram)
1124       {
1125         struct frq_chart *hist;
1126
1127         hist = frq.hist = xmalloc (sizeof *frq.hist);
1128         hist->x_min = hi_min;
1129         hist->x_max = hi_max;
1130         hist->y_scale = hi_scale;
1131         hist->y_max = hi_scale == FRQ_FREQ ? hi_freq : hi_pcnt;
1132         hist->draw_normal = hi_norm != FRQ_NONORMAL;
1133         hist->include_missing = false;
1134
1135         if (hist->x_min != SYSMIS && hist->x_max != SYSMIS
1136             && hist->x_min >= hist->x_max)
1137           {
1138             msg (SE, _("%s for histogram must be greater than or equal to %s, "
1139                        "but %s was specified as %.15g and %s as %.15g.  "
1140                        "%s and %s will be ignored."),
1141                  "MAX", "MIN",
1142                  "MIN", hist->x_min,
1143                  "MAX", hist->x_max,
1144                  "MIN", "MAX");
1145             hist->x_min = hist->x_max = SYSMIS;
1146           }
1147
1148         frq.percentiles =
1149           xrealloc (frq.percentiles,
1150                     (frq.n_percentiles + 2)
1151                     * sizeof (*frq.percentiles));
1152
1153         frq.percentiles[frq.n_percentiles].p = 0.25;
1154         frq.percentiles[frq.n_percentiles].show = false;
1155
1156         frq.percentiles[frq.n_percentiles + 1].p = 0.75;
1157         frq.percentiles[frq.n_percentiles + 1].show = false;
1158
1159         frq.n_percentiles+=2;
1160       }
1161
1162     if (sbc_barchart)
1163       {
1164         frq.bar = xmalloc (sizeof *frq.bar);
1165         frq.bar->x_min = bar_min;
1166         frq.bar->x_max = bar_max;
1167         frq.bar->include_missing = false;
1168         frq.bar->y_scale = bar_freq ? FRQ_FREQ : FRQ_PERCENT;
1169       }
1170
1171     if (sbc_piechart)
1172       {
1173         struct frq_chart *pie;
1174
1175         pie = frq.pie = xmalloc (sizeof *frq.pie);
1176         pie->x_min = pie_min;
1177         pie->x_max = pie_max;
1178         pie->include_missing = pie_missing;
1179
1180         if (pie->x_min != SYSMIS && pie->x_max != SYSMIS
1181             && pie->x_min >= pie->x_max)
1182           {
1183             msg (SE, _("%s for pie chart must be greater than or equal to %s, "
1184                        "but %s was specified as %.15g and %s as %.15g.  "
1185                        "%s and %s will be ignored."),
1186                  "MAX", "MIN",
1187                  "MIN", pie->x_min,
1188                  "MAX", pie->x_max,
1189                  "MIN", "MAX");
1190             pie->x_min = pie->x_max = SYSMIS;
1191           }
1192       }
1193   }
1194
1195   {
1196     int i,o;
1197     double previous_p = -1;
1198     qsort (frq.percentiles, frq.n_percentiles,
1199            sizeof (*frq.percentiles),
1200            ptile_3way);
1201
1202     for (i = o = 0; i < frq.n_percentiles; ++i)
1203       {
1204         if (frq.percentiles[i].p != previous_p)
1205           {
1206             frq.percentiles[o].p = frq.percentiles[i].p;
1207             frq.percentiles[o].show = frq.percentiles[i].show;
1208             o++;
1209           }
1210         else if (frq.percentiles[i].show &&
1211                  !frq.percentiles[o].show)
1212           {
1213             frq.percentiles[o].show = true;
1214           }
1215         previous_p = frq.percentiles[i].p;
1216       }
1217
1218     frq.n_percentiles = o;
1219
1220     frq.median = NULL;
1221     for (i = 0; i < frq.n_percentiles; i++)
1222       if (frq.percentiles[i].p == 0.5)
1223         {
1224           frq.median = &frq.percentiles[i];
1225           break;
1226         }
1227   }
1228
1229   {
1230     struct casegrouper *grouper;
1231     struct casereader *group;
1232     bool ok;
1233
1234     grouper = casegrouper_create_splits (proc_open (ds), dataset_dict (ds));
1235     while (casegrouper_get_next_group (grouper, &group))
1236       {
1237         struct ccase *c;
1238         precalc (&frq, group, ds);
1239
1240         for (; (c = casereader_read (group)) != NULL; case_unref (c))
1241           calc (&frq, c, ds);
1242         postcalc (&frq, ds);
1243         casereader_destroy (group);
1244       }
1245     ok = casegrouper_destroy (grouper);
1246     ok = proc_commit (ds) && ok;
1247   }
1248
1249
1250   free (vars);
1251   free (frq.vars);
1252   free (frq.bar);
1253   free (frq.pie);
1254   free (frq.hist);
1255   free (frq.percentiles);
1256   pool_destroy (frq.pool);
1257
1258   return CMD_SUCCESS;
1259
1260  error:
1261
1262   free (vars);
1263   free (frq.vars);
1264   free (frq.bar);
1265   free (frq.pie);
1266   free (frq.hist);
1267   free (frq.percentiles);
1268   pool_destroy (frq.pool);
1269
1270   return CMD_FAILURE;
1271 }
1272
1273 static double
1274 calculate_iqr (const struct frq_proc *frq)
1275 {
1276   double q1 = SYSMIS;
1277   double q3 = SYSMIS;
1278   int i;
1279
1280   /* This cannot work unless the 25th and 75th percentile are calculated */
1281   assert (frq->n_percentiles >= 2);
1282   for (i = 0; i < frq->n_percentiles; i++)
1283     {
1284       struct percentile *pc = &frq->percentiles[i];
1285
1286       if (fabs (0.25 - pc->p) < DBL_EPSILON)
1287         q1 = pc->value;
1288       else if (fabs (0.75 - pc->p) < DBL_EPSILON)
1289         q3 = pc->value;
1290     }
1291
1292   return q1 == SYSMIS || q3 == SYSMIS ? SYSMIS : q3 - q1;
1293 }
1294
1295 static bool
1296 chart_includes_value (const struct frq_chart *chart,
1297                       const struct variable *var,
1298                       const union value *value)
1299 {
1300   if (!chart->include_missing && var_is_value_missing (var, value, MV_ANY))
1301     return false;
1302
1303   if (var_is_numeric (var)
1304       && ((chart->x_min != SYSMIS && value->f < chart->x_min)
1305           || (chart->x_max != SYSMIS && value->f > chart->x_max)))
1306     return false;
1307
1308   return true;
1309 }
1310
1311 /* Create a gsl_histogram from a freq_tab */
1312 static struct histogram *
1313 freq_tab_to_hist (const struct frq_proc *frq, const struct freq_tab *ft,
1314                   const struct variable *var)
1315 {
1316   double x_min, x_max, valid_freq;
1317   int i;
1318   double bin_width;
1319   struct histogram *histogram;
1320   double iqr;
1321
1322   /* Find out the extremes of the x value, within the range to be included in
1323      the histogram, and sum the total frequency of those values. */
1324   x_min = DBL_MAX;
1325   x_max = -DBL_MAX;
1326   valid_freq = 0;
1327   for (i = 0; i < ft->n_valid; i++)
1328     {
1329       const struct freq *f = &ft->valid[i];
1330       if (chart_includes_value (frq->hist, var, f->values))
1331         {
1332           x_min = MIN (x_min, f->values[0].f);
1333           x_max = MAX (x_max, f->values[0].f);
1334           valid_freq += f->count;
1335         }
1336     }
1337
1338   if (valid_freq <= 0)
1339     return NULL;
1340
1341   iqr = calculate_iqr (frq);
1342
1343   if (iqr > 0)
1344     /* Freedman-Diaconis' choice of bin width. */
1345     bin_width = 2 * iqr / pow (valid_freq, 1.0 / 3.0);
1346
1347   else
1348     /* Sturges Rule */
1349     bin_width = (x_max - x_min) / (1 + log2 (valid_freq));
1350
1351   histogram = histogram_create (bin_width, x_min, x_max);
1352
1353   if (histogram == NULL)
1354     return NULL;
1355
1356   for (i = 0; i < ft->n_valid; i++)
1357     {
1358       const struct freq *f = &ft->valid[i];
1359       if (chart_includes_value (frq->hist, var, f->values))
1360         histogram_add (histogram, f->values[0].f, f->count);
1361     }
1362
1363   return histogram;
1364 }
1365
1366
1367 /* Allocate an array of struct freqs and fill them from the data in FRQ_TAB,
1368    according to the parameters of CATCHART
1369    N_SLICES will contain the number of slices allocated.
1370    The caller is responsible for freeing slices
1371 */
1372 static struct freq *
1373 pick_cat_counts (const struct frq_chart *catchart,
1374                  const struct freq_tab *frq_tab,
1375                  int *n_slicesp)
1376 {
1377   int n_slices = 0;
1378   int i;
1379   struct freq *slices = xnmalloc (frq_tab->n_valid + frq_tab->n_missing, sizeof *slices);
1380
1381   for (i = 0; i < frq_tab->n_valid; i++)
1382     {
1383       const struct freq *f = &frq_tab->valid[i];
1384       if (f->count > catchart->x_max)
1385         continue;
1386
1387       if (f->count < catchart->x_min)
1388         continue;
1389
1390       slices[n_slices] = *f;
1391
1392       n_slices++;
1393     }
1394
1395   if (catchart->include_missing)
1396     {
1397       for (i = 0; i < frq_tab->n_missing; i++)
1398         {
1399           const struct freq *f = &frq_tab->missing[i];
1400           slices[n_slices].count += f->count;
1401
1402           if (i == 0)
1403             slices[n_slices].values[0] = f->values[0];
1404         }
1405
1406       if (frq_tab->n_missing > 0)
1407         n_slices++;
1408     }
1409
1410   *n_slicesp = n_slices;
1411   return slices;
1412 }
1413
1414
1415 /* Allocate an array of struct freqs and fill them from the data in FRQ_TAB,
1416    according to the parameters of CATCHART
1417    N_SLICES will contain the number of slices allocated.
1418    The caller is responsible for freeing slices
1419 */
1420 static struct freq **
1421 pick_cat_counts_ptr (const struct frq_chart *catchart,
1422                      const struct freq_tab *frq_tab,
1423                      int *n_slicesp)
1424 {
1425   int n_slices = 0;
1426   int i;
1427   struct freq **slices = xnmalloc (frq_tab->n_valid + frq_tab->n_missing, sizeof *slices);
1428
1429   for (i = 0; i < frq_tab->n_valid; i++)
1430     {
1431       struct freq *f = &frq_tab->valid[i];
1432       if (f->count > catchart->x_max)
1433         continue;
1434
1435       if (f->count < catchart->x_min)
1436         continue;
1437
1438       slices[n_slices] = f;
1439
1440       n_slices++;
1441     }
1442
1443   if (catchart->include_missing)
1444     {
1445       for (i = 0; i < frq_tab->n_missing; i++)
1446         {
1447           const struct freq *f = &frq_tab->missing[i];
1448           if (i == 0)
1449             {
1450               slices[n_slices] = xmalloc (sizeof (struct freq));
1451               slices[n_slices]->values[0] = f->values[0];
1452             }
1453
1454           slices[n_slices]->count += f->count;
1455
1456         }
1457     }
1458
1459   *n_slicesp = n_slices;
1460   return slices;
1461 }
1462
1463
1464
1465 static void
1466 do_piechart(const struct frq_chart *pie, const struct variable *var,
1467             const struct freq_tab *frq_tab)
1468 {
1469   int n_slices;
1470   struct freq *slices = pick_cat_counts (pie, frq_tab, &n_slices);
1471
1472   if (n_slices < 2)
1473     msg (SW, _("Omitting pie chart for %s, which has only %d unique values."),
1474          var_get_name (var), n_slices);
1475   else if (n_slices > 50)
1476     msg (SW, _("Omitting pie chart for %s, which has over 50 unique values."),
1477          var_get_name (var));
1478   else
1479     chart_submit (piechart_create (var, slices, n_slices));
1480
1481   free (slices);
1482 }
1483
1484
1485 static void
1486 do_barchart(const struct frq_chart *bar, const struct variable **var,
1487             const struct freq_tab *frq_tab)
1488 {
1489   int n_slices;
1490   struct freq **slices = pick_cat_counts_ptr (bar, frq_tab, &n_slices);
1491
1492   if (n_slices < 1)
1493     msg (SW, _("Omitting bar chart, which has no values."));
1494   else
1495     chart_submit (barchart_create (var, 1,
1496                                    (bar->y_scale == FRQ_FREQ) ? _("Count") : _("Percent"),
1497                                    (bar->y_scale == FRQ_PERCENT),
1498                                    slices, n_slices));
1499   free (slices);
1500 }
1501
1502
1503 /* Calculates all the pertinent statistics for VF, putting them in array
1504    D[]. */
1505 static void
1506 calc_stats (const struct frq_proc *frq, const struct var_freqs *vf,
1507             double d[FRQ_ST_count])
1508 {
1509   const struct freq_tab *ft = &vf->tab;
1510   double W = ft->valid_cases;
1511   const struct freq *f;
1512   struct moments *m;
1513   int most_often = -1;
1514   double X_mode = SYSMIS;
1515
1516   /* Calculate the mode. */
1517   for (f = ft->valid; f < ft->missing; f++)
1518     {
1519       if (most_often < f->count)
1520         {
1521           most_often = f->count;
1522           X_mode = f->values[0].f;
1523         }
1524       else if (most_often == f->count)
1525         {
1526           /* A duplicate mode is undefined.
1527              FIXME: keep track of *all* the modes. */
1528           X_mode = SYSMIS;
1529         }
1530     }
1531
1532   /* Calculate moments. */
1533   m = moments_create (MOMENT_KURTOSIS);
1534   for (f = ft->valid; f < ft->missing; f++)
1535     moments_pass_one (m, f->values[0].f, f->count);
1536   for (f = ft->valid; f < ft->missing; f++)
1537     moments_pass_two (m, f->values[0].f, f->count);
1538   moments_calculate (m, NULL, &d[FRQ_ST_MEAN], &d[FRQ_ST_VARIANCE],
1539                      &d[FRQ_ST_SKEWNESS], &d[FRQ_ST_KURTOSIS]);
1540   moments_destroy (m);
1541
1542   /* Formulae below are taken from _SPSS Statistical Algorithms_. */
1543   if (ft->n_valid > 0)
1544     {
1545       d[FRQ_ST_MINIMUM] = ft->valid[0].values[0].f;
1546       d[FRQ_ST_MAXIMUM] = ft->valid[ft->n_valid - 1].values[0].f;
1547       d[FRQ_ST_RANGE] = d[FRQ_ST_MAXIMUM] - d[FRQ_ST_MINIMUM];
1548     }
1549   else
1550     {
1551       d[FRQ_ST_MINIMUM] = SYSMIS;
1552       d[FRQ_ST_MAXIMUM] = SYSMIS;
1553       d[FRQ_ST_RANGE] = SYSMIS;
1554     }
1555   d[FRQ_ST_MODE] = X_mode;
1556   d[FRQ_ST_SUM] = d[FRQ_ST_MEAN] * W;
1557   d[FRQ_ST_STDDEV] = sqrt (d[FRQ_ST_VARIANCE]);
1558   d[FRQ_ST_SEMEAN] = d[FRQ_ST_STDDEV] / sqrt (W);
1559   d[FRQ_ST_SESKEWNESS] = calc_seskew (W);
1560   d[FRQ_ST_SEKURTOSIS] = calc_sekurt (W);
1561   d[FRQ_ST_MEDIAN] = frq->median ? frq->median->value : SYSMIS;
1562 }
1563
1564 static bool
1565 all_string_variables (const struct frq_proc *frq)
1566 {
1567   for (size_t i = 0; i < frq->n_vars; i++)
1568     if (var_is_numeric (frq->vars[i].var))
1569       return false;
1570
1571   return true;
1572 }
1573
1574 /* Displays a table of all the statistics requested. */
1575 static void
1576 dump_statistics (const struct frq_proc *frq, const struct variable *wv)
1577 {
1578   if (all_string_variables (frq))
1579     return;
1580
1581   struct pivot_table *table = pivot_table_create (N_("Statistics"));
1582   pivot_table_set_weight_var (table, wv);
1583
1584   struct pivot_dimension *variables
1585     = pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Variables"));
1586
1587   struct pivot_dimension *statistics = pivot_dimension_create (
1588     table, PIVOT_AXIS_ROW, N_("Statistics"));
1589   struct pivot_category *n = pivot_category_create_group (
1590     statistics->root, N_("N"));
1591   pivot_category_create_leaves (n,
1592                                 N_("Valid"), PIVOT_RC_COUNT,
1593                                 N_("Missing"), PIVOT_RC_COUNT);
1594   for (int i = 0; i < FRQ_ST_count; i++)
1595     if (frq->stats & BIT_INDEX (i))
1596       pivot_category_create_leaf (statistics->root,
1597                                   pivot_value_new_text (st_name[i]));
1598   struct pivot_category *percentiles = NULL;
1599   for (size_t i = 0; i < frq->n_percentiles; i++)
1600     {
1601       const struct percentile *pc = &frq->percentiles[i];
1602
1603       if (!pc->show)
1604         continue;
1605
1606       if (!percentiles)
1607         percentiles = pivot_category_create_group (
1608           statistics->root, N_("Percentiles"));
1609       pivot_category_create_leaf (percentiles, pivot_value_new_integer (
1610                                     pc->p * 100.0));
1611     }
1612
1613   for (size_t i = 0; i < frq->n_vars; i++)
1614     {
1615       struct var_freqs *vf = &frq->vars[i];
1616       if (var_is_alpha (vf->var))
1617         continue;
1618
1619       const struct freq_tab *ft = &vf->tab;
1620
1621       int var_idx = pivot_category_create_leaf (
1622         variables->root, pivot_value_new_variable (vf->var));
1623
1624       int row = 0;
1625       pivot_table_put2 (table, var_idx, row++,
1626                         pivot_value_new_number (ft->valid_cases));
1627       pivot_table_put2 (table, var_idx, row++,
1628                         pivot_value_new_number (
1629                           ft->total_cases - ft->valid_cases));
1630
1631       double stat_values[FRQ_ST_count];
1632       calc_stats (frq, vf, stat_values);
1633       for (int j = 0; j < FRQ_ST_count; j++)
1634         {
1635           if (!(frq->stats & BIT_INDEX (j)))
1636             continue;
1637
1638           union value v = { .f = vf->tab.n_valid ? stat_values[j] : SYSMIS };
1639           struct pivot_value *pv
1640             = (j == FRQ_ST_MODE || j == FRQ_ST_MINIMUM || j == FRQ_ST_MAXIMUM
1641                ? pivot_value_new_var_value (vf->var, &v)
1642                : pivot_value_new_number (v.f));
1643           pivot_table_put2 (table, var_idx, row++, pv);
1644         }
1645
1646       for (size_t j = 0; j < frq->n_percentiles; j++)
1647         {
1648           const struct percentile *pc = &frq->percentiles[j];
1649           if (!pc->show)
1650             continue;
1651
1652           union value v = { .f = vf->tab.n_valid ? pc->value : SYSMIS };
1653           pivot_table_put2 (table, var_idx, row++,
1654                             pivot_value_new_var_value (vf->var, &v));
1655         }
1656     }
1657
1658   pivot_table_submit (table);
1659 }