# HG changeset patch # User Felix Wolfsteller # Date 1322119246 0 # Node ID 7c52e9cb2a72009558cb8837548aceb7a664ca7a # Parent de0c2bbb27f910014bb3b777906dbaf88839291b Allow more than two datasets and more flexibility with axes in plots. Based on patch by S. Teichmann. flys-artifacts/trunk@3312 c6561f87-3c4e-4783-a992-168aeb5c3f6f diff -r de0c2bbb27f9 -r 7c52e9cb2a72 flys-artifacts/ChangeLog --- a/flys-artifacts/ChangeLog Wed Nov 23 14:09:29 2011 +0000 +++ b/flys-artifacts/ChangeLog Thu Nov 24 07:20:46 2011 +0000 @@ -1,3 +1,30 @@ +2011-11-24 Felix Wolfsteller + + In XYChartGenerators allow more than two datasets. + Assign axis to indices of datasets, do not show axis if corresponding + dataset is set to be not visible. + Do proper axis-setting in LongitudinalSectionGenerator only (other + will follow). Based on a patch by Sascha Teichmann. + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Keep relation between index and dataset, once its added. Compute + ranges per index. Allow subclasses to override createAxes to specify + internationalized labels etc. + + * src/main/java/de/intevation/flys/exports/DischargeCurveGenerator.java, + src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java, + src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java, + src/main/java/de/intevation/flys/exports/DurationCurveGenerator.java, + src/main/java/de/intevation/flys/exports/WDifferencesCurveGenerator.java, + src/main/java/de/intevation/flys/exports/DischargeLongitudinalSectionGenerator.java: + Add datasets to first index. + + * src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java: + Implement createYAxis to create correct first, second and third + axis. Added enum to easy identification of axis. Stripped down + adjustAxis which was used to create second axis. + Add datasets at correct indices. + 2011-11-23 Felix Wolfsteller * src/main/java/de/intevation/flys/artifacts/datacage/templating/StackFrames.java, diff -r de0c2bbb27f9 -r 7c52e9cb2a72 flys-artifacts/src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java --- a/flys-artifacts/src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java Wed Nov 23 14:09:29 2011 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java Thu Nov 24 07:20:46 2011 +0000 @@ -144,7 +144,7 @@ XYSeries series = new StyledXYSeries(facet.getDescription(), theme); StyledSeriesBuilder.addPoints(series, data); - addFirstAxisSeries(series, visible); + addAxisSeries(series, 0, visible); } /** @@ -161,7 +161,7 @@ XYSeries series = new StyledXYSeries(facet.getDescription(), theme); StyledSeriesBuilder.addPointsQW(series, wqkms); - addFirstAxisSeries(series, visible); + addAxisSeries(series, 0, visible); } diff -r de0c2bbb27f9 -r 7c52e9cb2a72 flys-artifacts/src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java --- a/flys-artifacts/src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java Wed Nov 23 14:09:29 2011 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java Thu Nov 24 07:20:46 2011 +0000 @@ -194,7 +194,7 @@ StyledSeriesBuilder.addPoints(series, (double [][]) o); - addFirstAxisSeries(series, visible); + addAxisSeries(series, 0, visible); } @@ -216,7 +216,7 @@ StyledSeriesBuilder.addPoints(series, (double [][]) o); - addFirstAxisSeries(series, visible); + addAxisSeries(series, 0, visible); } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r de0c2bbb27f9 -r 7c52e9cb2a72 flys-artifacts/src/main/java/de/intevation/flys/exports/DischargeCurveGenerator.java --- a/flys-artifacts/src/main/java/de/intevation/flys/exports/DischargeCurveGenerator.java Wed Nov 23 14:09:29 2011 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/DischargeCurveGenerator.java Thu Nov 24 07:20:46 2011 +0000 @@ -171,7 +171,7 @@ StyledSeriesBuilder.addPointsQW(series, wqkms); - addFirstAxisSeries(series, visible); + addAxisSeries(series, 0, visible); } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r de0c2bbb27f9 -r 7c52e9cb2a72 flys-artifacts/src/main/java/de/intevation/flys/exports/DischargeLongitudinalSectionGenerator.java --- a/flys-artifacts/src/main/java/de/intevation/flys/exports/DischargeLongitudinalSectionGenerator.java Wed Nov 23 14:09:29 2011 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/DischargeLongitudinalSectionGenerator.java Thu Nov 24 07:20:46 2011 +0000 @@ -108,7 +108,7 @@ series.add(wqckms.getKm(i), wqckms.getC(i)); } - addFirstAxisSeries(series, visible); + addAxisSeries(series, 0, visible); } if (wqckms.guessWaterIncreasing()) { diff -r de0c2bbb27f9 -r 7c52e9cb2a72 flys-artifacts/src/main/java/de/intevation/flys/exports/DurationCurveGenerator.java --- a/flys-artifacts/src/main/java/de/intevation/flys/exports/DurationCurveGenerator.java Wed Nov 23 14:09:29 2011 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/DurationCurveGenerator.java Thu Nov 24 07:20:46 2011 +0000 @@ -184,7 +184,7 @@ series.add((double) day, w); } - addFirstAxisSeries(series, visible); + addAxisSeries(series, 0, visible); } @@ -209,7 +209,7 @@ series.add((double) day, q); } - addSecondAxisSeries(series, visible); + addAxisSeries(series, 1, visible); } @@ -238,5 +238,7 @@ logger.warn("Could not determine chart curve type: " + type); return type; } + + // MainValue-Annotations should be visualized by a line that goes to the curve itself. } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r de0c2bbb27f9 -r 7c52e9cb2a72 flys-artifacts/src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java --- a/flys-artifacts/src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java Wed Nov 23 14:09:29 2011 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java Thu Nov 24 07:20:46 2011 +0000 @@ -39,6 +39,16 @@ extends XYChartGenerator implements FacetTypes { + public static enum YAXIS { + W(0), + Q(1), + D(2); + protected int idx; + private YAXIS(int c) { + idx = c; + } + } + /** The logger that is used in this generator. */ private static Logger logger = Logger.getLogger(LongitudinalSectionGenerator.class); @@ -161,6 +171,29 @@ /** + * Create Axis for given index. + * @return axis with according internationalized label. + */ + @Override + protected NumberAxis createYAxis(int index) { + Font labelFont = new Font("Tahoma", Font.BOLD, 14); + String label = "default"; + if (index == YAXIS.W.idx) { + label = getYAxisLabel(); + } + else if (index == YAXIS.Q.idx) { + label = msg(get2YAxisLabelKey(), get2YAxisDefaultLabel()); + } + else if (index == YAXIS.D.idx) { + // TODO: diff label + label = "TODO: diff"; + } + NumberAxis axis = new NumberAxis(label); + axis.setLabelFont(labelFont); + return axis; + } + + /** * Get default value for the second Y-Axis' label (if no translation was * found). */ @@ -178,23 +211,11 @@ /** - * Adjust the axis to meet LongitudinalSection diagram demands. - * (e.g. add second Y-axis with internationalized label, trigger - * inversion). - * @param see get2YAxisLabelKey, get2YAxisDefaultLabel + * Trigger inversion. */ @Override protected void adjustAxes(XYPlot plot) { super.adjustAxes(plot); - - NumberAxis qAxis = new NumberAxis( - msg(get2YAxisLabelKey(), get2YAxisDefaultLabel())); - - plot.setRangeAxis(1, qAxis); - - Font font = plot.getRangeAxis(0).getLabelFont(); - qAxis.setLabelFont(font); - invertXAxis(plot.getDomainAxis()); } @@ -321,7 +342,7 @@ StyledSeriesBuilder.addPoints(series, wkms); - addFirstAxisSeries(series, visible); + addAxisSeries(series, YAXIS.W.idx, visible); if (wkms instanceof WQKms) { if (needInvertAxis((WQKms) wkms)) { @@ -359,7 +380,7 @@ StyledSeriesBuilder.addPoints(series, wkms); - addSecondAxisSeries(series, visible); + addAxisSeries(series, YAXIS.D.idx, visible); if (DataUtil.guessWaterIncreasing(wkms.allWs())) { setInverted(true); } @@ -389,7 +410,7 @@ StyledSeriesBuilder.addPoints(series, wqkms); - addSecondAxisSeries(series, visible); + addAxisSeries(series, YAXIS.Q.idx, visible); if (needInvertAxis(wqkms)) { setInverted(true); diff -r de0c2bbb27f9 -r 7c52e9cb2a72 flys-artifacts/src/main/java/de/intevation/flys/exports/WDifferencesCurveGenerator.java --- a/flys-artifacts/src/main/java/de/intevation/flys/exports/WDifferencesCurveGenerator.java Wed Nov 23 14:09:29 2011 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/WDifferencesCurveGenerator.java Thu Nov 24 07:20:46 2011 +0000 @@ -5,6 +5,7 @@ import org.jfree.chart.title.TextTitle; import org.jfree.chart.JFreeChart; +import org.jfree.chart.axis.NumberAxis; import org.jfree.chart.plot.XYPlot; import org.jfree.data.xy.XYSeries; import org.jfree.data.Range; @@ -189,7 +190,7 @@ // Note: the only difference in the super-implementation // (in LongitudinalSectionGenerator) is here (adds with // addFirstAxisSeries() . - addSecondAxisSeries(series, visible); + addAxisSeries(series, 3, visible); if (wkms instanceof WQKms) { if (needInvertAxis((WQKms) wkms)) { @@ -245,12 +246,18 @@ StyledSeriesBuilder.addPoints(series, wkms); - addFirstAxisSeries(series, visible); + addAxisSeries(series, 0, visible); if (DataUtil.guessWaterIncreasing(wkms.allWs())) { setInverted(true); } } + @Override + protected NumberAxis createYAxis(int index) { + String s = "" + index; + return new NumberAxis(s); + } + /** * Disable Longitudinals behaviour to include "0" in the Q axis. * diff -r de0c2bbb27f9 -r 7c52e9cb2a72 flys-artifacts/src/main/java/de/intevation/flys/exports/XYChartGenerator.java --- a/flys-artifacts/src/main/java/de/intevation/flys/exports/XYChartGenerator.java Wed Nov 23 14:09:29 2011 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/XYChartGenerator.java Thu Nov 24 07:20:46 2011 +0000 @@ -10,8 +10,10 @@ import java.util.ArrayList; import java.util.HashMap; +import java.util.TreeMap; import java.util.List; import java.util.Map; +import java.util.SortedMap; import org.w3c.dom.Document; @@ -31,6 +33,7 @@ import org.jfree.data.Range; import org.jfree.data.xy.XYSeries; import org.jfree.data.xy.XYSeriesCollection; +import org.jfree.data.xy.XYDataset; import org.jfree.ui.RectangleInsets; @@ -52,11 +55,8 @@ /** The logger that is used in this generator. */ private static Logger logger = Logger.getLogger(XYChartGenerator.class); - /** SeriesCollection used for the first axis. */ - protected XYSeriesCollection first; - - /** SeriesCollection used for the second axis. */ - protected XYSeriesCollection second; + /** Map of datasets ("index"). */ + protected SortedMap> datasets; /** List of annotations to insert in plot. */ protected List annotations; @@ -71,6 +71,13 @@ public static final float DEFAULT_GRID_LINE_WIDTH = 0.3f; + public XYChartGenerator() { + xRanges = new HashMap(); + yRanges = new HashMap(); + datasets = new TreeMap>(); + } + + /** * Returns the title of a chart. * @@ -157,10 +164,9 @@ false, false); + XYPlot plot = (XYPlot) chart.getPlot(); chart.setBackgroundPaint(Color.WHITE); - chart.getPlot().setBackgroundPaint(Color.WHITE); - - XYPlot plot = (XYPlot) chart.getPlot(); + plot.setBackgroundPaint(Color.WHITE); addDatasets(plot); addAnnotations(plot); @@ -169,6 +175,7 @@ localizeAxes(plot); removeEmptyRangeAxes(plot); + createAxes(plot); adjustAxes(plot); preparePointRanges(plot); @@ -181,73 +188,67 @@ /** - * Add first and second dataset to plot. + * Add datasets to plot. * @param plot plot to add datasets to. */ protected void addDatasets(XYPlot plot) { - if (first != null) { - logger.debug("Set the first axis dataset."); - plot.setDataset(0, first); - } - if (second != null) { - logger.debug("Set the second axis dataset."); - plot.setDataset(1, second); - } - } - - - public void addFirstAxisSeries(XYSeries series, boolean visible) { - if (first == null) { - first = new XYSeriesCollection(); - } - - if (series != null) { - if (visible) { - first.addSeries(series); + int count = 0; + for (Map.Entry> entry: datasets.entrySet()) { + List axisList = new ArrayList(1); + axisList.add(entry.getKey()); + for (XYDataset dataset: entry.getValue()) { + int index = count++; + plot.setDataset(index, dataset); + plot.mapDatasetToRangeAxes(index, axisList); } - - combineYRanges(new Range(series.getMinY(), series.getMaxY()), 0); - combineXRanges(new Range(series.getMinX(), series.getMaxX()), 0); } } - public void addSecondAxisSeries(XYSeries series, boolean visible) { - if (second == null) { - second = new XYSeriesCollection(); - } - - if (series != null) { - if (visible) { - second.addSeries(series); - } - - combineYRanges(new Range(series.getMinY(), series.getMaxY()), 1); - combineXRanges(new Range(series.getMinX(), series.getMaxX()), 0); - } - } - - - private void combineXRanges(Range range, int index) { - Integer key = Integer.valueOf(index); - - if (xRanges == null) { - xRanges = new HashMap(); - xRanges.put(key, range); + /** + * Add given series. + * @param series the dataseries to include in plot. + * @param index index of the series and of its axis. + * @param visible whether or not the data should be plotted. + */ + public void addAxisSeries(XYSeries series, int index, boolean visible) { + if (series == null) { return; } - Range newX = null; - Range oldX = xRanges.get(key); + if (visible) { + XYSeriesCollection collection = new XYSeriesCollection(series); - if (oldX != null) { - newX = Range.combine(oldX, range); - } - else { - newX = range; + List dataset = datasets.get(index); + + if (dataset == null) { + dataset = new ArrayList(); + datasets.put(index, dataset); + } + + dataset.add(collection); } - xRanges.put(key, newX); + // Do this also when not visible to have axis scaled by default such + // that every data-point could be seen (except for annotations). + combineXRanges(new Range(series.getMinX(), series.getMaxX()), 0); + combineYRanges(new Range(series.getMinY(), series.getMaxY()), index); + } + + /** + * Effect: extend range of x axis to include given limits. + * @param range the given ("minimal") range. + * @param index index of axis to be merged. + */ + private void combineXRanges(Range range, int index) { + + Range old = xRanges.get(index); + + if (old != null) { + range = Range.combine(old, range); + } + + xRanges.put(index, range); } @@ -255,25 +256,14 @@ * @param range the new range. */ private void combineYRanges(Range range, int index) { - Integer key = Integer.valueOf(index); - if (yRanges == null) { - yRanges = new HashMap(); - yRanges.put(key, range); - return; + Range old = yRanges.get(index); + + if (old != null) { + range = Range.combine(old, range); } - Range newY = null; - Range oldY = yRanges.get(key); - - if (oldY != null) { - newY = Range.combine(oldY, range); - } - else { - newY = range; - } - - yRanges.put(key, newY); + yRanges.put(index, range); } @@ -293,17 +283,47 @@ } + /** + * Create y-axes. + */ + public void createAxes(XYPlot plot) { + logger.debug("XYChartGenerator.createAxes"); + Integer last = datasets.lastKey(); + + if (last != null) { + for (int i = last; i >= 0; --i) { + if (datasets.containsKey(i)) { + plot.setRangeAxis(i, createYAxis(i)); + } + } + } + } + + /** + * Create Y (range) axis for given index. + * Shall be overriden by subclasses. + */ + protected NumberAxis createYAxis(int index) { + NumberAxis axis = new NumberAxis("default axis"); + return axis; + } + private void removeEmptyRangeAxes(XYPlot plot) { - if (first == null) { - plot.setRangeAxis(0, null); - } + Integer last = datasets.lastKey(); - if (second == null) { - plot.setRangeAxis(1, null); + if (last != null) { + for (int i = last-1; i >= 0; --i) { + if (!datasets.containsKey(i)) { + plot.setRangeAxis(i, null); + } + } } } + /** + * Expands X and Y axes if only a point is shown. + */ private void preparePointRanges(XYPlot plot) { for (int i = 0, num = plot.getDomainAxisCount(); i < num; i++) { Integer key = Integer.valueOf(i); @@ -325,6 +345,9 @@ } + /** + * Expand range by percent. + */ public static Range expandRange(Range range, double percent) { if (range == null) { return null; @@ -479,14 +502,18 @@ /** - * Adjusts the axes of a plot. + * Adjusts the axes of a plot (the first axis does not include zero). * * @param plot The XYPlot of the chart. */ protected void adjustAxes(XYPlot plot) { NumberAxis yAxis = (NumberAxis) plot.getRangeAxis(); - - yAxis.setAutoRangeIncludesZero(false); + if (yAxis == null) { + logger.warn("No Axis to setAutoRangeIncludeZero."); + } + else { + yAxis.setAutoRangeIncludesZero(false); + } } @@ -508,14 +535,6 @@ plot.setRangeGridlinesVisible(true); plot.setAxisOffset(new RectangleInsets(0d, 0d, 0d, 0d)); - - if (plot.getDataset(0) != null) { - plot.mapDatasetToRangeAxis(0, 0); - } - - if (plot.getDataset(1) != null) { - plot.mapDatasetToRangeAxis(1, 1); - } } @@ -581,12 +600,14 @@ protected void applyThemes(XYPlot plot) { - if (first != null) { - applyThemes(plot, first, 0); - } - if (second != null) { - applyThemes(plot, second, 1); + for (Map.Entry> entry: datasets.entrySet()) { + int axis = entry.getKey(); + for (XYDataset dataset: entry.getValue()) { + if (dataset instanceof XYSeriesCollection) { + applyThemes(plot, (XYSeriesCollection)dataset, axis); + } + } } }