view gnv-artifacts/src/main/java/de/intevation/gnv/chart/DefaultHistogram.java @ 629:d08b9ba148c5

Implemented logic to adjust number of bins corresponding to user input. gnv-artifacts/trunk@706 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Ingo Weinzierl <ingo.weinzierl@intevation.de>
date Wed, 24 Feb 2010 14:30:52 +0000
parents 65f09139e9b3
children 79401c871da4
line wrap: on
line source
package de.intevation.gnv.chart;

import java.text.NumberFormat;
import java.text.ParseException;
import java.util.Locale;
import java.util.Map;

import org.apache.log4j.Logger;

import org.jfree.chart.ChartTheme;

import org.jfree.chart.plot.XYPlot;

import org.jfree.data.statistics.HistogramDataset;

/**
 * @author Ingo Weinzierl (ingo.weinzierl@intevation.de)
 */
public class DefaultHistogram
extends      AbstractHistogram
{
    // TODO take a better default value
    public static final int DEFAULT_BINS = 15;
    public static final int MAXIMAL_BINS = 20;
    public static final String REQUEST_KEY_BIN_COUNT   = "bincount";
    public static final String REQUEST_KEY_BIN_WIDTH   = "binwidth";
    public static final String REQUEST_KEY_CHART_WIDTH = "width";
    public static final String REQUEST_KEY_LOCALE      = "locale";
    public static final String REQUEST_KEY_BIN_CHOICE  = "bintype";

    private static Logger logger = Logger.getLogger(DefaultHistogram.class);

    protected Map requestParameter;


    public DefaultHistogram(
        ChartLabels labels, Object[] data, ChartTheme theme, Map requestParameter
    ) {
        super(labels, data, theme);
        this.requestParameter = requestParameter;
    }


    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]);
        int      bins   = getBinCount(values);

        HistogramDataset dataset = new HistogramDataset();
        dataset.addSeries(name, values, bins);

        plot.setDataset(0, dataset);
    }


    protected double[] getMinMax(double[] values) {
        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];
        }

        return minmax;
    }


    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;
    }


    protected int getBinCount(double[] values) {
        String param = (String) requestParameter.get(REQUEST_KEY_BIN_CHOICE);

        if (param != null && param.equalsIgnoreCase(REQUEST_KEY_BIN_WIDTH)) {
            return getBinCountByWidth(values);
        }
        else {
            return getBinCountByNumber();
        }
    }


    protected int getBinCountByNumber() {
        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;
        }
    }


    protected int getBinCountByWidth(double[] values) {
        int    bins   = -1;
        String param  = (String) requestParameter.get(REQUEST_KEY_BIN_WIDTH);
        Locale locale = (Locale) requestParameter.get(REQUEST_KEY_LOCALE);
        NumberFormat format = NumberFormat.getInstance(locale);

        try {
            double[] minmax     = getMinMax(values);
            double   totalWidth = minmax[1] - minmax[0];
            Number   number     = format.parse(param);
            double   binWidth   = -1d;

            if (number instanceof Double) {
                binWidth = ((Double) number).doubleValue();
            }
            else if (number instanceof Long) {
                binWidth = ((Long) number).doubleValue();
            }
            else if (number instanceof Integer) {
                binWidth = ((Integer) number).doubleValue();
            }
            else {
                logger.warn("Invalid bin width for histogram chart: " + param);
                logger.warn("Return default bins: " + DEFAULT_BINS);

                return DEFAULT_BINS;
            }

            double tmpBins = totalWidth / binWidth;

            bins = (int) Math.round(tmpBins);
            bins = bins <= 0 ? DEFAULT_BINS : bins;
            bins = bins >  MAXIMAL_BINS ? MAXIMAL_BINS : bins;

            return bins;
        }
        catch (ParseException pe) {
            logger.warn("Invalid bin width for histogram chart: " + param);
            logger.warn("Return default bins: " + DEFAULT_BINS);

            return DEFAULT_BINS;
        }
        catch (NumberFormatException nfe) {
            logger.warn("Invalid bin width for histogram chart: " + param);
            logger.warn("Return default bins: " + DEFAULT_BINS);

            return DEFAULT_BINS;
        }
    }
}
// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :

http://dive4elements.wald.intevation.org