changeset 617:3d13fa281a7e

Added new ouput mode: histogram. gnv-artifacts/trunk@688 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Ingo Weinzierl <ingo.weinzierl@intevation.de>
date Mon, 15 Feb 2010 11:44:01 +0000
parents 93978859fa9e
children 250160797195
files gnv-artifacts/ChangeLog gnv-artifacts/src/main/java/de/intevation/gnv/chart/AbstractChart.java gnv-artifacts/src/main/java/de/intevation/gnv/chart/AbstractHistogram.java gnv-artifacts/src/main/java/de/intevation/gnv/chart/DefaultHistogram.java gnv-artifacts/src/main/java/de/intevation/gnv/chart/XMLChartTheme.java gnv-artifacts/src/main/java/de/intevation/gnv/exports/ChartExportHelper.java gnv-artifacts/src/main/java/de/intevation/gnv/histogram/HistogramHelper.java gnv-artifacts/src/main/java/de/intevation/gnv/state/timeseries/TimeSeriesOutputState.java
diffstat 8 files changed, 495 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/gnv-artifacts/ChangeLog	Fri Feb 12 18:04:58 2010 +0000
+++ b/gnv-artifacts/ChangeLog	Mon Feb 15 11:44:01 2010 +0000
@@ -1,3 +1,23 @@
+2010-02-15  Ingo Weinzierl <ingo.weinzierl@intevation.de>
+
+	* src/main/java/de/intevation/gnv/state/timeseries/TimeSeriesOutputState.java:
+	  Added code path to create and return histograms.
+
+	* src/main/java/de/intevation/gnv/chart/AbstractHistogram.java,
+	  src/main/java/de/intevation/gnv/chart/DefaultHistogram.java: New. Classes
+	  for creating histograms. Each histogram contains exactly one parameter.
+
+	* src/main/java/de/intevation/gnv/chart/XMLChartTheme.java: Added parsing
+	  of histogram bar color.
+
+	* src/main/java/de/intevation/gnv/exports/ChartExportHelper.java: Added a
+	  new funcion to copy all histograms into a single image and send it to
+	  output stream.
+
+	* src/main/java/de/intevation/gnv/histogram/HistogramHelper.java: New. Added
+	  helper function to split the result collections for each parameter and for 
+	  each measurement into pieces.
+
 2010-02-12  Tim Englich  <tim.englich@intevation.de>
 
 	* doc/conf/queries.properties: 
--- a/gnv-artifacts/src/main/java/de/intevation/gnv/chart/AbstractChart.java	Fri Feb 12 18:04:58 2010 +0000
+++ b/gnv-artifacts/src/main/java/de/intevation/gnv/chart/AbstractChart.java	Mon Feb 15 11:44:01 2010 +0000
@@ -7,7 +7,7 @@
 import org.jfree.chart.ChartTheme;
 
 /**
- * @author Ingo Weinzierl <ingo.weinzierl@intevation.de>
+ * @author Ingo Weinzierl (ingo.weinzierl@intevation.de)
  */
 public abstract class AbstractChart
 implements            Chart
@@ -28,4 +28,4 @@
 
     public abstract JFreeChart generateChart();
 }
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=latin1 :
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gnv-artifacts/src/main/java/de/intevation/gnv/chart/AbstractHistogram.java	Mon Feb 15 11:44:01 2010 +0000
@@ -0,0 +1,79 @@
+package de.intevation.gnv.chart;
+
+import java.util.Locale;
+
+import org.apache.log4j.Logger;
+
+import org.jfree.chart.ChartFactory;
+import org.jfree.chart.ChartTheme;
+import org.jfree.chart.JFreeChart;
+
+import org.jfree.chart.axis.NumberAxis;
+import org.jfree.chart.plot.PlotOrientation;
+import org.jfree.chart.plot.XYPlot;
+import org.jfree.chart.renderer.xy.XYBarRenderer;
+
+import org.jfree.data.statistics.HistogramDataset;
+
+
+/**
+ * @author Ingo Weinzierl (ingo.weinzierl@intevation.de)
+ */
+public abstract class AbstractHistogram
+implements            Chart
+{
+    private Logger logger = Logger.getLogger(AbstractHistogram.class);
+
+    protected JFreeChart  chart;
+    protected ChartLabels labels;
+    protected ChartTheme  theme;
+    protected Object[]    data;
+
+    protected Locale     locale;
+
+
+    public AbstractHistogram(
+        ChartLabels labels, Object[] data, ChartTheme theme
+    ) {
+        this.labels = labels;
+        this.data   = data;
+        this.theme  = theme;
+    }
+
+
+    public JFreeChart generateChart() {
+
+        if (chart != null)
+            return chart;
+
+        chart = ChartFactory.createHistogram(
+            labels.getTitle(),
+            labels.getDomainAxisLabel(),
+            labels.getRangeAxisLabel(),
+            null,
+            PlotOrientation.VERTICAL,
+            true,
+            false,
+            false);
+
+        applyDatasets();
+
+        theme.apply(chart);
+        adjustPlot();
+
+        return chart;
+    }
+
+
+    protected void adjustPlot() {
+        XYPlot plot = (XYPlot) chart.getPlot();
+        XYBarRenderer renderer = (XYBarRenderer) plot.getRenderer();
+
+        renderer.setShadowVisible(false);
+        renderer.setSeriesVisibleInLegend(0, false);
+    }
+
+
+    protected abstract void applyDatasets();
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gnv-artifacts/src/main/java/de/intevation/gnv/chart/DefaultHistogram.java	Mon Feb 15 11:44:01 2010 +0000
@@ -0,0 +1,61 @@
+package de.intevation.gnv.chart;
+
+import java.util.Locale;
+
+import org.apache.log4j.Logger;
+
+import org.jfree.chart.ChartTheme;
+import org.jfree.chart.JFreeChart;
+import org.jfree.chart.axis.NumberAxis;
+import org.jfree.chart.plot.XYPlot;
+import org.jfree.chart.renderer.xy.XYBarRenderer;
+
+import org.jfree.data.general.Dataset;
+import org.jfree.data.statistics.HistogramDataset;
+
+
+/**
+ * @author Ingo Weinzierl (ingo.weinzierl@intevation.de)
+ */
+public class DefaultHistogram
+extends      AbstractHistogram
+{
+    // TODO take a better default value
+    public static final int DEFAULT_BINS = 15;
+
+    private static Logger logger = Logger.getLogger(DefaultHistogram.class);
+
+
+    public DefaultHistogram(
+        ChartLabels labels, Object[] data, ChartTheme theme
+    ) {
+        super(labels, data, theme);
+    }
+
+
+    protected void applyDatasets() {
+        XYPlot plot = (XYPlot) chart.getPlot();
+
+        // prepare data and create add them to histogram dataset
+        String   name   = (String)   data[0];
+        double[] values = toDouble((Double[]) data[1]);
+
+        HistogramDataset dataset = new HistogramDataset();
+        dataset.addSeries(name, values, DEFAULT_BINS);
+
+        plot.setDataset(0, dataset);
+    }
+
+
+    protected double[] toDouble(Double[] array) {
+        int length      = array.length;
+        double[] values = new double[length];
+
+        for(int i = 0; i < length; i++) {
+            values[i] = array[i].doubleValue();
+        }
+
+        return values;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- a/gnv-artifacts/src/main/java/de/intevation/gnv/chart/XMLChartTheme.java	Fri Feb 12 18:04:58 2010 +0000
+++ b/gnv-artifacts/src/main/java/de/intevation/gnv/chart/XMLChartTheme.java	Mon Feb 15 11:44:01 2010 +0000
@@ -2,6 +2,7 @@
 
 import java.awt.Font;
 import java.awt.Color;
+import java.awt.Paint;
 import java.awt.geom.Ellipse2D;
 import java.lang.NumberFormatException;
 
@@ -9,6 +10,8 @@
 
 import org.jfree.chart.StandardChartTheme;
 import org.jfree.chart.plot.XYPlot;
+import org.jfree.chart.renderer.xy.AbstractXYItemRenderer;
+import org.jfree.chart.renderer.xy.XYBarRenderer;
 import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
 import org.jfree.ui.RectangleInsets;
 import org.jfree.util.UnitType;
@@ -36,6 +39,8 @@
     protected int pointWidth;
     protected int pointHeight;
 
+    protected Paint histogramBasePaint;
+
 
     public XMLChartTheme(String name) {
         super(name);
@@ -62,6 +67,16 @@
     }
 
 
+    public void setHistogramBasePaint(Color c) {
+        this.histogramBasePaint = c;
+    }
+
+
+    public Paint getHistogramBasePaint() {
+        return histogramBasePaint;
+    }
+
+
     public void applyXMLConfiguration(Document document) {
         log.debug("create XMLChartTheme");
 
@@ -79,6 +94,7 @@
         initAxisParameters(document);
         initLegendParameters(document);
         initRenderer(document);
+        initHistogramColor(document);
     }
 
 
@@ -213,6 +229,16 @@
     }
 
 
+    private void initHistogramColor(Document document) {
+        log.debug("init histogram color");
+        String tmp = getString(document, "theme/histogram/bar/color/@value");
+        Color c = decodeColor(tmp);
+
+        if (c != null)
+            setHistogramBasePaint(c);
+    }
+
+
     private static String getString(Document document, String xpath) {
         return Config.getStringXPath(document, xpath);
     }
@@ -271,7 +297,14 @@
         plot.setDomainCrosshairVisible(this.domainCrosshairVisible);
         plot.setRangeCrosshairVisible(this.rangeCrosshairVisible);
 
-        applyToXYLineAndShapeRenderer(plot);
+        AbstractXYItemRenderer renderer = (AbstractXYItemRenderer) 
+            plot.getRenderer();
+
+        if (renderer instanceof XYLineAndShapeRenderer)
+            applyToXYLineAndShapeRenderer(plot);
+
+        if (renderer instanceof XYBarRenderer)
+            applyToXYBarRenderer(plot);
     }
 
 
@@ -292,4 +325,14 @@
 
         plot.setRenderer(renderer);
     }
+
+
+    protected void applyToXYBarRenderer(XYPlot plot) {
+        if (plot == null)
+            return;
+
+        XYBarRenderer renderer = (XYBarRenderer) plot.getRenderer();
+
+        renderer.setSeriesPaint(0, histogramBasePaint);
+    }
 }
--- a/gnv-artifacts/src/main/java/de/intevation/gnv/exports/ChartExportHelper.java	Fri Feb 12 18:04:58 2010 +0000
+++ b/gnv-artifacts/src/main/java/de/intevation/gnv/exports/ChartExportHelper.java	Mon Feb 15 11:44:01 2010 +0000
@@ -9,9 +9,12 @@
 import com.lowagie.text.pdf.PdfWriter;
 
 import java.awt.Transparency;
+import java.awt.Graphics;
 import java.awt.Graphics2D;
+import java.awt.geom.Point2D;
 import java.awt.geom.Rectangle2D;
 import java.awt.geom.Rectangle2D.Double;
+import java.awt.image.BufferedImage;
 import java.io.OutputStream;
 import java.io.OutputStreamWriter;
 import java.io.IOException;
@@ -25,6 +28,7 @@
 import org.jfree.chart.JFreeChart;
 
 import de.intevation.artifactdatabase.XMLUtils;
+import de.intevation.gnv.chart.Chart;
 
 
 /**
@@ -58,6 +62,31 @@
     }
 
 
+    public static void exportHistograms(
+        OutputStream out,
+        Chart[]      histograms,
+        String       format,
+        int          width,
+        int          height)
+    throws IOException
+    {
+        log.info("export histograms");
+
+        int size            = histograms.length;
+        BufferedImage image = new BufferedImage(
+            width, height*size, BufferedImage.TYPE_INT_RGB);
+        Graphics2D g        = image.createGraphics();
+
+        for (int i = 0; i < size; i++) {
+            JFreeChart chart = histograms[i].generateChart();
+            chart.draw(g, new Rectangle2D.Double(0.0D, i*height, width, height));
+        }
+        g.finalize();
+
+        ImageIO.write(image, format, out);
+    }
+
+
     public static void exportSVG(
         OutputStream out,
         JFreeChart   chart,
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gnv-artifacts/src/main/java/de/intevation/gnv/histogram/HistogramHelper.java	Mon Feb 15 11:44:01 2010 +0000
@@ -0,0 +1,214 @@
+package de.intevation.gnv.histogram;
+
+import de.intevation.gnv.geobackend.base.Result;
+import de.intevation.gnv.geobackend.base.ResultDescriptor;
+
+import de.intevation.gnv.state.describedata.KeyValueDescibeData;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+
+/**
+ * @author Ingo Weinzierl (ingo.weinzierl@intevation.de)
+ */
+public class HistogramHelper {
+
+    private static Logger logger = Logger.getLogger(HistogramHelper.class);
+
+
+    private HistogramHelper() {
+    }
+
+
+/*
+    public static Object[][] prepareHistogramData(
+        Collection input,
+        Collection parameters,
+        Collection measurements,
+        Collection dates
+    ) {
+        List<Double> values = new ArrayList<Double>();
+
+        ResultDescriptor rd;
+        int b1Idx, b2Idx, b3Idx, yIdx;
+
+        Iterator it = parameters.iterator();
+        KeyValueDescibeData param = (KeyValueDescibeData) it.hasNext();
+        int parameter = param.getValue();
+
+        Iterator iter = input.iterator();
+        while (iter.hasNext()) {
+            Result row = (Result) iter.next();
+
+            if (rd == null) {
+                rd    = row.getResultDescriptor();
+                b1Idx = rd.getColumnIndex("GROUP1");
+                b2Idx = rd.getColumnIndex("GROUP2");
+                b3Idx = rd.getColumnIndex("GROUP3");
+            }
+
+            if (row.getInteger(b1Idx) == parameter 
+            &&  row.getInteger(b2Idx) == measurement)
+            {
+                
+            }
+        }
+
+        return null;
+    }
+    */
+
+    public static Object[][] prepareHistogramData(
+        Collection input,
+        Collection parameters,
+        Collection measurements,
+        Collection dates
+    ) {
+        List names = new ArrayList<String>();
+        List data  = new ArrayList<Double[]>();
+
+        if (logger.isDebugEnabled()) {
+            logger.debug("############ prepare histogram data ##########");
+            logger.debug("Input data size: " + input.size());
+        }
+
+        if (input == null) {
+            return new Object[0][0];
+        }
+
+        String break1, break2, break3;
+        int b1Idx = -1;
+        int b2Idx = -1;
+        int b3Idx = -1;
+        int yIdx  = -1;
+        try {
+            Iterator iter = input.iterator();
+
+            if (iter.hasNext()) {
+                Result row = (Result) iter.next();
+                Result previousRow = row;
+
+                if (b1Idx == -1) {
+                    ResultDescriptor rd = row.getResultDescriptor();
+                    b1Idx = rd.getColumnIndex("GROUP1");
+                    b2Idx = rd.getColumnIndex("GROUP2");
+                    b3Idx = rd.getColumnIndex("GROUP3");
+                    yIdx  = rd.getColumnIndex("YORDINATE");
+
+                    if (b1Idx == -1 || b2Idx == -1 || b3Idx == -1 || yIdx == -1) {
+                        return new Object[0][0];
+                    }
+                }
+                break1 = row.getString(b1Idx);
+                break2 = row.getString(b2Idx);
+                break3 = row.getString(b3Idx);
+
+                List values = new ArrayList<Double>();
+                while (iter.hasNext()) {
+
+                    // found new series
+                    if (!break1.equals(row.getString(b1Idx))
+                        || !break2.equals(row.getString(b2Idx))
+                        || !break3.equals(row.getString(b3Idx))
+                        ) {
+
+                        // get parameter name
+                        String name = generateName(
+                            break1, break2, break3,
+                            parameters, measurements, dates
+                        );
+
+                        // add values and parameter name
+                        data.add((Double[]) values.toArray(new Double[values.size()]));
+                        names.add(name);
+
+                        if (logger.isDebugEnabled()) {
+                            logger.debug(" --- series name: " + name);
+                            logger.debug(" --- series items: " + values.size());
+                        }
+
+                        values.clear();
+
+                        Double yValue = row.getDouble(yIdx);
+                        if (yValue != null)
+                            values.add(yValue);
+
+                        // set new conditions to find new series
+                        break1 = row.getString(b1Idx);
+                        break2 = row.getString(b2Idx);
+                        break3 = row.getString(b3Idx);
+
+                        previousRow = row;
+                        row         = (Result) iter.next();
+                    } else {
+
+                        Double value = row.getDouble(yIdx);
+                        if (value != null)
+                            values.add(value);
+
+                        row = (Result) iter.next();
+                    }
+                }
+
+                Double yValue = row.getDouble(yIdx);
+                if (yValue != null)
+                    values.add(yValue);
+
+                String name = generateName(
+                    break1, break2, break3, parameters, measurements, dates);
+
+                if (logger.isDebugEnabled()) {
+                    logger.debug(" --- series name: " + name);
+                    logger.debug(" --- series items: " + values.size());
+                }
+
+                data.add((Double[]) values.toArray(new Double[values.size()]));
+                names.add(name);
+            }
+        }
+        catch (Exception e) {
+            logger.error(e.getMessage(), e);
+        }
+
+        int series = data.size();
+        logger.debug(" === Found total: " + series);
+        Object[][] obj = new Object[series][2];
+        for (int i = 0; i < series; i++) {
+            obj[i][0] = names.get(i);
+            obj[i][1] = (Double[]) data.get(i);
+        }
+
+        return obj;
+    }
+
+
+    protected static String generateName(
+        String break1, String break2, String break3,
+        Collection parameters, Collection measurements, Collection dates)
+    {
+        return findValueTitle(parameters,break1) + " " +
+               findValueTitle(measurements,break2) + "m";
+    }
+
+
+    protected static String findValueTitle(Collection values, String id) {
+        if (values != null) {
+            Iterator it = values.iterator();
+
+            while (it.hasNext()) {
+                KeyValueDescibeData data = (KeyValueDescibeData) it.next();
+
+                if (id.equals(data.getKey())) {
+                    return data.getValue();
+                }
+            }
+        }
+        return "";
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- a/gnv-artifacts/src/main/java/de/intevation/gnv/state/timeseries/TimeSeriesOutputState.java	Fri Feb 12 18:04:58 2010 +0000
+++ b/gnv-artifacts/src/main/java/de/intevation/gnv/state/timeseries/TimeSeriesOutputState.java	Mon Feb 15 11:44:01 2010 +0000
@@ -19,6 +19,7 @@
 
 import de.intevation.gnv.chart.Chart;
 import de.intevation.gnv.chart.ChartLabels;
+import de.intevation.gnv.chart.DefaultHistogram;
 import de.intevation.gnv.chart.TimeSeriesChart;
 import de.intevation.gnv.chart.XMLChartTheme;
 
@@ -35,6 +36,8 @@
 
 import de.intevation.gnv.geobackend.base.Result;
 
+import de.intevation.gnv.histogram.HistogramHelper;
+
 import de.intevation.gnv.state.InputData;
 import de.intevation.gnv.state.OutputStateBase;
 
@@ -289,6 +292,40 @@
                     callContext
                 );
             }
+            else if (outputMode.equalsIgnoreCase("histogram")) {
+                log.debug("Create histogram.");
+
+                Collection results      = (Collection)
+                    getChartResult(uuid, callContext);
+
+                String exportFormat = getExportFormat(mimeType);
+                Collection<KeyValueDescibeData> parameters = getParameters(uuid);
+                Collection<KeyValueDescibeData> measurements = getMeasurements(uuid);
+                Collection<KeyValueDescibeData> dates        = getDates(uuid);
+                Object[][] data = HistogramHelper.prepareHistogramData(
+                    results, parameters, measurements, dates);
+
+                int size           = data.length;
+                Chart[] histograms = new Chart[size];
+
+                for (int i = 0; i < size; i++) {
+                    ChartLabels labels = createHistogramLabels(
+                        uuid, callContext, data[i]);
+
+                    ChartTheme theme   = createStyle(callContext);
+
+                    histograms[i] = new DefaultHistogram(
+                        labels, data[i], theme);
+                }
+
+                ChartExportHelper.exportHistograms(
+                    outputStream,
+                    histograms,
+                    exportFormat,
+                    chartWidth,
+                    chartHeight
+                );
+            }
             else if (outputMode.equalsIgnoreCase("pdf")) {
                 log.debug("Output mode == pdf");
 
@@ -385,7 +422,8 @@
 
                 XMLUtils.toStream(doc, outputStream);
 
-            } else if (outputMode.equalsIgnoreCase("odv")) {
+            }
+            else if (outputMode.equalsIgnoreCase("odv")) {
                 Collection<Result> odvResult = this.getODVResult(uuid);
                 this.createODV(outputStream, odvResult);
             }
@@ -773,6 +811,13 @@
     }
 
 
+    protected ChartLabels createHistogramLabels(
+        String uuid, CallContext context, Object[] data)
+    {
+        return new ChartLabels((String) data[0], "", "");
+    }
+
+
     protected String getFisName(Locale locale) {
         String    returnValue = "";
         InputData input       = inputData.get("fisname");

http://dive4elements.wald.intevation.org