view gnv-artifacts/src/main/java/de/intevation/gnv/chart/AbstractXYLineChart.java @ 506:d41c155db337

Solved issue100. Improved axes range. Scale dataset to its own axis. gnv-artifacts/trunk@589 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Ingo Weinzierl <ingo.weinzierl@intevation.de>
date Thu, 21 Jan 2010 10:09:01 +0000
parents 2413273f1c13
children b98d1adee7a6
line wrap: on
line source
package de.intevation.gnv.chart;

import java.awt.Color;
import java.awt.geom.Ellipse2D;
import java.text.NumberFormat;
import java.util.Collection;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;

import org.apache.log4j.Logger;

import org.jfree.chart.JFreeChart;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.axis.Axis;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.axis.NumberTickUnit;
import org.jfree.chart.axis.AxisLocation;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.chart.title.TextTitle;
import org.jfree.data.xy.XYDataset;
import org.jfree.data.Range;
import org.jfree.data.general.Series;

import de.intevation.gnv.geobackend.base.Result;
import de.intevation.gnv.state.describedata.KeyValueDescibeData;


/**
 * @author Ingo Weinzierl <ingo.weinzierl@intevation.de>
 */
public abstract class AbstractXYLineChart
extends               AbstractChart
{
    public static final double LOWER_MARGIN = 0.05D;
    public static final double UPPER_MARGIN = 0.05D;

    private static Logger log      = Logger.getLogger(AbstractXYLineChart.class);

    protected static Color[] COLOR = {
        Color.black, Color.red, Color.green, Color.blue, Color.yellow,
        Color.gray, Color.orange, Color.pink, Color.cyan
    };

    protected static int nextColor = 0;

    protected PlotOrientation PLOT_ORIENTATION = PlotOrientation.VERTICAL;

    /** Map to store datasets for each parameter */
    protected Map datasets;

    /** Map to store max ranges of each parameter (axis.setAutoRange(true)
     * doesn't seem to work */
    protected Map ranges;

    protected abstract void initData();
    protected abstract void addValue(Result row, Series series);
    protected abstract void addSeries(Series series, String label, int idx);
    protected abstract void localizeDomainAxis(Axis axis, Locale locale);
    protected abstract String createSeriesName(
        String breakPoint1,
        String breakPoint2,
        String breakPoint3
    );


    public JFreeChart generateChart() {
        log.debug("generate XYLineChart");
        nextColor = 0;

        if (chart != null)
            return chart;

        initChart();

        chart.addSubtitle(new TextTitle(labels.getSubtitle()));

        theme.apply(chart);
        initData();

        adjustPlot((XYPlot)chart.getPlot());

        return chart;
    }


    protected void initChart() {
        chart = ChartFactory.createXYLineChart(
            labels.getTitle(),
            labels.getDomainAxisLabel(),
            null,
            null,
            PLOT_ORIENTATION,
            true,
            false,
            false
        );
    }


    protected void prepareAxis(String seriesKey, int idx) {
        log.debug("prepare axis of xychart");

        XYPlot plot      = chart.getXYPlot();
        Axis xAxis       = plot.getDomainAxis();
        NumberAxis yAxis = new NumberAxis(seriesKey);

        localizeDomainAxis(xAxis, locale);
        localizeRangeAxis(yAxis, locale);

        // litte workarround to adjust the max range of axes.
        // NumberAxis.setAutoRange(true) doesn't seem to work properly.
        Range yRange     = (Range) ranges.get(seriesKey);
        yAxis.setRange(Range.expand(yRange, LOWER_MARGIN, UPPER_MARGIN));
        log.debug("Max Range of dataset is: " + yRange.toString());

        if (seriesKey.contains("richtung")) {
            yAxis.setTickUnit(new NumberTickUnit(30.0));
            yAxis.setUpperBound(360.0);
            yAxis.setLowerBound(0.0);
        }
        else {
            yAxis.setFixedDimension(10.0);
            yAxis.setAutoRangeIncludesZero(false);
        }

        plot.setRangeAxis(idx, yAxis);
        yAxis.configure();

        if (idx % 2 != 0)
            plot.setRangeAxisLocation(idx, AxisLocation.BOTTOM_OR_RIGHT);
        else
            plot.setRangeAxisLocation(idx, AxisLocation.BOTTOM_OR_LEFT);

        plot.mapDatasetToRangeAxis(idx, idx);
    }


    protected void adjustRenderer(
        int     idx,
        int     seriesCount,
        boolean renderLines,
        boolean renderShapes
    ) {
        log.debug("Adjust render of series");
        XYLineAndShapeRenderer renderer = null;
        XYPlot                 plot     = chart.getXYPlot();

        try {
            renderer = (XYLineAndShapeRenderer)((XYLineAndShapeRenderer)
                (plot.getRenderer())).clone();
        }
        catch (CloneNotSupportedException cnse) {
            log.warn("Error while cloning renderer.", cnse);
            renderer = new XYLineAndShapeRenderer(renderLines, renderShapes);
            renderer.setBaseShape(new Ellipse2D.Double(-2,-2,4,4));
        }

        for (int i = 0; i < seriesCount; i++) {
            renderer.setSeriesShape(i, renderer.getSeriesShape(0));
            renderer.setSeriesPaint(i, COLOR[nextColor%COLOR.length]);
            renderer.setSeriesShapesVisible(i, renderShapes);
            renderer.setSeriesLinesVisible(i, renderLines);
            nextColor++;
        }
        plot.setRenderer(idx, renderer);
    }


    protected void adjustPlot(XYPlot plot) {
        if (plot.getRangeAxisCount() > 1)
            plot.setRangeGridlinesVisible(false);
    }


    protected void localizeRangeAxis(Axis axis, Locale locale) {
        if (locale == null)
            return;

        log.debug(
            "Set language of axis [" + axis.getLabel() + "] " +
            "to " + locale.toString()
        );

        NumberFormat format = NumberFormat.getInstance(locale);
        ((NumberAxis) axis).setNumberFormatOverride(format);
    }


    public Range getMaxRangeOfDataset(XYDataset dataset) {
        int    seriesCount = dataset.getSeriesCount();
        double upper       = Double.NEGATIVE_INFINITY;
        double lower       = Double.POSITIVE_INFINITY;

        for (int i = 0; i < seriesCount; i++) {
            int itemCount = dataset.getItemCount(i);

            for (int j = 0; j < itemCount; j++) {
                Number num = dataset.getY(i, j);

                if (num != null) {
                    double y = num.doubleValue();
                    lower    = y < lower ? y : lower;
                    upper    = y > upper ? y : upper;
                }
            }
        }

        return new Range(lower, upper);
    }


    public Range getMaxRangeOfDatasetWithMargin(
        XYDataset dataset,
        double    percent
    ) {
        Range range   = getMaxRangeOfDataset(dataset);
        double length = range.getLength();
        double upper  = range.getUpperBound() + length /100 * percent;
        double lower  = range.getLowerBound() - length /100 * percent;

        return new Range(lower, upper);
    }


    protected String findParameter(String label) {
        Iterator iter = parameters.iterator();

        while (iter.hasNext()) {
            KeyValueDescibeData data = (KeyValueDescibeData) iter.next();
            String              key  = data.getValue();

            if (label.indexOf(key) > -1)
                return key;
        }

        return label;
    }


    protected String findValueTitle(Collection values, String id) {
        log.debug("find description of dataset");

        if (values != null){
            Iterator it = values.iterator();
            while (it.hasNext()) {
                KeyValueDescibeData data = (KeyValueDescibeData) it.next();

                if (id.equals(data.getKey()))
                    return data.getValue();
            }
        }
        return "";
    }


    protected void storeMaxRange(double value, String parameter) {
        Range  range     = null;

        range = ranges.containsKey(parameter)
            ? (Range) ranges.get(parameter)
            : new Range(value, value);

        double lower = range.getLowerBound();
        double upper = range.getUpperBound();

        lower = value < lower ? value : lower;
        upper = value > upper ? value : upper;

        ranges.put(parameter, new Range(lower, upper));
    }
}
// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :

http://dive4elements.wald.intevation.org