histogram tick drawing - added format generation for optimum tick drawing
[pspp] / src / output / charts / plot-hist-cairo.c
index 87409b1a90937bd76a62c668e033df74bbc80aea..7e2afee9b022cc621578623c889a474ad7b033dc 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2009, 2011 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2011, 2014 Free Software Foundation, Inc.
 
    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
    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
 
 #include <config.h>
-
+#include "math/chart-geometry.h"
 #include "output/charts/plot-hist.h"
 
+#include <float.h>
 #include <gsl/gsl_randist.h>
 
 #include "data/val-type.h"
 #include "output/cairo-chart.h"
 
 #include "gl/xvasprintf.h"
+#include "gl/minmax.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -67,7 +69,8 @@ histogram_write_legend (cairo_t *cr, const struct xrchart_geometry *geom,
 
 static void
 hist_draw_bar (cairo_t *cr, const struct xrchart_geometry *geom,
-               const gsl_histogram *h, int bar, bool label)
+               const gsl_histogram *h, int bar, const char *tick_format_string,
+              const double tickscale, const bool tickoversize)
 {
   double upper;
   double lower;
@@ -101,9 +104,9 @@ hist_draw_bar (cairo_t *cr, const struct xrchart_geometry *geom,
   cairo_restore (cr);
   cairo_stroke (cr);
 
-  if (label)
-    draw_tick (cr, geom, SCALE_ABSCISSA,
-              x_pos + width / 2.0, "%g", (upper + lower) / 2.0);
+  draw_tick (cr, geom, SCALE_ABSCISSA, tickoversize,
+            x_pos + width / 2.0, tick_format_string, (upper+lower)/2.0*tickscale);
+
 }
 
 void
@@ -113,6 +116,11 @@ xrchart_draw_histogram (const struct chart_item *chart_item, cairo_t *cr,
   struct histogram_chart *h = to_histogram_chart (chart_item);
   int i;
   int bins;
+  char *tick_format_string;
+  char *test_text;
+  double width, left_width, right_width, unused;
+  double tickscale;
+  bool tickoversize;
 
   xrchart_write_title (cr, geom, _("HISTOGRAM"));
 
@@ -125,14 +133,28 @@ xrchart_draw_histogram (const struct chart_item *chart_item, cairo_t *cr,
       return;
     }
 
-  bins = gsl_histogram_bins (h->gsl_hist);
-
-  xrchart_write_yscale (cr, geom, 0, gsl_histogram_max_val (h->gsl_hist), 5);
+  xrchart_write_yscale (cr, geom, 0, gsl_histogram_max_val (h->gsl_hist));
 
+  /* Draw the ticks and compute if the rendered tick text is wider than the bin */
+  bins = gsl_histogram_bins (h->gsl_hist);
+  tick_format_string = chart_get_ticks_format (gsl_histogram_max (h->gsl_hist),
+                                              gsl_histogram_min (h->gsl_hist),
+                                              bins,
+                                              &tickscale);
+  test_text = xasprintf(tick_format_string, gsl_histogram_max (h->gsl_hist)*tickscale);
+  xrchart_text_extents (cr, geom, test_text, &right_width, &unused);
+  free(test_text);
+  test_text = xasprintf(tick_format_string, gsl_histogram_min (h->gsl_hist)*tickscale);
+  xrchart_text_extents (cr, geom, test_text, &left_width, &unused);
+  free(test_text);
+  width = MAX(left_width, right_width);
+  tickoversize = width > 0.9 *
+    ((double)(geom->axis[SCALE_ABSCISSA].data_max - geom->axis[SCALE_ABSCISSA].data_min))/bins;
   for (i = 0; i < bins; i++)
     {
-      hist_draw_bar (cr, geom, h->gsl_hist, i, true);
+      hist_draw_bar (cr, geom, h->gsl_hist, i, tick_format_string, tickscale, tickoversize);
     }
+  free(tick_format_string);
 
   histogram_write_legend (cr, geom, h->n, h->mean, h->stddev);