changeset 2633:894186b4c1d0

Issue 494. Add manual points with text annotations to time charts. flys-artifacts/trunk@4255 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Raimund Renkert <raimund.renkert@intevation.de>
date Wed, 18 Apr 2012 07:14:48 +0000
parents 7d163c2c6e6d
children fa015cf5c0af
files flys-artifacts/ChangeLog flys-artifacts/doc/conf/artifacts/manualpoints.xml flys-artifacts/doc/conf/artifacts/winfo.xml flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java flys-artifacts/src/main/java/de/intevation/flys/exports/HistoricalDischargeCurveGenerator.java flys-artifacts/src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java
diffstat 6 files changed, 278 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/flys-artifacts/ChangeLog	Tue Apr 17 13:55:50 2012 +0000
+++ b/flys-artifacts/ChangeLog	Wed Apr 18 07:14:48 2012 +0000
@@ -1,3 +1,20 @@
+2012-04-18  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Issue 494.
+
+	* src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java:
+	  Create manual points with text annotations in time charts.
+
+	* src/main/java/de/intevation/flys/exports/HistoricalDischargeCurveGenerator.java:
+	  Add manual points to the chart.
+
+	* src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java:
+	  Added historical discharge to chart types.
+
+	* doc/conf/artifacts/winfo.xml,
+	  doc/conf/artifacts/manualpoints.xml:
+	  Added manual points facet to output modes.
+
 2012-04-17	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
 
 	* contrib/fixoverview2html.xsl: Render optional check boxes.
--- a/flys-artifacts/doc/conf/artifacts/manualpoints.xml	Tue Apr 17 13:55:50 2012 +0000
+++ b/flys-artifacts/doc/conf/artifacts/manualpoints.xml	Wed Apr 18 07:14:48 2012 +0000
@@ -16,6 +16,7 @@
             <facet name="cross_section.manualpoints" description="Points provided by user." />
             <facet name="reference_curve.manualpoints" description="User-provided points *yawn*"/>
             <facet name="reference_curve_normalized.manualpoints" description="points"/>
+            <facet name="historical_discharge.manualpoints" description="Points provided by user." />
           </facets>
         </outputmode>
       </outputmodes>
--- a/flys-artifacts/doc/conf/artifacts/winfo.xml	Tue Apr 17 13:55:50 2012 +0000
+++ b/flys-artifacts/doc/conf/artifacts/winfo.xml	Wed Apr 18 07:14:48 2012 +0000
@@ -516,6 +516,7 @@
                     <facets>
                         <facet name="historical_discharge.historicalq"/>
                         <facet name="historical_discharge.historicalq.diff"/>
+                        <facet name="historical_discharge.manualpoints"/>
                     </facets>
                 </outputmode>
                 <outputmode name="historical_discharge_export" description="output.historical_discharge.export" mime-type="text/plain" type="export">
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java	Tue Apr 17 13:55:50 2012 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java	Wed Apr 18 07:14:48 2012 +0000
@@ -45,7 +45,8 @@
         DIC("discharge_curve"),
         RC("reference_curve"),
         RCN("reference_curve_normalized"),
-        WD("wdifferences");
+        WD("wdifferences"),
+        HD("historical_discharge");
 
         private String chartTypeString;
 
--- a/flys-artifacts/src/main/java/de/intevation/flys/exports/HistoricalDischargeCurveGenerator.java	Tue Apr 17 13:55:50 2012 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/HistoricalDischargeCurveGenerator.java	Wed Apr 18 07:14:48 2012 +0000
@@ -153,6 +153,11 @@
                 theme,
                 visible);
         }
+        else if (FacetTypes.IS.MANUALPOINTS(name)) {
+            doPoints (artifactFacet.getData(context),
+                      artifactFacet,
+                      theme, visible, YAXIS.Q.idx);
+        }
         // TODO ADD THE CASE FOR DISPLAYING W VALUES
         else {
            logger.warn("doOut(): unknown facet name: " + name);
--- a/flys-artifacts/src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java	Tue Apr 17 13:55:50 2012 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java	Wed Apr 18 07:14:48 2012 +0000
@@ -2,28 +2,50 @@
 
 import java.awt.Color;
 import java.awt.Font;
+import java.awt.Paint;
+import java.awt.BasicStroke;
+import java.awt.Stroke;
 
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Date;
+
+import org.json.JSONArray;
+import org.json.JSONException;
 
 import org.apache.log4j.Logger;
 
+import org.w3c.dom.Document;
+
 import org.jfree.chart.ChartFactory;
 import org.jfree.chart.JFreeChart;
 import org.jfree.chart.axis.ValueAxis;
 import org.jfree.chart.plot.XYPlot;
+import org.jfree.chart.annotations.XYTextAnnotation;
+import org.jfree.chart.LegendItemCollection;
 
 import org.jfree.data.Range;
 import org.jfree.data.time.TimeSeriesCollection;
 import org.jfree.data.general.Series;
 import org.jfree.data.xy.XYDataset;
+import org.jfree.data.general.SeriesException;
+import org.jfree.data.time.Day;
+import org.jfree.data.time.RegularTimePeriod;
+import org.jfree.data.time.TimeSeries;
+
+import de.intevation.artifactdatabase.state.ArtifactAndFacet;
+import de.intevation.artifactdatabase.state.Facet;
 
 import de.intevation.flys.jfree.Bounds;
 import de.intevation.flys.jfree.DoubleBounds;
 import de.intevation.flys.jfree.TimeBounds;
+import de.intevation.flys.jfree.StyledTimeSeries;
+import de.intevation.flys.jfree.FLYSAnnotation;
+import de.intevation.flys.jfree.CollisionFreeXYTextAnnotation;
 
+import de.intevation.flys.utils.ThemeAccess;
 
 /**
  * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
@@ -122,6 +144,9 @@
     } // end of TimeseriesAxisDataset class
 
 
+    /** List of annotations to insert in plot. */
+    protected List<FLYSAnnotation> annotations;
+
 
     private static final Logger logger =
         Logger.getLogger(TimeseriesChartGenerator.class);
@@ -173,6 +198,8 @@
 
         adaptZoom(plot);
 
+        addAnnotationsToRenderer(plot);
+
         return chart;
     }
 
@@ -450,5 +477,230 @@
         xaxis.setLabelFont(labelFont);
         xaxis.setTickLabelFont(labelFont);
     }
+
+
+    /**
+     * Do Points out.
+     */
+    protected void doPoints(
+        Object     o,
+        ArtifactAndFacet aandf,
+        Document   theme,
+        boolean    visible,
+        int        axisIndex
+    ) {
+        String seriesName = aandf.getFacetDescription();
+        TimeSeries series = new StyledTimeSeries(seriesName, theme);
+
+        // Add text annotations for single points.
+        List<XYTextAnnotation> xy = new ArrayList<XYTextAnnotation>();
+        HashMap<Day, String> names = new HashMap<Day, String>();
+
+        try {
+            JSONArray points = new JSONArray((String) o);
+            for (int i = 0; i < points.length(); i++) {
+                JSONArray array = points.getJSONArray(i);
+                double x    = array.getDouble(0);
+                double y    = array.getDouble(1);
+                String name = array.getString(2);
+                boolean act = array.getBoolean(3);
+                if (!act) {
+                    continue;
+                }
+                long l = (new Double(x)).longValue();
+                Date date = new Date(l);
+                Day day = new Day(date);
+                series.add(day, y, false);
+                names.put(day, name);
+            }
+        }
+        catch(JSONException e){
+            logger.error("Could not decode json.");
+        }
+
+        TimeSeriesCollection tsc = new TimeSeriesCollection();
+        tsc.addSeries(series);
+        // Add Annotations.
+        for (int i = 0; i < series.getItemCount(); i++) {
+            double x = tsc.getXValue(0, i);
+            double y = tsc.getYValue(0, i);
+            xy.add(new CollisionFreeXYTextAnnotation(
+                       names.get(series.getTimePeriod(i)), x, y));
+        }
+        FLYSAnnotation annotations =
+            new FLYSAnnotation(null, null, null, theme);
+        annotations.setTextAnnotations(xy);
+
+        // Do not generate second legend entry. (null was passed for the aand before).
+        doAnnotations(annotations, aandf, theme, visible);
+
+        addAxisDataset(tsc, axisIndex, visible);
+    }
+
+    /**
+     * Register annotations like MainValues for later plotting
+     *
+     * @param o     list of annotations (data of facet).
+     * @param facet The facet. This facet does NOT support any data objects. Use
+     * FLYSArtifact.getNativeFacet() instead to retrieve a Facet which supports
+     * data.
+     * @param theme   Theme document for given annotations.
+     * @param visible The visibility of the annotations.
+     */
+    protected void doAnnotations(
+        FLYSAnnotation annotations,
+        ArtifactAndFacet aandf,
+        Document theme,
+        boolean visible
+    ){
+        // Running into trouble here.
+        logger.debug("doAnnotations");
+
+        // Add all annotations to our annotation pool.
+        annotations.setTheme(theme);
+        if (aandf != null) {
+            Facet facet = aandf.getFacet();
+            annotations.setLabel(aandf.getFacetDescription());
+        }
+        else {
+            logger.debug(
+                "Art/Facet for Annotations is null. " +
+                "This should never happen!");
+        }
+
+        addAnnotations(annotations, visible);
+    }
+
+
+
+    /**
+     * Adds annotations to list (if visible is true).
+     */
+    public void addAnnotations(FLYSAnnotation annotation, boolean visible) {
+        if (!visible) {
+            return;
+        }
+
+        if (annotations == null) {
+            annotations = new ArrayList<FLYSAnnotation>();
+        }
+
+        annotations.add(annotation);
+    }
+
+
+    /** Add annotations (Sticky, Text and hyk zones). */
+    public void addAnnotationsToRenderer(XYPlot plot) {
+        logger.debug("XYChartGenerator.addAnnotationsToRenderer");
+
+        if (annotations == null) {
+            logger.debug("XYChartGenerator.addBoxAnnotations: no annotations.");
+            return;
+        }
+
+        // Paints for the boxes/lines.
+        Stroke basicStroke = new BasicStroke(1.0f);
+
+        Paint linePaint = new Color(255,  0,0,60);
+        Paint fillPaint = new Color(0,  255,0,60);
+        Paint tranPaint = new Color(0,    0,0, 0);
+
+        // OPTMIMIZE: Pre-calculate positions
+        Area area = new Area(
+            plot.getDomainAxis(0).getRange(),
+            plot.getRangeAxis().getRange());
+
+        // Walk over all Annotation sets.
+        for (FLYSAnnotation fa: annotations) {
+
+            // Access text styling, if any.
+            Document theme = fa.getTheme();
+            ThemeAccess.TextStyle textStyle = null;
+            ThemeAccess.LineStyle lineStyle = null;
+
+            // Get Themeing information and add legend item.
+            if (theme != null) {
+                ThemeAccess themeAccess = new ThemeAccess(theme);
+                textStyle = themeAccess.parseTextStyle();
+                lineStyle = themeAccess.parseLineStyle();
+                if (fa.getLabel() != null) {
+                    LegendItemCollection lic = new LegendItemCollection();
+                    LegendItemCollection old = plot.getFixedLegendItems();
+                    lic.add(createLegendItem(theme, fa.getLabel()));
+                    // (Re-)Add prior legend entries.
+                    if (old != null) {
+                        old.addAll(lic);
+                    }
+                    else {
+                        old = lic;
+                    }
+                    plot.setFixedLegendItems(old);
+                }
+            }
+
+            // Other Text Annotations (e.g. labels of manual points).
+            for (XYTextAnnotation ta: fa.getTextAnnotations()) {
+                // Style the text.
+                if (textStyle != null) {
+                    textStyle.apply(ta);
+                }
+                ta.setY(area.above(0.05d, ta.getY()));
+                plot.getRenderer().addAnnotation(ta, org.jfree.ui.Layer.FOREGROUND);
+            }
+        }
+    }
+
+
+    /** Two Ranges that span a rectangular area. */
+    public static class Area {
+        protected Range xRange;
+        protected Range yRange;
+
+        public Area(Range rangeX, Range rangeY) {
+            this.xRange = rangeX;
+            this.yRange = rangeY;
+        }
+
+        public Area(ValueAxis axisX, ValueAxis axisY) {
+            this.xRange = axisX.getRange();
+            this.yRange = axisY.getRange();
+        }
+
+        public double ofLeft(double percent) {
+            return xRange.getLowerBound()
+                + xRange.getLength() * percent;
+        }
+
+        public double ofRight(double percent) {
+            return xRange.getUpperBound()
+                - xRange.getLength() * percent;
+        }
+
+        public double ofGround(double percent) {
+            return yRange.getLowerBound()
+                + yRange.getLength() * percent;
+        }
+
+        public double atTop() {
+            return yRange.getUpperBound();
+        }
+
+        public double atGround() {
+            return yRange.getLowerBound();
+        }
+
+        public double atRight() {
+            return xRange.getUpperBound();
+        }
+
+        public double atLeft() {
+            return xRange.getLowerBound();
+        }
+
+        public double above(double percent, double base) {
+            return base + yRange.getLength() * percent;
+        }
+    }
+
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :

http://dive4elements.wald.intevation.org