Mercurial > dive4elements > gnv-client
view gnv-artifacts/src/main/java/de/intevation/gnv/chart/DefaultHistogram.java @ 774:d0a39efbfd96
Removed race-condition when trying to access the index of the next line color used in charts (applied patch in issue211).
gnv-artifacts/trunk@834 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author | Ingo Weinzierl <ingo.weinzierl@intevation.de> |
---|---|
date | Fri, 26 Mar 2010 10:06:36 +0000 |
parents | 79401c871da4 |
children | 9a828e5a2390 |
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; /** * 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 <code>Locale</code> object from {@link * #requestParameter} used for i18n support. */ public static final String REQUEST_KEY_LOCALE = "locale"; /** * 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; /** * 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; } /** * @see de.intevation.gnv.chart.AbstractHistogram#applyDatasets() */ @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]); int bins = getBinCount(values); HistogramDataset dataset = new HistogramDataset(); dataset.addSeries(name, values, bins); 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) { 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; } /** * 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 calculate the number of bins this chart should be parted into. * The real calculation takes place in {@link #getBinCountByNumber} and * {@link #getBinCountByWidth}. This method switches between these methods * depending on the object stored in {@link #requestParameter}. * * @param values All values used in this histogram * * @return Number of bins */ 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(); } } /** * Method to retrieve the number of bins. If {@link #requestParameter} * contains a valid <code>Integer</code> at * <code>REQUEST_KEY_BIN_COUNT</code> and this is smaller than or equal * {@link #MAXIMAL_BINS}, this value is used. If no valid * <code>Integer</code> is given or if the value in {@link #requestParameter} * is bigger than {@link #MAXIMAL_BINS}, {@link #DEFAULT_BINS} is used. * * @return Number of bins */ 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; } } /** * Serves the number of bins depending on a given width for each bin, but * maximum bin count is limited by {@link MAXIMAL_BINS}. * * @param values All values in this histogram * * @return Number of 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 :