changeset 9496:d8e753d0fdb9

stripedArea introduced for Assessment Scheme/Bewertungsschema
author gernotbelger
date Wed, 26 Sep 2018 15:48:05 +0200
parents bb278c927b66
children 7b4b66c7b303 853f2dafc16e
files artifacts/doc/conf/themes/default.xml artifacts/doc/conf/themes/second.xml artifacts/src/main/java/org/dive4elements/river/artifacts/common/AbstractProcessor.java artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/SalixLineProcessor.java artifacts/src/main/java/org/dive4elements/river/exports/AbstractChartGenerator.java artifacts/src/main/java/org/dive4elements/river/exports/DiagramGenerator.java artifacts/src/main/java/org/dive4elements/river/exports/LegendProcessor.java artifacts/src/main/java/org/dive4elements/river/exports/XYChartGenerator.java artifacts/src/main/java/org/dive4elements/river/exports/process/AreaProcessor.java artifacts/src/main/java/org/dive4elements/river/exports/process/DeltaWProcessor.java artifacts/src/main/java/org/dive4elements/river/exports/process/FixDeltaWAProcessor.java artifacts/src/main/java/org/dive4elements/river/exports/process/FixDeltaWProcessor.java artifacts/src/main/java/org/dive4elements/river/exports/process/WOutProcessor.java artifacts/src/main/java/org/dive4elements/river/java2d/ShapeUtils.java artifacts/src/main/java/org/dive4elements/river/jfree/AxisDataset.java artifacts/src/main/java/org/dive4elements/river/jfree/StripedAreaDataset.java artifacts/src/main/java/org/dive4elements/river/jfree/StripedAreaDatasetRenderer.java artifacts/src/main/java/org/dive4elements/river/jfree/StyledAreaSeriesCollection.java artifacts/src/main/java/org/dive4elements/river/jfree/StyledXYDataset.java artifacts/src/main/resources/messages.properties artifacts/src/main/resources/messages_de.properties
diffstat 21 files changed, 484 insertions(+), 359 deletions(-) [+]
line wrap: on
line diff
--- a/artifacts/doc/conf/themes/default.xml	Tue Sep 25 16:43:51 2018 +0200
+++ b/artifacts/doc/conf/themes/default.xml	Wed Sep 26 15:48:05 2018 +0200
@@ -2971,16 +2971,9 @@
     </fields>
   </theme>
   <theme name="UInfoSalixRank">
-    <inherits>
-      <inherit from="Areas"/>
-    </inherits>
-    <fields>
-      <field name="areashowbg" type="boolean" display="Hintergrund anzeigen" default="true" hints="hidden"/>
-      <field name="areashowborder" type="boolean" display="Begrenzung" default="false" hints="hidden"/>
-      <field name="areabordercolor" type="Color" default="0, 0, 0" display="Begrenzungslinienfarbe" hints="hidden"/>
-      <field name="showarea" type="boolean" display="Flaeche anzeigen" default="true" hints="hidden"/>
-      <field name="showarealabel" type="boolean" display="Flächenbeschriftung anzeigen" default="false"/>
-    </fields>
+   <fields> 
+      <field name="areatransparency" type="int" default="50" display="Transparenz" /> 
+  </fields>
   </theme>
   <theme name="UInfoSalixCrossSectionWaterLine">
     <inherits>
--- a/artifacts/doc/conf/themes/second.xml	Tue Sep 25 16:43:51 2018 +0200
+++ b/artifacts/doc/conf/themes/second.xml	Wed Sep 26 15:48:05 2018 +0200
@@ -2959,16 +2959,9 @@
     </fields>
   </theme>
   <theme name="UInfoSalixRank">
-    <inherits>
-      <inherit from="Areas"/>
-    </inherits>
-    <fields>
-      <field name="areashowbg" type="boolean" display="Hintergrund anzeigen" default="true" hints="hidden"/>
-      <field name="areashowborder" type="boolean" display="Begrenzung" default="false" hints="hidden"/>
-      <field name="areabordercolor" type="Color" default="0, 0, 0" display="Begrenzungslinienfarbe" hints="hidden"/>
-      <field name="showarea" type="boolean" display="Flaeche anzeigen" default="true" hints="hidden"/>
-      <field name="showarealabel" type="boolean" display="Flächenbeschriftung anzeigen" default="false"/>
-    </fields>
+   <fields> 
+      <field name="areatransparency" type="int" default="50" display="Transparenz" /> 
+  </fields>
   </theme>
   <theme name="UInfoSalixCrossSectionWaterLine">
     <inherits>
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/common/AbstractProcessor.java	Tue Sep 25 16:43:51 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/common/AbstractProcessor.java	Wed Sep 26 15:48:05 2018 +0200
@@ -30,6 +30,8 @@
 import org.dive4elements.river.exports.DiagramGenerator;
 import org.dive4elements.river.exports.StyledSeriesBuilder;
 import org.dive4elements.river.exports.process.DefaultProcessor;
+import org.dive4elements.river.jfree.StripedAreaDataset;
+import org.dive4elements.river.jfree.StripedAreaDataset.Stripe;
 import org.dive4elements.river.jfree.StyledAreaSeriesCollection;
 import org.dive4elements.river.jfree.StyledXYSeries;
 import org.dive4elements.river.themes.ThemeDocument;
@@ -164,7 +166,20 @@
         area.addSeries(seriesUp);
         area.addSeries(seriesDown);
 
-        generator.addAreaSeries(area, getAxisName(), visible);
+        generator.addAxisDataset(area, getAxisName(), visible);
+
+        return null;
+    }
+
+    protected final String buildStripedAreaSeries(final Stripe[] stripes, final DiagramGenerator generator, final ArtifactAndFacet bundle,
+            final ThemeDocument theme, final boolean visible) {
+
+        final StripedAreaDataset dataset = new StripedAreaDataset(theme);
+
+        for (final Stripe stripe : stripes)
+            dataset.addStripe(stripe);
+
+        generator.addAxisDataset(dataset, getAxisName(), visible);
 
         return null;
     }
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/SalixLineProcessor.java	Tue Sep 25 16:43:51 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/SalixLineProcessor.java	Wed Sep 26 15:48:05 2018 +0200
@@ -10,14 +10,14 @@
 
 package org.dive4elements.river.artifacts.uinfo.salix;
 
+import java.awt.Color;
 import java.util.HashSet;
 import java.util.Set;
 
 import org.dive4elements.artifactdatabase.state.ArtifactAndFacet;
 import org.dive4elements.artifactdatabase.state.Facet;
 import org.dive4elements.artifacts.CallContext;
-import org.dive4elements.river.artifacts.D4EArtifact;
-import org.dive4elements.river.artifacts.access.RangeAccess;
+import org.dive4elements.artifacts.CallMeta;
 import org.dive4elements.river.artifacts.common.AbstractProcessor;
 import org.dive4elements.river.artifacts.model.CrossSectionWaterLineFacet;
 import org.dive4elements.river.artifacts.model.FacetTypes;
@@ -26,6 +26,7 @@
 import org.dive4elements.river.artifacts.uinfo.common.UInfoResultType;
 import org.dive4elements.river.artifacts.uinfo.salix.SalixLineCrossSectionIndexData.SalixWaterlevel;
 import org.dive4elements.river.exports.DiagramGenerator;
+import org.dive4elements.river.jfree.StripedAreaDataset.Stripe;
 import org.dive4elements.river.themes.ThemeDocument;
 
 /**
@@ -167,9 +168,6 @@
 
     @Override
     protected String generateSeries(final DiagramGenerator generator, final ArtifactAndFacet bundle, final ThemeDocument theme, final boolean visible) {
-
-        // log.debug("Processing facet: " + bundle.getFacetName());
-
         if (bundle.getFacetName().equals(FACET_SALIX_SCENARIO_FILTERED) || bundle.getFacetName().equals(FACET_SALIX_SCENARIO_RAW)) {
             final CallContext context = generator.getContext();
             final SalixLineCalculationResult data = (SalixLineCalculationResult) bundle.getData(context);
@@ -179,19 +177,24 @@
         }
 
         if (bundle.getFacetName().equals(FACET_SALIX_RANK)) {
-            final RangeAccess kmRange = new RangeAccess((D4EArtifact) bundle.getArtifact());
-            // TODO get all rank data (5 ranks) from database
-            final double[][] points = new double[2][2];
-            points[0][0] = kmRange.getLowerKm();
-            points[0][1] = kmRange.getUpperKm();
-            points[1][0] = 1.5;
-            points[1][1] = 1.5;
-            return buildSeriesForPoints(points, generator, bundle, theme, visible, null);
+            final CallMeta meta = generator.getContext().getMeta();
+            final Stripe[] stripes = new Stripe[] { //
+                    new Stripe(getSimpleMsg("uinfo_salix_rank.excellent", meta), Color.decode("#00B0F0"), -0.3, 0.3), //
+                    new Stripe(getSimpleMsg("uinfo_salix_rank.good", meta), Color.decode("#00B050"), 0.3, 0.5), //
+                    new Stripe(getSimpleMsg("uinfo_salix_rank.moderate", meta), Color.decode("#FFFF00"), 0.5, 1.0), //
+                    new Stripe(getSimpleMsg("uinfo_salix_rank.bad", meta), Color.decode("#FFC000"), 1.0, 1.5), //
+                    new Stripe(getSimpleMsg("uinfo_salix_rank.very_bad", meta), Color.decode("#FF0000"), 1.5, Double.NaN) };
+
+            return buildStripedAreaSeries(stripes, generator, bundle, theme, visible);
         }
 
         return buildSeriesForType(generator, bundle, theme, visible, doGetType(bundle.getFacetName()), GAP_DISTANCE);
     }
 
+    private String getSimpleMsg(final String code, final CallMeta meta) {
+        return Resources.getMsg(meta, code);
+    }
+
     protected UInfoResultType doGetType(final String facetName) {
 
         if (FACET_SALIX_LINE_FILTERED.contentEquals(facetName))
--- a/artifacts/src/main/java/org/dive4elements/river/exports/AbstractChartGenerator.java	Tue Sep 25 16:43:51 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/exports/AbstractChartGenerator.java	Wed Sep 26 15:48:05 2018 +0200
@@ -12,11 +12,7 @@
 import java.awt.BasicStroke;
 import java.awt.Color;
 import java.awt.Font;
-import java.awt.Paint;
 import java.awt.Stroke;
-import java.awt.TexturePaint;
-import java.awt.geom.Rectangle2D;
-import java.awt.image.BufferedImage;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.text.DateFormat;
@@ -38,7 +34,6 @@
 import org.dive4elements.artifactdatabase.state.ArtifactAndFacet;
 import org.dive4elements.artifactdatabase.state.Settings;
 import org.dive4elements.artifacts.Artifact;
-import org.dive4elements.artifacts.ArtifactCollection;
 import org.dive4elements.artifacts.ArtifactNamespaceContext;
 import org.dive4elements.artifacts.CallContext;
 import org.dive4elements.artifacts.CallMeta;
@@ -56,12 +51,10 @@
 import org.dive4elements.river.jfree.DoubleBounds;
 import org.dive4elements.river.jfree.EnhancedLineAndShapeRenderer;
 import org.dive4elements.river.jfree.RiverAnnotation;
-import org.dive4elements.river.jfree.StableXYDifferenceRenderer;
 import org.dive4elements.river.jfree.Style;
-import org.dive4elements.river.jfree.StyledAreaSeriesCollection;
 import org.dive4elements.river.jfree.StyledSeries;
+import org.dive4elements.river.jfree.StyledXYDataset;
 import org.dive4elements.river.themes.ThemeDocument;
-import org.dive4elements.river.utils.Formatter;
 import org.jfree.chart.JFreeChart;
 import org.jfree.chart.LegendItem;
 import org.jfree.chart.LegendItemCollection;
@@ -478,7 +471,7 @@
         addMetadataSubtitle(chart);
 
         /* add the real chart title, but as subtitle after the metadata */
-        final String chartTitle =  getChartTitle(this.context);
+        final String chartTitle = getChartTitle(this.context);
         if (chartTitle != null) {
             final TextTitle title = new TextTitle(chartTitle, JFreeChart.DEFAULT_TITLE_FONT);
             chart.addSubtitle(title);
@@ -487,7 +480,6 @@
         addSubtitles(this.context, chart);
     }
 
-
     /**
      * Adds a metadata sub-title to the chart if it gets exported
      */
@@ -503,7 +495,7 @@
 
         final TextTitle subtitle = new TextTitle(text, titleFont);
         subtitle.setHorizontalAlignment(HorizontalAlignment.LEFT);
-        subtitle.setMargin(new RectangleInsets(10,10,10,10));
+        subtitle.setMargin(new RectangleInsets(10, 10, 10, 10));
 
         chart.addSubtitle(subtitle);
     }
@@ -517,9 +509,6 @@
             return Collections.emptyList();
         }
 
-        final CollectionCallContext ccc = (CollectionCallContext) this.context;
-        final ArtifactCollection collection = ccc.getCollection();
-
         final List<String> subtitles = new ArrayList<>();
 
         /* version */
@@ -817,7 +806,7 @@
                         plot.setDataset(datasetIndex, dataset);
                         plot.mapDatasetToRangeAxis(datasetIndex, axisIndex);
 
-                        applyThemes(plot, dataset, datasetIndex, axisDataset.isArea(dataset));
+                        applyThemes(plot, dataset, datasetIndex);
 
                         datasetIndex++;
                     }
@@ -839,18 +828,21 @@
     protected abstract NumberAxis createYAxis(final int index);
 
     /**
-     * @param idx
+     * @param datasetIndex
      *            "index" of dataset/series (first dataset to be drawn has
      *            index 0), correlates with renderer index.
      * @param isArea
      *            true if the series describes an area and shall be rendered
      *            as such.
      */
-    private void applyThemes(final XYPlot plot, final XYDataset series, final int idx, final boolean isArea) {
-        if (isArea)
-            applyAreaTheme(plot, (StyledAreaSeriesCollection) series, idx);
+    private void applyThemes(final XYPlot plot, final XYDataset dataset, final int datasetIndex) {
+
+        final Font legendFont = createLegendLabelFont();
+
+        if (dataset instanceof StyledXYDataset)
+            ((StyledXYDataset) dataset).applyTheme(this.context.getMeta(), plot, datasetIndex, legendFont);
         else
-            applyLineTheme(plot, series, idx);
+            applyLineTheme(plot, dataset, datasetIndex, legendFont);
     }
 
     /**
@@ -883,12 +875,8 @@
      * @return a new instance of EnhancedLineAndShapeRenderer.
      */
     private XYLineAndShapeRenderer createRenderer(final XYPlot plot, final int idx) {
-        log.debug("Create EnhancedLineAndShapeRenderer for idx: " + idx);
-
         final EnhancedLineAndShapeRenderer r = new EnhancedLineAndShapeRenderer(true, false);
-
         r.setPlot(plot);
-
         return r;
     }
 
@@ -903,15 +891,14 @@
      *            The XYDataset which needs to support Series objects.
      * @param idx
      *            The index of the renderer / dataset.
+     * @param legendFont2
      */
-    private void applyLineTheme(final XYPlot plot, final XYDataset dataset, final int idx) {
+    private void applyLineTheme(final XYPlot plot, final XYDataset dataset, final int idx, final Font legendFont) {
         log.debug("Apply LineTheme for dataset at index: " + idx);
 
         final LegendItemCollection lic = new LegendItemCollection();
         final LegendItemCollection anno = plot.getFixedLegendItems();
 
-        final Font legendFont = createLegendLabelFont();
-
         final XYLineAndShapeRenderer renderer = createRenderer(plot, idx);
 
         for (int s = 0, num = dataset.getSeriesCount(); s < num; s++) {
@@ -951,64 +938,6 @@
         plot.setRenderer(idx, renderer);
     }
 
-    /**
-     * @param plot
-     *            The plot.
-     * @param area
-     *            A StyledAreaSeriesCollection object.
-     * @param idx
-     *            The index of the dataset.
-     */
-    private final void applyAreaTheme(final XYPlot plot, final StyledAreaSeriesCollection area, final int idx) {
-        final LegendItemCollection lic = new LegendItemCollection();
-        final LegendItemCollection anno = plot.getFixedLegendItems();
-
-        final Font legendFont = createLegendLabelFont();
-
-        log.debug("Registering an 'area'renderer at idx: " + idx);
-
-        final StableXYDifferenceRenderer dRenderer = new StableXYDifferenceRenderer();
-
-        if (area.getMode() == StyledAreaSeriesCollection.FILL_MODE.UNDER) {
-            dRenderer.setPositivePaint(createTransparentPaint());
-        }
-
-        plot.setRenderer(idx, dRenderer);
-
-        area.applyTheme(dRenderer);
-
-        // i18n
-        dRenderer.setAreaLabelNumberFormat(Formatter.getFormatter(this.context.getMeta(), 2, 4));
-
-        dRenderer.setAreaLabelTemplate(Resources.getMsg(this.context.getMeta(), "area.label.template", "Area=%sm2"));
-
-        final LegendItem legendItem = dRenderer.getLegendItem(idx, 0);
-        if (legendItem != null) {
-            legendItem.setLabelFont(legendFont);
-            lic.add(legendItem);
-        } else {
-            log.warn("Could not get LegentItem for renderer: " + idx + ", series-idx " + 0);
-        }
-
-        if (anno != null) {
-            lic.addAll(anno);
-        }
-
-        plot.setFixedLegendItems(lic);
-    }
-
-    /**
-     * Returns a transparently textured paint.
-     *
-     * @return a transparently textured paint.
-     */
-    private static Paint createTransparentPaint() {
-        // TODO why not use a transparent color?
-        final BufferedImage texture = new BufferedImage(1, 1, BufferedImage.TYPE_4BYTE_ABGR);
-
-        return new TexturePaint(texture, new Rectangle2D.Double(0d, 0d, 0d, 0d));
-    }
-
     private void preparePDFContext(final CallContext context) {
         final int[] dimension = getExportDimension();
 
@@ -1069,21 +998,27 @@
 
         final Bounds[] xyBounds = ChartHelper.getBounds(dataset);
 
-        if (xyBounds == null) {
-            log.warn("Skip XYDataset for Axis (invalid ranges): " + idx);
-            return;
-        }
+        // if (xyBounds == null) {
+        // log.warn("Skip XYDataset for Axis (invalid ranges): " + idx);
+        // return;
+        // }
 
         if (visible) {
             if (log.isDebugEnabled()) {
                 log.debug("Add new AxisDataset at index: " + idx);
-                log.debug("X extent: " + xyBounds[0]);
-                log.debug("Y extent: " + xyBounds[1]);
+                if (xyBounds != null) {
+                    log.debug("X extent: " + xyBounds[0]);
+                    log.debug("Y extent: " + xyBounds[1]);
+                }
             }
 
             axisDataset.addDataset(dataset);
         }
 
+        /* No range merging, for areas extending to infinity this causes problems. */
+        if (xyBounds == null || StyledSeriesBuilder.isBigDoubleValue(xyBounds[1].getLower()) || StyledSeriesBuilder.isBigDoubleValue(xyBounds[1].getLower()))
+            return;
+
         combineXBounds(xyBounds[0], 0);
         combineYBounds(xyBounds[1], idx);
     }
--- a/artifacts/src/main/java/org/dive4elements/river/exports/DiagramGenerator.java	Tue Sep 25 16:43:51 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/exports/DiagramGenerator.java	Wed Sep 26 15:48:05 2018 +0200
@@ -37,7 +37,6 @@
 import org.dive4elements.river.jfree.Bounds;
 import org.dive4elements.river.jfree.DoubleBounds;
 import org.dive4elements.river.jfree.RiverAnnotation;
-import org.dive4elements.river.jfree.StyledAreaSeriesCollection;
 import org.dive4elements.river.jfree.XYMetaSeriesCollection;
 import org.dive4elements.river.themes.ThemeDocument;
 import org.jfree.chart.ChartFactory;
@@ -51,7 +50,6 @@
 import org.jfree.chart.plot.Marker;
 import org.jfree.chart.plot.PlotOrientation;
 import org.jfree.chart.plot.XYPlot;
-import org.jfree.chart.title.TextTitle;
 import org.jfree.data.Range;
 import org.jfree.data.general.Series;
 import org.jfree.data.xy.XYDataset;
@@ -442,67 +440,6 @@
     }
 
     /**
-     * Registers an area to be drawn.
-     * @param area Area to be drawn.
-     * @param axisName Name of the axis.
-     * @param visible Whether or not to be visible
-     *                (important for range calculations).
-     */
-    public void addAreaSeries(
-        StyledAreaSeriesCollection area,
-        String axisName,
-        boolean visible
-    ) {
-        addAreaSeries(area, diagramAttributes.getAxisIndex(axisName), visible);
-    }
-
-    /**
-     * Registers an area to be drawn.
-     * @param area Area to be drawn.
-     * @param index 'axis index'
-     * @param visible Whether or not to be visible
-     *                (important for range calculations).
-     */
-    public void addAreaSeries(
-        StyledAreaSeriesCollection area,
-        int index,
-        boolean visible
-    ) {
-        if (area == null) {
-            log.warn("Cannot yet render above/under curve.");
-            return;
-        }
-
-        AxisDataset axisDataset = (AxisDataset) getAxisDataset(index);
-
-        Bounds[] xyBounds = ChartHelper.getBounds(area);
-
-        if (xyBounds == null) {
-            log.warn("Skip XYDataset for Axis (invalid ranges): " + index);
-            return;
-        }
-        
-
-        if (visible) {
-            if (log.isDebugEnabled()) {
-                log.debug("Add new AxisDataset at index: " + index);
-                log.debug("X extent: " + xyBounds[0]);
-                log.debug("Y extent: " + xyBounds[1]);
-            }
-
-            axisDataset.addArea(area);
-        }
-
-        /* No range merging, for areas extending to infinity this causes problems. */
-        /* No range merging, for areas extending to infinity this causes problems. */
-        if( StyledSeriesBuilder.isBigDoubleValue( xyBounds[1].getLower() ) || StyledSeriesBuilder.isBigDoubleValue( xyBounds[1].getLower() ) )
-            return;
-        
-        combineXBounds(xyBounds[0], 0);
-        combineYBounds(xyBounds[1], index);
-    }
-
-    /**
      * Add given series if visible, if not visible adjust ranges (such that
      * all points in data would be plotted once visible).
      * @param series   the data series to include in plot.
@@ -1134,7 +1071,7 @@
     }
 
     protected final String getDefaultYAxisLabel(String axisName) {
-        Set labelSet = axesLabels.get(diagramAttributes.getAxisIndex(axisName));
+        Set<String> labelSet = axesLabels.get(diagramAttributes.getAxisIndex(axisName));
         log.debug("Labels for axis: " + labelSet);
         if (labelSet != null && !labelSet.isEmpty()) {
             String label = StringUtils.join(labelSet, ", ");
--- a/artifacts/src/main/java/org/dive4elements/river/exports/LegendProcessor.java	Tue Sep 25 16:43:51 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/exports/LegendProcessor.java	Wed Sep 26 15:48:05 2018 +0200
@@ -19,25 +19,23 @@
 import org.jfree.chart.LegendItemCollection;
 import org.jfree.chart.plot.XYPlot;
 
-
 /** Class to process Plots legends. */
 public abstract class LegendProcessor {
 
     /** (Empty) shape for aggregated Legend Items. */
-    private static final Line2D.Double SPACE = new Line2D.Double(0,0,0,0);
-
+    private static final Line2D.Double SPACE = new Line2D.Double(0, 0, 0, 0);
 
     /** Prevent instantiations. */
     private LegendProcessor() {
     }
 
-
     /**
      * Create a hash from a legenditem.
      * This hash can then be used to merge legend items labels.
+     *
      * @return hash for given legenditem to identify mergeables.
      */
-    protected static String legendItemHash(LegendItem li) {
+    protected static String legendItemHash(final LegendItem li) {
         // TODO Do proper implementation.
         // Ensure that only mergable sets are created.
         // getFillPaint()
@@ -55,46 +53,52 @@
         // boolean isShapeFilled()
         // boolean isShapeOutlineVisible()
         // boolean isShapeVisible()
-        String hash = li.getLinePaint().toString();
+        final String hash = li.getLinePaint().toString();
         // XXX: DEAD CODE // String label = li.getLabel();
-        /*if (label.startsWith("W (") || label.startsWith("W(")) {
-            hash += "-W-";
-        }
-        else if (label.startsWith("Q(") || label.startsWith("Q (")) {
-            hash += "-Q-";
-        }*/
+        /*
+         * if (label.startsWith("W (") || label.startsWith("W(")) {
+         * hash += "-W-";
+         * }
+         * else if (label.startsWith("Q(") || label.startsWith("Q (")) {
+         * hash += "-Q-";
+         * }
+         */
 
         // WQ.java holds example of using regex Matcher/Pattern.
 
         return hash;
     }
 
-
     /**
      * Create new legend entries, dependent on settings.
-     * @param plot The plot for which to modify the legend.
-     * @param threshold How many items are needed for aggregation to
-     *                  be triggered?
+     *
+     * @param plot
+     *            The plot for which to modify the legend.
+     * @param threshold
+     *            How many items are needed for aggregation to
+     *            be triggered?
      */
-    public static void aggregateLegendEntries(XYPlot plot, int threshold) {
-        LegendItemCollection old = plot.getLegendItems();
+    public static void aggregateLegendEntries(final XYPlot plot, final int threshold) {
+        final LegendItemCollection old = plot.getLegendItems();
         // Find "similar" entries if aggregation is enabled.
 
         int maxListSize = 0;
-        int AGGR_THRESHOLD = threshold;
+        final int AGGR_THRESHOLD = threshold;
 
-        if (AGGR_THRESHOLD > old.getItemCount() || AGGR_THRESHOLD <= 0){
+        if (AGGR_THRESHOLD > old.getItemCount() || AGGR_THRESHOLD <= 0) {
             return;
         }
 
-        HashMap<String, List<LegendItem>> entries =
-            new LinkedHashMap<String, List<LegendItem>>();
-        for (Iterator<LegendItem> i = old.iterator(); i.hasNext();) {
-            LegendItem item = i.next();
-            String hash = legendItemHash(item);
+        final HashMap<String, List<LegendItem>> entries = new LinkedHashMap<>();
+        // for (Iterator<LegendItem> i = old.iterator(); i.hasNext();) {
+
+        final Iterator<LegendItem> iterator = old.iterator();
+        while (iterator.hasNext()) {
+            final LegendItem item = iterator.next();
+            final String hash = legendItemHash(item);
             List<LegendItem> itemList = entries.get(hash);
             if (itemList == null) {
-                itemList = new ArrayList<LegendItem>();
+                itemList = new ArrayList<>();
                 entries.put(hash, itemList);
             }
             itemList.add(item);
@@ -111,8 +115,8 @@
 
         // Run over collected entries, merge their names and create new
         // entry if needed.
-        LegendItemCollection newLegend = new LegendItemCollection();
-        for (List<LegendItem> itemList: entries.values()) {
+        final LegendItemCollection newLegend = new LegendItemCollection();
+        for (final List<LegendItem> itemList : entries.values()) {
             if (itemList.size() >= AGGR_THRESHOLD) {
                 // Now do merging.
                 // XXX: DEAD CODE // LegendItem item = itemList.get(0);
@@ -124,41 +128,26 @@
                 // to prevent "overfill" of legenditemblock.
                 for (int i = 0, I = itemList.size(); i < I; i++) {
                     if (i != 0) {
-                        LegendItem litem = itemList.get(i);
+                        final LegendItem litem = itemList.get(i);
 
                         // Make shape and line really small.
-                        LegendItem merged = new LegendItem(
-                            "," + litem.getLabel(),
-                            litem.getDescription(),
-                            litem.getToolTipText(),
-                            litem.getURLText(),
-                            false,
-                            SPACE,
-                            false,
-                            litem.getFillPaint(),
-                            false,
-                            litem.getOutlinePaint(),
-                            litem.getOutlineStroke(),
-                            false,
-                            SPACE,
-                            litem.getLineStroke(),
-                            litem.getLinePaint());
+                        final LegendItem merged = new LegendItem("," + litem.getLabel(), litem.getDescription(), litem.getToolTipText(), litem.getURLText(),
+                                false, SPACE, false, litem.getFillPaint(), false, litem.getOutlinePaint(), litem.getOutlineStroke(), false, SPACE,
+                                litem.getLineStroke(), litem.getLinePaint());
                         newLegend.add(merged);
-                    }
-                    else {
+                    } else {
                         newLegend.add(itemList.get(i));
                     }
                 }
-            }
-            else {
+            } else {
                 // Do not merge entries.
-                for (LegendItem li: itemList) {
+                for (final LegendItem li : itemList) {
                     newLegend.add(li);
                 }
             }
         }
 
-        plot.setFixedLegendItems (newLegend);
+        plot.setFixedLegendItems(newLegend);
     }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/artifacts/src/main/java/org/dive4elements/river/exports/XYChartGenerator.java	Tue Sep 25 16:43:51 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/exports/XYChartGenerator.java	Wed Sep 26 15:48:05 2018 +0200
@@ -392,7 +392,7 @@
         AxisDataset axisDataset = (AxisDataset) getAxisDataset(index);
 
         if (visible) {
-            axisDataset.addArea(area);
+            axisDataset.addDataset(area);
         }
         else {
             /* No range merging, for areas extending to infinity this
--- a/artifacts/src/main/java/org/dive4elements/river/exports/process/AreaProcessor.java	Tue Sep 25 16:43:51 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/exports/process/AreaProcessor.java	Wed Sep 26 15:48:05 2018 +0200
@@ -129,7 +129,7 @@
             ? upperFacetName
             : lowerFacetName;
         /* Decide axis name based on facet name */
-        generator.addAreaSeries(area,
+        generator.addAxisDataset(area,
                 axisNameForFacet(facetNameForAxis), visible);
     }
 
--- a/artifacts/src/main/java/org/dive4elements/river/exports/process/DeltaWProcessor.java	Tue Sep 25 16:43:51 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/exports/process/DeltaWProcessor.java	Wed Sep 26 15:48:05 2018 +0200
@@ -213,7 +213,7 @@
         area.addSeries(upper);
         area.addSeries(lower);
 
-        generator.addAreaSeries(area, axisName, visible);
+        generator.addAxisDataset(area, axisName, visible);
     }
 
     protected void doReferenceDeviationOut(
@@ -255,7 +255,7 @@
         marker.setStroke(new BasicStroke(2));
         marker.setPaint(Color.BLACK);
         generator.addValueMarker(marker);
-        generator.addAreaSeries(area, axisName, visible);
+        generator.addAxisDataset(area, axisName, visible);
     }
 
     @Override
--- a/artifacts/src/main/java/org/dive4elements/river/exports/process/FixDeltaWAProcessor.java	Tue Sep 25 16:43:51 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/exports/process/FixDeltaWAProcessor.java	Wed Sep 26 15:48:05 2018 +0200
@@ -66,7 +66,7 @@
             area.addSeries(seriesUp);
             area.addSeries(seriesDown);
             area.setMode(StyledAreaSeriesCollection.FILL_MODE.BETWEEN);
-            generator.addAreaSeries(area, axisName, visible);
+            generator.addAxisDataset(area, axisName, visible);
         }
     }
 
--- a/artifacts/src/main/java/org/dive4elements/river/exports/process/FixDeltaWProcessor.java	Tue Sep 25 16:43:51 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/exports/process/FixDeltaWProcessor.java	Wed Sep 26 15:48:05 2018 +0200
@@ -66,7 +66,7 @@
             area.addSeries(seriesUp);
             area.addSeries(seriesDown);
             area.setMode(StyledAreaSeriesCollection.FILL_MODE.BETWEEN);
-            generator.addAreaSeries(area, axisName, visible);
+            generator.addAxisDataset(area, axisName, visible);
         }
     }
 
--- a/artifacts/src/main/java/org/dive4elements/river/exports/process/WOutProcessor.java	Tue Sep 25 16:43:51 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/exports/process/WOutProcessor.java	Wed Sep 26 15:48:05 2018 +0200
@@ -101,7 +101,7 @@
             area.addSeries(seriesUp);
             area.addSeries(seriesDown);
             area.setMode(StyledAreaSeriesCollection.FILL_MODE.BETWEEN);
-            generator.addAreaSeries(area, axisName, visible);
+            generator.addAxisDataset(area, axisName, visible);
         }
 
         if (bundle.getFacetName().equals(FacetTypes.LONGITUDINAL_W)
--- a/artifacts/src/main/java/org/dive4elements/river/java2d/ShapeUtils.java	Tue Sep 25 16:43:51 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/java2d/ShapeUtils.java	Wed Sep 26 15:48:05 2018 +0200
@@ -8,6 +8,7 @@
 
 package org.dive4elements.river.java2d;
 
+import java.awt.Color;
 import java.awt.Shape;
 import java.awt.geom.Area;
 import java.awt.geom.Ellipse2D;
@@ -24,7 +25,7 @@
 
     private static Map<Long, Shape> scaledShapesCache = new HashMap<>();
 
-    private static final Shape createCross(float size) {
+    private static final Shape createCross(final float size) {
 
         final GeneralPath p = new GeneralPath();
 
@@ -38,15 +39,15 @@
         return p;
     }
 
-    private static Shape createBox(float size) {
+    private static Shape createBox(final float size) {
         return new Rectangle2D.Double(-size, -size, size * 2, size * 2);
     }
 
-    private static Shape createCircle(float size) {
+    private static Shape createCircle(final float size) {
         return new Ellipse2D.Float(-size, -size, size * 2, size * 2);
     }
 
-    private static final Shape createTriangle(float size) {
+    private static final Shape createTriangle(final float size) {
         final GeneralPath p = new GeneralPath();
 
         p.moveTo(-size, size);
@@ -57,7 +58,7 @@
         return new Area(p);
     }
 
-    public static synchronized Shape getScaledShape(final ShapeType type, float size) {
+    public static synchronized Shape getScaledShape(final ShapeType type, final float size) {
 
         final Long hash = Long.valueOf((((long) type.ordinal()) << 32) | Float.floatToIntBits(size));
 
@@ -70,7 +71,7 @@
         return newShape;
     }
 
-    private static Shape createScaledShape(ShapeType type, float size) {
+    private static Shape createScaledShape(final ShapeType type, final float size) {
         switch (type) {
         case measured:
             return createBox(size);
@@ -86,4 +87,12 @@
             return createCircle(size);
         }
     }
+
+    public static Color withAlpha(final Color color, final int transparencyPercent) {
+
+        if (transparencyPercent <= 0 || transparencyPercent > 100 || color == null)
+            return color;
+
+        return new Color(color.getRed(), color.getGreen(), color.getBlue(), (int) ((100 - transparencyPercent) * 2.55f));
+    }
 }
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/jfree/AxisDataset.java	Tue Sep 25 16:43:51 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/jfree/AxisDataset.java	Wed Sep 26 15:48:05 2018 +0200
@@ -8,24 +8,18 @@
 
 package org.dive4elements.river.jfree;
 
+import java.util.ArrayList;
 import java.util.List;
-import java.util.ArrayList;
 
 import org.jfree.data.Range;
 import org.jfree.data.RangeInfo;
+import org.jfree.data.time.TimeSeriesCollection;
 import org.jfree.data.xy.XYDataset;
-import org.jfree.data.xy.XYSeries;
-import org.jfree.data.xy.XYSeriesCollection;
-import org.jfree.data.time.TimeSeriesCollection;
-
-import org.apache.log4j.Logger;
 
 /**
  * Axis datasets.
  */
-public class AxisDataset
-{
-    private static Logger log = Logger.getLogger(AxisDataset.class);
+public class AxisDataset {
 
     /** Symbolic integer, but also coding the priority (0 goes first). */
     protected int axisSymbol;
@@ -42,42 +36,39 @@
     protected boolean rangeDirty;
 
     /** Create AxisDataset. */
-    public AxisDataset(int symb) {
-        axisSymbol = symb;
-        datasets   = new ArrayList<XYDataset>();
+    public AxisDataset(final int symb) {
+        this.axisSymbol = symb;
+        this.datasets = new ArrayList<>();
     }
 
     /** Add a dataset to internal list for this axis. */
-    public void addDataset(XYDataset dataset) {
-        datasets.add(dataset);
-        rangeDirty = true;
+    public void addDataset(final XYDataset dataset) {
+        this.datasets.add(dataset);
+        this.rangeDirty = true;
     }
 
-    /** Add a dataset. */
-    public void addDataset(XYSeries series) {
-        addDataset(new XYSeriesCollection(series));
-    }
-
-    public void setRange(Range val) {
-        range = val;
+    public void setRange(final Range val) {
+        this.range = val;
     }
 
     /** Get Range for the range axis of this dataset. */
     public Range getRange() {
-        if (range != null && !rangeDirty) {
-            return range;
+        if (this.range != null && !this.rangeDirty) {
+            return this.range;
         }
         /* Calculate the min / max of all series */
-        for (XYDataset dataset: datasets) {
+        for (final XYDataset dataset : this.datasets) {
             Range newRange = null;
             if (dataset instanceof StyledAreaSeriesCollection) {
                 final StyledAreaSeriesCollection areaSeries = (StyledAreaSeriesCollection) dataset;
-                if( areaSeries.shouldCalculateRange() )
+                if (areaSeries.shouldCalculateRange())
                     newRange = areaSeries.getRangeBounds(false);
                 else {
-                    /* For most area themes, we do not include areas in the range calculation because
+                    /*
+                     * For most area themes, we do not include areas in the range calculation because
                      * they are used with very large / small values to draw areas
-                     * with axis boundaries */
+                     * with axis boundaries
+                     */
                     continue;
                 }
             } else if (dataset instanceof RangeInfo) {
@@ -85,49 +76,37 @@
                 newRange = ((RangeInfo) dataset).getRangeBounds(false);
             } else if (dataset instanceof TimeSeriesCollection) {
                 /* Lalala <3 Jfreechart's class hirarchy */
-                newRange = ((TimeSeriesCollection)dataset)
-                    .getRangeBounds(false);
+                newRange = ((TimeSeriesCollection) dataset).getRangeBounds(false);
             }
 
             /* Now we only expand as we also only add new data */
-            if (range == null) {
-                range = newRange;
+            if (this.range == null) {
+                this.range = newRange;
             } else {
-                range = Range.combine(range, newRange);
+                this.range = Range.combine(this.range, newRange);
             }
         }
-        rangeDirty = false;
-        return range;
+        this.rangeDirty = false;
+        return this.range;
     }
 
     /** Get Array of Datasets. */
     public XYDataset[] getDatasets() {
-        return datasets.toArray(new XYDataset[datasets.size()]);
-    }
-
-    /** True if to be rendered as area. */
-    public boolean isArea(XYDataset series) {
-        return (series instanceof StyledAreaSeriesCollection);
+        return this.datasets.toArray(new XYDataset[this.datasets.size()]);
     }
 
     /** True if no datasets given. */
     public boolean isEmpty() {
-        return datasets.isEmpty();
+        return this.datasets.isEmpty();
     }
 
     /** Set the 'real' axis index that this axis is mapped to. */
-    public void setPlotAxisIndex(int axisIndex) {
-        plotAxisIndex = axisIndex;
+    public void setPlotAxisIndex(final int axisIndex) {
+        this.plotAxisIndex = axisIndex;
     }
 
     /** Get the 'real' axis index that this axis is mapped to. */
     public int getPlotAxisIndex() {
-        return plotAxisIndex;
+        return this.plotAxisIndex;
     }
-
-    /** Add a Dataset that describes an area. */
-    public void addArea(StyledAreaSeriesCollection series) {
-        addDataset(series);
-    }
-
-}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts/src/main/java/org/dive4elements/river/jfree/StripedAreaDataset.java	Wed Sep 26 15:48:05 2018 +0200
@@ -0,0 +1,133 @@
+/** Copyright (C) 2017 by Bundesanstalt für Gewässerkunde
+ * Software engineering by
+ *  Björnsen Beratende Ingenieure GmbH
+ *  Dr. Schumacher Ingenieurbüro für Wasser und Umwelt
+ *
+ * This file is Free Software under the GNU AGPL (>=v3)
+ * and comes with ABSOLUTELY NO WARRANTY! Check out the
+ * documentation coming with Dive4Elements River for details.
+ */
+package org.dive4elements.river.jfree;
+
+import java.awt.Color;
+import java.awt.Font;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.dive4elements.artifacts.CallMeta;
+import org.dive4elements.river.java2d.ShapeUtils;
+import org.dive4elements.river.themes.ThemeDocument;
+import org.jfree.chart.LegendItem;
+import org.jfree.chart.LegendItemCollection;
+import org.jfree.chart.plot.XYPlot;
+import org.jfree.data.xy.XYSeries;
+import org.jfree.data.xy.XYSeriesCollection;
+
+/**
+ * @author Domenico Nardi Tironi
+ */
+public class StripedAreaDataset extends XYSeriesCollection implements StyledXYDataset {
+
+    public static final class Stripe {
+
+        private final String label;
+
+        private final Color color;
+
+        private final double lower;
+
+        private final double upper;
+
+        public Stripe(final String label, final Color color, final double lower, final double upper) {
+            this.label = label;
+            this.color = color;
+            this.lower = lower;
+            this.upper = upper;
+        }
+
+        public String getLabel() {
+            return this.label;
+        }
+
+        public Color getColor() {
+            return this.color;
+        }
+
+        public double getLower() {
+            return this.lower;
+        }
+
+        public double getUpper() {
+            return this.upper;
+        }
+
+    }
+
+    private static final long serialVersionUID = 1L;
+
+    private final List<Stripe> stripes = new ArrayList<>();
+
+    private final ThemeDocument theme;
+
+    public StripedAreaDataset(final ThemeDocument theme) {
+        this.theme = theme;
+    }
+
+    public void addStripe(final Stripe stripe) {
+
+        this.stripes.add(stripe);
+
+        final XYSeries stripeSeries = new XYSeries(stripe.getLabel());
+        // REMARK: we need at least one item, so the renderer method is called
+        stripeSeries.add(Double.NaN, Double.NaN);
+        super.addSeries(stripeSeries);
+    }
+
+    @Override
+    public void addSeries(final XYSeries series) {
+        throw new UnsupportedOperationException();
+    }
+
+    Stripe getStripe(final int series) {
+        return this.stripes.get(series);
+    }
+
+    @Override
+    public void applyTheme(final CallMeta callMeta, final XYPlot plot, final int datasetIndex, final Font legendFont) {
+
+        final StripedAreaDatasetRenderer renderer = createRenderer();
+
+        plot.setRenderer(datasetIndex, renderer);
+
+        final LegendItemCollection newItems = new LegendItemCollection();
+        final LegendItemCollection oldItems = plot.getFixedLegendItems();
+
+        final int seriesCount = getSeriesCount();
+        for (int i = 0; i < seriesCount; i++) {
+            final LegendItem legendItem = renderer.getLegendItem(datasetIndex, i);
+            if (legendItem != null) {
+                legendItem.setLabelFont(legendFont);
+                newItems.add(legendItem);
+            }
+        }
+
+        if (oldItems != null)
+            newItems.addAll(oldItems);
+
+        plot.setFixedLegendItems(newItems);
+    }
+
+    private StripedAreaDatasetRenderer createRenderer() {
+
+        final int transparency = this.theme.parseAreaTransparency();
+
+        final StripedAreaDatasetRenderer renderer = new StripedAreaDatasetRenderer();
+        for (int i = 0; i < this.stripes.size(); i++) {
+
+            final Color alphaPaint = ShapeUtils.withAlpha(this.stripes.get(i).getColor(), transparency);
+            renderer.setSeriesPaint(i, alphaPaint);
+        }
+
+        return renderer;
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts/src/main/java/org/dive4elements/river/jfree/StripedAreaDatasetRenderer.java	Wed Sep 26 15:48:05 2018 +0200
@@ -0,0 +1,69 @@
+/** Copyright (C) 2017 by Bundesanstalt für Gewässerkunde
+ * Software engineering by
+ *  Björnsen Beratende Ingenieure GmbH
+ *  Dr. Schumacher Ingenieurbüro für Wasser und Umwelt
+ *
+ * This file is Free Software under the GNU AGPL (>=v3)
+ * and comes with ABSOLUTELY NO WARRANTY! Check out the
+ * documentation coming with Dive4Elements River for details.
+ */
+package org.dive4elements.river.jfree;
+
+import java.awt.Graphics2D;
+import java.awt.Paint;
+import java.awt.Stroke;
+import java.awt.geom.GeneralPath;
+import java.awt.geom.Rectangle2D;
+
+import org.dive4elements.river.jfree.StripedAreaDataset.Stripe;
+import org.jfree.chart.axis.ValueAxis;
+import org.jfree.chart.plot.CrosshairState;
+import org.jfree.chart.plot.PlotRenderingInfo;
+import org.jfree.chart.plot.XYPlot;
+import org.jfree.chart.renderer.xy.AbstractXYItemRenderer;
+import org.jfree.chart.renderer.xy.XYItemRendererState;
+import org.jfree.data.xy.XYDataset;
+
+/**
+ * @author Domenico Nardi Tironi
+ */
+final class StripedAreaDatasetRenderer extends AbstractXYItemRenderer {
+
+    private static final long serialVersionUID = 1L;
+
+    @Override
+    public void drawItem(final Graphics2D g2, final XYItemRendererState state, final Rectangle2D dataArea, final PlotRenderingInfo info, final XYPlot plot,
+            final ValueAxis domainAxis, final ValueAxis rangeAxis, final XYDataset dataset, final int series, final int item,
+            final CrosshairState crosshairState, final int pass) {
+
+        if (item != 0)
+            return;
+
+        final StripedAreaDataset stripedDataset = (StripedAreaDataset) dataset;
+        final Stripe stripe = stripedDataset.getStripe(series);
+
+        final double lower = stripe.getLower();
+        final double upper = stripe.getUpper();
+
+        final double transLower = Double.isNaN(lower) ? dataArea.getMaxY() : rangeAxis.valueToJava2D(lower, dataArea, plot.getRangeAxisEdge());
+        final double transUpper = Double.isNaN(upper) ? dataArea.getMinY() : rangeAxis.valueToJava2D(upper, dataArea, plot.getRangeAxisEdge());
+
+        final double transLeft = dataArea.getMinX();
+        final double transRight = dataArea.getMaxX();
+
+        final GeneralPath area = new GeneralPath();
+
+        area.moveTo(transLeft, transLower);
+        area.lineTo(transRight, transLower);
+        area.lineTo(transRight, transUpper);
+        area.lineTo(transLeft, transUpper);
+        area.closePath();
+
+        final Paint paint = getItemPaint(series, item);
+        final Stroke stroke = getItemStroke(series, item);
+        g2.setPaint(paint);
+        g2.setStroke(stroke);
+
+        g2.fill(area);
+    }
+}
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/jfree/StyledAreaSeriesCollection.java	Tue Sep 25 16:43:51 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/jfree/StyledAreaSeriesCollection.java	Wed Sep 26 15:48:05 2018 +0200
@@ -10,6 +10,7 @@
 
 import java.awt.BasicStroke;
 import java.awt.Color;
+import java.awt.Font;
 import java.awt.Paint;
 import java.awt.Stroke;
 import java.awt.TexturePaint;
@@ -17,7 +18,15 @@
 import java.awt.geom.Rectangle2D;
 import java.awt.image.BufferedImage;
 
+import org.apache.log4j.Logger;
+import org.dive4elements.artifacts.CallMeta;
+import org.dive4elements.river.artifacts.resources.Resources;
+import org.dive4elements.river.java2d.ShapeUtils;
 import org.dive4elements.river.themes.ThemeDocument;
+import org.dive4elements.river.utils.Formatter;
+import org.jfree.chart.LegendItem;
+import org.jfree.chart.LegendItemCollection;
+import org.jfree.chart.plot.XYPlot;
 import org.jfree.data.xy.XYSeriesCollection;
 
 /**
@@ -27,12 +36,17 @@
  * The display options can be used to control the z-order and the axis of the
  * dataset.
  */
-// FIXME:  bad abstraction: the only purpose of this derivation is to apply specific styles. This should rather be solved similar to the XYSTyle.
-public class StyledAreaSeriesCollection extends XYSeriesCollection {
+// FIXME: bad abstraction: the only purpose of this derivation is to apply specific styles. This should rather be solved
+// similar to the XYSTyle.
+public class StyledAreaSeriesCollection extends XYSeriesCollection implements StyledXYDataset {
     private static final long serialVersionUID = 5274940965666948237L;
 
+    private static final Logger log = Logger.getLogger(StyledAreaSeriesCollection.class);
+
     /** Mode, how to draw/which areas to fill. */
-    public enum FILL_MODE {UNDER, ABOVE, BETWEEN}
+    public enum FILL_MODE {
+        UNDER, ABOVE, BETWEEN
+    }
 
     /** MODE in use. */
     private FILL_MODE mode;
@@ -41,35 +55,83 @@
     private final ThemeDocument theme;
 
     /**
-     * @param theme the theme-document.
+     * @param theme
+     *            the theme-document.
      */
     public StyledAreaSeriesCollection(final ThemeDocument theme) {
         this.theme = theme;
         this.mode = FILL_MODE.BETWEEN;
     }
 
-
     /** Gets the Fill mode. */
-    public FILL_MODE getMode() {
+    private FILL_MODE getMode() {
         return this.mode;
     }
 
-
     /** Sets the Fill mode. */
     public void setMode(final FILL_MODE fMode) {
         this.mode = fMode;
     }
 
+    @Override
+    public void applyTheme(final CallMeta callMeta, final XYPlot plot, final int datasetIndex, final Font legendFont) {
+
+        final LegendItemCollection lic = new LegendItemCollection();
+        final LegendItemCollection anno = plot.getFixedLegendItems();
+
+        log.debug("Registering an 'area'renderer at idx: " + datasetIndex);
+
+        final StableXYDifferenceRenderer dRenderer = new StableXYDifferenceRenderer();
+
+        if (getMode() == StyledAreaSeriesCollection.FILL_MODE.UNDER) {
+            dRenderer.setPositivePaint(createTransparentPaint());
+        }
+
+        plot.setRenderer(datasetIndex, dRenderer);
+
+        applyTheme(dRenderer);
+
+        // i18n
+        dRenderer.setAreaLabelNumberFormat(Formatter.getFormatter(callMeta, 2, 4));
+
+        dRenderer.setAreaLabelTemplate(Resources.getMsg(callMeta, "area.label.template", "Area=%sm2"));
+
+        final LegendItem legendItem = dRenderer.getLegendItem(datasetIndex, 0);
+        if (legendItem != null) {
+            legendItem.setLabelFont(legendFont);
+            lic.add(legendItem);
+        } else {
+            log.warn("Could not get LegentItem for renderer: " + datasetIndex + ", series-idx " + 0);
+        }
+
+        if (anno != null) {
+            lic.addAll(anno);
+        }
+
+        plot.setFixedLegendItems(lic);
+    }
+
+    /**
+     * Returns a transparently textured paint.
+     *
+     * @return a transparently textured paint.
+     */
+    private static Paint createTransparentPaint() {
+        // TODO why not use a transparent color?
+        final BufferedImage texture = new BufferedImage(1, 1, BufferedImage.TYPE_4BYTE_ABGR);
+
+        return new TexturePaint(texture, new Rectangle2D.Double(0d, 0d, 0d, 0d));
+    }
 
     /**
      * Applies line color, size and type attributes to renderer, also
      * whether to draw lines and/or points.
-     * @param renderer Renderer to apply theme to.
+     *
+     * @param renderer
+     *            Renderer to apply theme to.
      * @return \param renderer
      */
-    public StableXYDifferenceRenderer applyTheme(
-            final StableXYDifferenceRenderer renderer
-            ) {
+    private StableXYDifferenceRenderer applyTheme(final StableXYDifferenceRenderer renderer) {
         applyFillColor(renderer);
         applyShowBorder(renderer);
         applyShowArea(renderer);
@@ -81,16 +143,11 @@
         applyPointStyle(renderer);
         applyShowMinimumMaximum(renderer);
         if (this.mode == FILL_MODE.UNDER) {
-            renderer.setAreaCalculationMode(
-                    StableXYDifferenceRenderer.CALCULATE_NEGATIVE_AREA);
-        }
-        else if (this.mode == FILL_MODE.ABOVE) {
-            renderer.setAreaCalculationMode(
-                    StableXYDifferenceRenderer.CALCULATE_POSITIVE_AREA);
-        }
-        else {
-            renderer.setAreaCalculationMode(
-                    StableXYDifferenceRenderer.CALCULATE_ALL_AREA);
+            renderer.setAreaCalculationMode(StableXYDifferenceRenderer.CALCULATE_NEGATIVE_AREA);
+        } else if (this.mode == FILL_MODE.ABOVE) {
+            renderer.setAreaCalculationMode(StableXYDifferenceRenderer.CALCULATE_POSITIVE_AREA);
+        } else {
+            renderer.setAreaCalculationMode(StableXYDifferenceRenderer.CALCULATE_ALL_AREA);
         }
 
         // Apply text style.
@@ -115,13 +172,11 @@
 
         if (paint != null && this.getMode() == FILL_MODE.ABOVE) {
             renderer.setPositivePaint(paint);
-            renderer.setNegativePaint(new Color(0,0,0,0));
-        }
-        else if (paint != null && this.getMode() == FILL_MODE.UNDER) {
+            renderer.setNegativePaint(new Color(0, 0, 0, 0));
+        } else if (paint != null && this.getMode() == FILL_MODE.UNDER) {
             renderer.setNegativePaint(paint);
-            renderer.setPositivePaint(new Color(0,0,0,0));
-        }
-        else {
+            renderer.setPositivePaint(new Color(0, 0, 0, 0));
+        } else {
             if (paint == null)
                 paint = new Color(177, 117, 102);
 
@@ -134,31 +189,19 @@
         final Color paint = this.theme.parseAreaBackgroundColor();
         final int transparency = this.theme.parseAreaTransparency();
 
-        final Color alphaPaint = withAlpha(paint, transparency);
+        final Color alphaPaint = ShapeUtils.withAlpha(paint, transparency);
 
         final AreaFillPattern pattern = this.theme.parseAreaBackgroundPattern();
 
-        if( pattern == null || pattern == AreaFillPattern.patternFill )
+        if (pattern == null || pattern == AreaFillPattern.patternFill)
             return alphaPaint;
 
         final BufferedImage image = pattern.getImage(alphaPaint);
 
-        final Rectangle2D anchor = new Rectangle2D.Double(0,0, image.getWidth(), image.getHeight());
+        final Rectangle2D anchor = new Rectangle2D.Double(0, 0, image.getWidth(), image.getHeight());
         return new TexturePaint(image, anchor);
     }
 
-    private Color withAlpha(final Color color, final int transparency) {
-
-        if (transparency <= 0 || color == null)
-            return color;
-
-        return new Color(
-                color.getRed(),
-                color.getGreen(),
-                color.getBlue(),
-                (int)((100 - transparency) * 2.55f));
-    }
-
     private void applyShowBorder(final StableXYDifferenceRenderer renderer) {
         final boolean show = this.theme.parseAreaShowBorder();
         renderer.setDrawOutline(show);
@@ -195,20 +238,14 @@
 
     private void applyOutlineStyle(final StableXYDifferenceRenderer renderer) {
         final float[] dashes = this.theme.parseLineStyle();
-        final int size       = this.theme.parseLineWidth();
+        final int size = this.theme.parseLineWidth();
 
         Stroke stroke = null;
 
         if (dashes.length <= 1) {
             stroke = new BasicStroke(Integer.valueOf(size));
-        }
-        else {
-            stroke = new BasicStroke(Integer.valueOf(size),
-                    BasicStroke.CAP_BUTT,
-                    BasicStroke.JOIN_ROUND,
-                    1.0f,
-                    dashes,
-                    0.0f);
+        } else {
+            stroke = new BasicStroke(Integer.valueOf(size), BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND, 1.0f, dashes, 0.0f);
         }
 
         renderer.setOutlineStroke(stroke);
@@ -219,10 +256,9 @@
         final boolean showPoints = this.theme.parseShowPoints();
         renderer.setShapesVisible(showPoints);
 
-        if( showPoints )
-        {
+        if (showPoints) {
             final int size = this.theme.parsePointWidth();
-            final int dim  = 2 * size;
+            final int dim = 2 * size;
 
             final Ellipse2D pointShape = new Ellipse2D.Double(-size, -size, dim, dim);
             final Color pointColor = this.theme.parsePointColor();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts/src/main/java/org/dive4elements/river/jfree/StyledXYDataset.java	Wed Sep 26 15:48:05 2018 +0200
@@ -0,0 +1,24 @@
+/** Copyright (C) 2017 by Bundesanstalt für Gewässerkunde
+ * Software engineering by
+ *  Björnsen Beratende Ingenieure GmbH
+ *  Dr. Schumacher Ingenieurbüro für Wasser und Umwelt
+ *
+ * This file is Free Software under the GNU AGPL (>=v3)
+ * and comes with ABSOLUTELY NO WARRANTY! Check out the
+ * documentation coming with Dive4Elements River for details.
+ */
+package org.dive4elements.river.jfree;
+
+import java.awt.Font;
+
+import org.dive4elements.artifacts.CallMeta;
+import org.jfree.chart.plot.XYPlot;
+import org.jfree.data.xy.XYDataset;
+
+/**
+ * @author Domenico Nardi Tironi
+ *
+ */
+public interface StyledXYDataset extends XYDataset {
+    void applyTheme(CallMeta callMeta, XYPlot plot, int datasetIndex, Font legendFont);
+}
\ No newline at end of file
--- a/artifacts/src/main/resources/messages.properties	Tue Sep 25 16:43:51 2018 +0200
+++ b/artifacts/src/main/resources/messages.properties	Wed Sep 26 15:48:05 2018 +0200
@@ -1198,6 +1198,11 @@
 uinfo_salix_scenario_historical = historical
 uinfo_facet_salix_rank = Assessment Scheme
 uinfo_facet_salix_rank.description = Assessment Scheme
+uinfo_salix_rank.excellent = Excellent
+uinfo_salix_rank.good = Good
+uinfo_salix_rank.moderate = Moderate
+uinfo_salix_rank.bad = Bad
+uinfo_salix_rank.very_bad = Very bad
 uinfo_salix_calc.warning.missing_mq = MQ (MW) missing at reference gauge, no calculation possible
 uinfo_salix_calc.warning.missing_mhq = MHQ (MHW) missing at reference gauge, no salix calculation possible 
 uinfo_salix_calc.warning.missing_mnq = MNQ (MNW) missing at reference gauge, no (MW-MNW) calculation possible
--- a/artifacts/src/main/resources/messages_de.properties	Tue Sep 25 16:43:51 2018 +0200
+++ b/artifacts/src/main/resources/messages_de.properties	Wed Sep 26 15:48:05 2018 +0200
@@ -1198,6 +1198,11 @@
 uinfo_salix_scenario_historical = historisch
 uinfo_facet_salix_rank = Bewertungsschema
 uinfo_facet_salix_rank.description = Bewertungsschema
+uinfo_salix_rank.excellent = Sehr gut
+uinfo_salix_rank.good = Gut
+uinfo_salix_rank.moderate = M\u00e4\u00dfig
+uinfo_salix_rank.bad = Schlecht
+uinfo_salix_rank.very_bad = Sehr schlecht
 uinfo_salix_calc.warning.missing_mq = MQ (MW) fehlt am Bezugspegel, Berechnung nicht m\u00f6glich
 uinfo_salix_calc.warning.missing_mhq = MHQ (MHW) fehlt am Bezugspegel, Berechnung des Iota nicht m\u00f6glich
 uinfo_salix_calc.warning.missing_mnq = MNQ (MNW) fehlt am Bezugspegel, Berechnung von (MW-MNW) nicht m\u00f6glich

http://dive4elements.wald.intevation.org