# HG changeset patch # User Ingo Weinzierl # Date 1266234241 0 # Node ID 3d13fa281a7ef4b65d803508d9fdf7fc1274c07c # Parent 93978859fa9ece7f47abd15fe7f0fb235efc7395 Added new ouput mode: histogram. gnv-artifacts/trunk@688 c6561f87-3c4e-4783-a992-168aeb5c3f6f diff -r 93978859fa9e -r 3d13fa281a7e gnv-artifacts/ChangeLog --- 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 + + * 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 * doc/conf/queries.properties: diff -r 93978859fa9e -r 3d13fa281a7e gnv-artifacts/src/main/java/de/intevation/gnv/chart/AbstractChart.java --- 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 + * @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 : diff -r 93978859fa9e -r 3d13fa281a7e gnv-artifacts/src/main/java/de/intevation/gnv/chart/AbstractHistogram.java --- /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 : diff -r 93978859fa9e -r 3d13fa281a7e gnv-artifacts/src/main/java/de/intevation/gnv/chart/DefaultHistogram.java --- /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 : diff -r 93978859fa9e -r 3d13fa281a7e gnv-artifacts/src/main/java/de/intevation/gnv/chart/XMLChartTheme.java --- 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); + } } diff -r 93978859fa9e -r 3d13fa281a7e gnv-artifacts/src/main/java/de/intevation/gnv/exports/ChartExportHelper.java --- 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, diff -r 93978859fa9e -r 3d13fa281a7e gnv-artifacts/src/main/java/de/intevation/gnv/histogram/HistogramHelper.java --- /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 values = new ArrayList(); + + 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(); + List data = new ArrayList(); + + 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(); + 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 : diff -r 93978859fa9e -r 3d13fa281a7e gnv-artifacts/src/main/java/de/intevation/gnv/state/timeseries/TimeSeriesOutputState.java --- 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 parameters = getParameters(uuid); + Collection measurements = getMeasurements(uuid); + Collection 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 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");