# HG changeset patch # User Ingo Weinzierl # Date 1328197453 0 # Node ID 23c7c51df7726aef72eccf8a29dda40710eff290 # Parent 60615235e95160b9a6d1f760437d4f4901abe09b Some more refactoring in XYChartGenerator and ChartGenerator; implemented necessary stuff in TimeseriesChartGenerator and return new empty instances of timeseries charts. flys-artifacts/trunk@3885 c6561f87-3c4e-4783-a992-168aeb5c3f6f diff -r 60615235e951 -r 23c7c51df772 flys-artifacts/ChangeLog --- a/flys-artifacts/ChangeLog Thu Feb 02 15:39:28 2012 +0000 +++ b/flys-artifacts/ChangeLog Thu Feb 02 15:44:13 2012 +0000 @@ -1,3 +1,15 @@ +2012-02-02 Ingo Weinzierl + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java, + src/main/java/de/intevation/flys/exports/ChartGenerator.java: More + refactoring: the AxisDataset is defined by an interface in ChartGenerator + now. Each subclass of ChartGenerator should implement its own AxisDataset. + This allows us to provide multiple XYDataset types in different charts. + + * src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java: + Implemented some necessary methods (abstract definitions of parent class) + and create new empty timeseries charts. + 2012-02-02 Ingo Weinzierl * src/main/java/de/intevation/flys/exports/ChartHelper.java: New helper diff -r 60615235e951 -r 23c7c51df772 flys-artifacts/src/main/java/de/intevation/flys/exports/ChartGenerator.java --- a/flys-artifacts/src/main/java/de/intevation/flys/exports/ChartGenerator.java Thu Feb 02 15:39:28 2012 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/ChartGenerator.java Thu Feb 02 15:44:13 2012 +0000 @@ -9,6 +9,8 @@ import java.util.ArrayList; import java.util.List; import java.util.Locale; +import java.util.TreeMap; +import java.util.SortedMap; import javax.xml.xpath.XPathConstants; @@ -21,6 +23,7 @@ import org.jfree.chart.LegendItem; import org.jfree.chart.axis.NumberAxis; import org.jfree.data.Range; +import org.jfree.data.xy.XYDataset; import de.intevation.artifacts.Artifact; import de.intevation.artifacts.CallContext; @@ -88,17 +91,43 @@ /** The settings that should be used during output creation.*/ protected Settings settings; + /** Map of datasets ("index"). */ + protected SortedMap datasets; + + /** * A mini interface that allows to walk over the YAXIS enums defined in * subclasses. */ public interface YAxisWalker { + int length(); + String getId(int idx); + } // end of YAxisWalker interface + + + + public interface AxisDataset { + + void addDataset(XYDataset dataset); + + boolean isEmpty(); + + } // end of AxisDataset interface + + + + /** + * Default constructor that initializes internal data structures. + */ + public ChartGenerator() { + datasets = new TreeMap(); } + /** * This method needs to be implemented by concrete subclasses to create new * instances of JFreeChart. @@ -145,6 +174,25 @@ /** + * This method is used to create new AxisDataset instances which may differ + * in concrete subclasses. + * + * @param idx The index of an axis. + */ + protected abstract AxisDataset createAxisDataset(int idx); + + + /** + * Combines the ranges of the X axis at index idx. + * + * @param range A new range. + * @param idx The index of the X axis that should be comined with + * range. + */ + protected abstract void combineXRanges(Range range, int idx); + + + /** * This method should be used by concrete subclasses to add subtitle to * chart. The method in this implementation is empty. * @@ -731,6 +779,59 @@ /** + * Adds a new AxisDataset which contains dataset at index idx. + * + * @param dataset An XYDataset. + * @param idx The axis index. + * @param visible Determines, if the dataset should be visible or not. + */ + public void addAxisDataset(XYDataset dataset, int idx, boolean visible) { + if (dataset == null || idx < 0) { + return; + } + + AxisDataset axisDataset = getAxisDataset(idx); + + Range[] xyRanges = ChartHelper.getRanges(dataset); + + if (visible) { + logger.debug("Add new AxisDataset at index: " + idx); + axisDataset.addDataset(dataset); + combineXRanges(xyRanges[0], 0); + } + else { + combineXRanges(xyRanges[0], 0); + + // TODO + // Expand y range provided by 'timeseries' to have a proper range + // set which includes all data. + // iw: I am not sure if we still need this + } + } + + + /** + * This method grants access to the AxisDatasets stored in datasets. + * If no AxisDataset exists for index idx, a new AxisDataset is + * created using createAxisDataset(). + * + * @param idx The index of the desired AxisDataset. + * + * @return an existing or new AxisDataset. + */ + public AxisDataset getAxisDataset(int idx) { + AxisDataset axisDataset = datasets.get(idx); + + if (axisDataset == null) { + axisDataset = createAxisDataset(idx); + datasets.put(idx, axisDataset); + } + + return axisDataset; + } + + + /** * This helper mehtod is used to extract the current locale from instance * vairable context. * @@ -947,6 +1048,29 @@ /** + * Create Y (range) axis for given index. + * Shall be overriden by subclasses. + */ + protected NumberAxis createYAxis(int index) { + YAxisWalker walker = getYAxisWalker(); + + Font labelFont = new Font( + DEFAULT_FONT_NAME, + Font.BOLD, + getYAxisFontSize(index)); + + IdentifiableNumberAxis axis = new IdentifiableNumberAxis( + walker.getId(index), + getYAxisLabel(index)); + + axis.setAutoRangeIncludesZero(false); + axis.setLabelFont(labelFont); + + return axis; + } + + + /** * Creates a new LegendItem with name and font provided by * createLegendLabelFont(). * diff -r 60615235e951 -r 23c7c51df772 flys-artifacts/src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java --- a/flys-artifacts/src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java Thu Feb 02 15:39:28 2012 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java Thu Feb 02 15:44:13 2012 +0000 @@ -1,10 +1,22 @@ package de.intevation.flys.exports; +import java.awt.Color; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import org.apache.log4j.Logger; +import org.jfree.chart.ChartFactory; import org.jfree.chart.JFreeChart; import org.jfree.chart.axis.NumberAxis; +import org.jfree.chart.plot.XYPlot; + +import org.jfree.data.Range; +import org.jfree.data.time.TimeSeriesCollection; +import org.jfree.data.xy.XYDataset; /** @@ -12,20 +24,139 @@ */ public abstract class TimeseriesChartGenerator extends ChartGenerator { + + /** + * Inner class TimeseriesAxisDataset stores TimeSeriesCollection. + */ + public class TimeseriesAxisDataset implements AxisDataset { + + protected int axisSymbol; + + protected List datasets; + + protected Range range; + + protected int plotAxisIndex; + + + public TimeseriesAxisDataset(int axisSymbol) { + this.axisSymbol = axisSymbol; + this.datasets = new ArrayList(); + } + + + @Override + public void addDataset(XYDataset dataset) { + if (!(dataset instanceof TimeSeriesCollection)) { + logger.warn("Skip non TimeSeriesCollection dataset."); + return; + } + + TimeSeriesCollection tsc = (TimeSeriesCollection) dataset; + + datasets.add(tsc); + mergeRanges(tsc); + } + + + @Override + public boolean isEmpty() { + return datasets.isEmpty(); + } + + + protected void mergeRanges(TimeSeriesCollection dataset) { + logger.debug("Range after merging: " + range); + + Range[] xyRanges = ChartHelper.getRanges(dataset); + range = Range.combine(range, xyRanges[1]); + + logger.debug("Range after merging: " + range); + } + + } // end of TimeseriesAxisDataset class + + + private static final Logger logger = Logger.getLogger(TimeseriesChartGenerator.class); - protected abstract NumberAxis createYAxis(int index); + protected Map xRanges; + + + + /** + * The default constructor that initializes internal datastructures. + */ + public TimeseriesChartGenerator() { + super(); + + xRanges = new HashMap(); + } + @Override public JFreeChart generateChart() { logger.info("Generate Timeseries Chart."); + JFreeChart chart = ChartFactory.createTimeSeriesChart( + getChartTitle(), + getXAxisLabel(), + getYAxisLabel(0), + null, + true, + false, + false); + logger.warn("TODO: IMPLEMENT ME!"); - return null; + XYPlot plot = (XYPlot) chart.getPlot(); + + chart.setBackgroundPaint(Color.WHITE); + plot.setBackgroundPaint(Color.WHITE); + + addSubtitles(chart); + addDatasets(plot); + + return chart; + } + + + /** + * This method creates new instances of TimeseriesAxisDataset. + * + * @param idx The symbol for the new TimeseriesAxisDataset. + */ + @Override + protected AxisDataset createAxisDataset(int idx) { + logger.debug("Create a new AxisDataset for index: " + idx); + return new TimeseriesAxisDataset(idx); + } + + + /** + * Effect: extend range of x axis to include given limits. + * @param range the given ("minimal") range. + * @param index index of axis to be merged. + */ + @Override + protected void combineXRanges(Range range, int index) { + if (range != null) { + Range old = xRanges.get(index); + + if (old != null) { + range = Range.combine(old, range); + } + + xRanges.put(index, range); + } + } + + + protected void addDatasets(XYPlot plot) { + logger.warn("TODO: IMPLEMENT ME!"); } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r 60615235e951 -r 23c7c51df772 flys-artifacts/src/main/java/de/intevation/flys/exports/XYChartGenerator.java --- a/flys-artifacts/src/main/java/de/intevation/flys/exports/XYChartGenerator.java Thu Feb 02 15:39:28 2012 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/XYChartGenerator.java Thu Feb 02 15:44:13 2012 +0000 @@ -83,7 +83,7 @@ public abstract class XYChartGenerator extends ChartGenerator { // TODO Consider storing the renderer here. - private class AxisDataset { + private class XYAxisDataset implements AxisDataset { /** Symbolic integer, but also coding the priority (0 goes first). */ protected int axisSymbol; /** List of assigned datasets (in order). */ @@ -94,7 +94,7 @@ protected int plotAxisIndex; /** Create AxisDataset. */ - public AxisDataset(int symb) { + public XYAxisDataset(int symb) { this.axisSymbol = symb; datasets = new ArrayList(); } @@ -114,10 +114,16 @@ range = Range.combine(range, subRange); } + + @Override + public void addDataset(XYDataset dataset) { + datasets.add(dataset); + includeYRange(((XYSeriesCollection) dataset).getSeries(0)); + } + /** Add a dataset, include its range. */ - public void addDataset(XYSeries dataset) { - this.datasets.add(new XYSeriesCollection(dataset)); - includeYRange(dataset); + public void addDataset(XYSeries series) { + addDataset(new XYSeriesCollection(series)); } public void addArea(StyledAreaSeriesCollection series) { @@ -172,9 +178,6 @@ /** The logger that is used in this generator. */ private static Logger logger = Logger.getLogger(XYChartGenerator.class); - /** Map of datasets ("index"). */ - protected SortedMap datasets; - /** List of annotations to insert in plot. */ protected List annotations; @@ -186,9 +189,10 @@ public XYChartGenerator() { + super(); + xRanges = new HashMap(); yRanges = new HashMap(); - datasets = new TreeMap(); } @@ -236,6 +240,13 @@ } + @Override + protected AxisDataset createAxisDataset(int idx) { + logger.debug("Create new XYAxisDataset for index: " + idx); + return new XYAxisDataset(idx); + } + + /** * Put debug output about datasets. */ @@ -288,7 +299,7 @@ for (Map.Entry entry: datasets.entrySet()) { if (!entry.getValue().isEmpty()) { // Add axis and range information. - AxisDataset axisDataset = entry.getValue(); + XYAxisDataset axisDataset = (XYAxisDataset) entry.getValue(); NumberAxis axis = createYAxis(entry.getKey()); plot.setRangeAxis(axisIndex, axis); @@ -324,12 +335,8 @@ logger.warn("Cannot yet render above/under curve."); return; } - AxisDataset axisDataset = datasets.get(index); - if (axisDataset == null) { - axisDataset = new AxisDataset(index); - datasets.put(index, axisDataset); - } + XYAxisDataset axisDataset = (XYAxisDataset) getAxisDataset(index); if (visible) { axisDataset.addArea(area); @@ -349,30 +356,19 @@ * @param visible whether or not the data should be plotted. */ public void addAxisSeries(XYSeries series, int index, boolean visible) { + addAxisDataset(new XYSeriesCollection(series), index, visible); + if (series == null) { return; } - AxisDataset axisDataset = datasets.get(index); - - if (axisDataset == null) { - axisDataset = new AxisDataset(index); - datasets.put(index, axisDataset); - } + XYAxisDataset axisDataset = (XYAxisDataset) getAxisDataset(index); - logger.debug("addAxisSeries: extent X " + series.getMinX() + " : " + series.getMaxX() - + " extent y " + series.getMinY() + " : " + series.getMaxY()); - - if (visible) { - axisDataset.addDataset(series); - } - else { + if (!visible) { // Do this also when not visible to have axis scaled by default such // that every data-point could be seen (except for annotations). axisDataset.includeYRange(series); } - - combineXRanges(new Range(series.getMinX(), series.getMaxX()), 0); } @@ -381,7 +377,7 @@ * @param range the given ("minimal") range. * @param index index of axis to be merged. */ - private void combineXRanges(Range range, int index) { + protected void combineXRanges(Range range, int index) { if (range == null || Double.isNaN(range.getLowerBound()) @@ -416,29 +412,6 @@ /** - * Create Y (range) axis for given index. - * Shall be overriden by subclasses. - */ - protected NumberAxis createYAxis(int index) { - YAxisWalker walker = getYAxisWalker(); - - Font labelFont = new Font( - DEFAULT_FONT_NAME, - Font.BOLD, - getYAxisFontSize(index)); - - IdentifiableNumberAxis axis = new IdentifiableNumberAxis( - walker.getId(index), - getYAxisLabel(index)); - - axis.setAutoRangeIncludesZero(false); - axis.setLabelFont(labelFont); - - return axis; - } - - - /** * If no data is visible, draw at least empty axis. */ private void recoverEmptyPlot(XYPlot plot) { @@ -687,7 +660,7 @@ // Do the more complicated case where we stick to the Y-Axis. // There is one nasty case (duration curves, where annotations // might stick to the second y-axis). - AxisDataset dataset = this.datasets.get( + XYAxisDataset dataset = (XYAxisDataset) getAxisDataset( new Integer(annotation.getAxisSymbol())); if (dataset == null) { logger.warn("Annotation should stick to unfindable y-axis: "