diff gnv-artifacts/src/main/java/de/intevation/gnv/chart/DefaultHistogram.java @ 1119:7c4f81f74c47

merged gnv-artifacts
author Thomas Arendsen Hein <thomas@intevation.de>
date Fri, 28 Sep 2012 12:14:00 +0200
parents f953c9a559d8
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gnv-artifacts/src/main/java/de/intevation/gnv/chart/DefaultHistogram.java	Fri Sep 28 12:14:00 2012 +0200
@@ -0,0 +1,234 @@
+/*
+ * Copyright (c) 2010 by Intevation GmbH
+ *
+ * This program is free software under the LGPL (>=v2.1)
+ * Read the file LGPL.txt coming with the software for details
+ * or visit http://www.gnu.org/licenses/ if it does not exist.
+ */
+
+package de.intevation.gnv.chart;
+
+import java.util.Locale;
+import java.util.Map;
+
+import org.apache.log4j.Logger;
+
+import org.jfree.chart.ChartTheme;
+
+import org.jfree.chart.plot.XYPlot;
+
+/**
+ * Default implementation of {@link de.intevation.gnv.chart.AbstractHistogram}.
+ *
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class DefaultHistogram
+extends      AbstractHistogram
+{
+    /**
+     * Default bin count.
+     * TODO find a better default value
+     */
+    public static final int DEFAULT_BINS = 15;
+
+    /**
+     * Constant field for limitating the number of bin in a single histogram.
+     */
+    public static final int MAXIMAL_BINS = 20;
+
+    /**
+     * Default key to retrieve the number of bins from {@link
+     * #requestParameter}.
+     */
+    public static final String REQUEST_KEY_BIN_COUNT   = "bincount";
+
+    /**
+     * Default key to retrieve the width of a single bin from {@link
+     * #requestParameter}.
+     */
+    public static final String REQUEST_KEY_BIN_WIDTH   = "binwidth";
+
+    /**
+     * Default key to retrieve the chart width from {@link #requestParameter}.
+     */
+    public static final String REQUEST_KEY_CHART_WIDTH = "width";
+
+    /**
+     * Default key to retrieve the object from {@link #requestParameter}. It
+     * defines which value this chart has to be used for bin calculation. You
+     * can either adjust the number of bins or the width of a single bin.
+     */
+    public static final String REQUEST_KEY_BIN_CHOICE  = "bintype";
+
+    /**
+     * Logger used for logging with log4j.
+     */
+    private static Logger logger = Logger.getLogger(DefaultHistogram.class);
+
+    /**
+     * Object storing some further parameter used for chart settings.
+     */
+    protected Map requestParameter;
+
+    protected double[] minmax = null;
+
+
+    /**
+     * Constructor to create DefaultHistogram objects.
+     *
+     * @param labels Labels to decorate this chart.
+     * @param data Raw data to be displayed in histogram.
+     * @param theme Theme used to adjust the chart look.
+     * @param requestParameter Object which serves some further settings.
+     */
+    public DefaultHistogram(
+        ChartLabels labels, Object[] data, ChartTheme theme, Map requestParameter
+    ) {
+        super(labels, data, theme);
+        this.requestParameter = requestParameter;
+        this.locale           = (Locale) requestParameter.get("locale");
+    }
+
+
+    @Override
+    protected void applyDatasets() {
+        XYPlot plot = (XYPlot) chart.getPlot();
+
+        // prepare data and create add them to histogram dataset
+        String   name   = (String)   data[0];
+        double[] values = toDouble((Double[]) data[1]);
+
+        double binWidth = getBinWidth(values);
+        int    binCount = getBinCount();
+
+        AdvancedHistogramDataset dataset =
+            new AdvancedHistogramDataset(binCount, binWidth);
+        dataset.addSeries(name, values);
+
+        plot.setDataset(0, dataset);
+    }
+
+
+    /**
+     * Method which scans the hole bunch of values and returns an array with
+     * contains min and max value. Min value is stored at position 0, max value
+     * is stored at position 1 in that array.
+     *
+     * @param values Array which contains all values
+     *
+     * @return Array which contains min and max value
+     */
+    protected double[] getMinMax(double[] values) {
+        if (minmax != null)
+            return minmax;
+
+        double[] minmax = new double[2];
+        minmax[0] = Double.MAX_VALUE;
+        minmax[1] = Double.MIN_VALUE;
+
+        int length = values.length;
+        for (int i = 0; i < length; i++) {
+            minmax[0] = values[i] < minmax[0] ? values[i] : minmax[0];
+            minmax[1] = values[i] > minmax[1] ? values[i] : minmax[1];
+        }
+
+        this.minmax = minmax;
+
+        return minmax;
+    }
+
+
+    /**
+     * Turn a Double[] into a double[].
+     *
+     * @param array Doube[]
+     *
+     * @return double[]
+     */
+    protected double[] toDouble(Double[] array) {
+        int length      = array.length;
+        double[] values = new double[length];
+
+        for(int i = 0; i < length; i++) {
+            values[i] = array[i].doubleValue();
+        }
+
+        return values;
+    }
+
+
+    /**
+     * Method to retrieve the number of bins.
+     *
+     * @return the number of bins that is specified in <i>requestParameter</i>
+     * or -1 if the number of bins is not the dominant value to calculate the
+     * width of a single bin.
+     */
+    protected int getBinCount() {
+        // Return -1 to trigger a calculation of the number of bins in
+        // AdvancedHistogramDataset if the user chose the bin width as dominant
+        // value.
+        String choice = (String) requestParameter.get(REQUEST_KEY_BIN_CHOICE);
+        if (choice != null && choice.equalsIgnoreCase(REQUEST_KEY_BIN_WIDTH)) {
+            return -1;
+        }
+
+        int    bins  = -1;
+        String param = (String) requestParameter.get(REQUEST_KEY_BIN_COUNT);
+
+        try {
+            bins = Integer.parseInt(param);
+            bins = bins <= 0 ? DEFAULT_BINS : bins;
+            bins = bins >  MAXIMAL_BINS ? MAXIMAL_BINS : bins;
+
+            return bins;
+        }
+        catch (NumberFormatException nfe) {
+            logger.warn("Invalid number of bins for histogram chart: " + param);
+            logger.warn("Return default bins: " + DEFAULT_BINS);
+
+            return DEFAULT_BINS;
+        }
+    }
+
+
+    /**
+     * Serves width of a single bin.
+     *
+     * @param values All values in this histogram
+     *
+     * @return The bin width that is given in <i>requestParameter</i> or -1 if
+     * the bin width is not the dominant value for calculating the number of
+     * bins in the histogram.
+     */
+    protected double getBinWidth(double[] values) {
+        // Return -1 to trigger a calculation of the bin width in
+        // AdvancedHistogramDataset if the user chose the number of bins as
+        // dominant value.
+        String choice = (String) requestParameter.get(REQUEST_KEY_BIN_CHOICE);
+        if (choice == null || !choice.equalsIgnoreCase(REQUEST_KEY_BIN_WIDTH)) {
+            return -1;
+        }
+
+        int    bins  = -1;
+        String param = (String) requestParameter.get(REQUEST_KEY_BIN_WIDTH);
+
+        double[] minmax     = getMinMax(values);
+        double   totalWidth = minmax[1] - minmax[0];
+        double   binWidth   = Double.parseDouble(param);
+
+        double tmpBins = totalWidth / binWidth;
+
+        bins = (int) Math.round(tmpBins);
+        bins = bins <= 0 ? DEFAULT_BINS : bins;
+
+        // the calculated number of bins with the given width exceed the maximum
+        // number of bins.
+        if (bins > MAXIMAL_BINS) {
+            return totalWidth / (MAXIMAL_BINS);
+        }
+
+        return binWidth;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :

http://dive4elements.wald.intevation.org