tim@65: /**
tim@65: * Title: ChartFactory, $Header: /share/gdi/SDI-Suite/Repository/projekte/BSH-GDI/genericViewer/src/main/java/de/conterra/bsh/gdi/gnviewer/output/chart/ChartFactory.java,v 1.8 2007/12/21 12:31:15 blume Exp $
tim@65: * Source: $Source: /share/gdi/SDI-Suite/Repository/projekte/BSH-GDI/genericViewer/src/main/java/de/conterra/bsh/gdi/gnviewer/output/chart/ChartFactory.java,v $
tim@65: * created by: Stefan Blume (blume)
tim@65: * erstellt am: 06.12.2007
tim@65: * Copyright: con terra GmbH, 2005
tim@65: *
tim@65: * modified by: $Author: blume $
tim@65: * modified on: $Date: 2007/12/21 12:31:15 $
tim@65: * Version: $Revision: 1.8 $
tim@65: * TAG: $Name: $
tim@65: * locked from: $Locker: $
tim@65: * CVS State: $State: Exp $
tim@65: * Project: $ProjectName$
tim@65: */
tim@65: package de.intevation.gnv.chart;
tim@65:
tim@65: import java.awt.Color;
tim@65: import java.awt.Font;
tim@65: import java.awt.image.BufferedImage;
tim@65: import java.io.BufferedOutputStream;
tim@65: import java.io.FileOutputStream;
tim@65: import java.io.FileReader;
tim@65: import java.io.IOException;
tim@65: import java.util.Date;
tim@65:
tim@65: import org.apache.log4j.Logger;
tim@65: import org.jfree.chart.JFreeChart;
tim@65: import org.jfree.chart.axis.AxisLocation;
tim@65: import org.jfree.chart.axis.DateAxis;
tim@65: import org.jfree.chart.axis.NumberAxis;
tim@65: import org.jfree.chart.axis.NumberTickUnit;
tim@65: import org.jfree.chart.encoders.KeypointPNGEncoderAdapter;
tim@65: import org.jfree.chart.plot.PlotOrientation;
tim@65: import org.jfree.chart.plot.XYPlot;
tim@65: import org.jfree.chart.renderer.xy.StandardXYItemRenderer;
tim@65: import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
tim@65: import org.jfree.data.time.Minute;
tim@65: import org.jfree.data.time.TimeSeries;
tim@65: import org.jfree.data.time.TimeSeriesCollection;
tim@65: import org.jfree.data.xy.XYDataset;
tim@65: import org.jfree.ui.RectangleInsets;
tim@65:
tim@65: import au.com.bytecode.opencsv.CSVReader;
tim@65: import de.conterra.bsh.gdi.gnviewer.data.filter.IdValue;
tim@65: import de.conterra.bsh.gdi.gnviewer.data.filter.MeasurementId;
tim@65: import de.conterra.bsh.gdi.gnviewer.data.filter.ParameterId;
tim@65: import de.conterra.bsh.gdi.gnviewer.datasources.ResultSet;
tim@65: import de.conterra.bsh.gdi.gnviewer.datasources.Row;
tim@65: import de.conterra.bsh.gdi.gnviewer.exception.TechnicalException;
tim@65: import de.conterra.bsh.gdi.gnviewer.renderer.DiagramRenderer;
tim@65: import de.conterra.bsh.gdi.gnviewer.util.TempFile;
tim@65: import de.conterra.bsh.gdi.gnviewer.util.TemporaryFileDirectory;
tim@65:
tim@65: /**
tim@65: * The class ChartFactory
fulfills the following purposes:
tim@65: *
tim@65: *
tim@65: *
tim@65: *
tim@65: * @author blume
tim@65: * @version 1.0
tim@65: * @serial 1.0
tim@65: * @see
tim@65: * @since 06.12.2007 17:25:59
tim@65: */
tim@65: public class ChartFactory {
tim@65:
tim@65: /**
tim@65: * Default Logging instance
tim@65: */
tim@65: private static Logger sLogger = Logger.getLogger(ChartFactory.class);
tim@65: private static boolean sDebug = sLogger.isDebugEnabled();
tim@65: private final TemporaryFileDirectory mTmpImageDir;
tim@65:
tim@65: /**
tim@65: *
tim@65: */
tim@65: public ChartFactory(TemporaryFileDirectory pTmpImageDir) {
tim@65: mTmpImageDir = pTmpImageDir;
tim@65: }
tim@65:
tim@65: public synchronized TempFile createSimpleTimeSeriesChart(
tim@65: ChartLabels pLabels, ChartStyle pStyle, String pTimeSeriesName,
tim@65: TempFile tempF, IdValue[] pParameterId,
tim@65: IdValue[] pMeasurementId, IdValue[] pFeatureId
tim@65: ) throws IOException, TechnicalException {
tim@65: if (sDebug)
tim@65: sLogger.debug("createSimpleTimeSeriesChart()");
tim@65: int lLowerLevel = Integer.MIN_VALUE;
tim@65: int lUpperLevel = Integer.MAX_VALUE;
tim@65: if (pStyle.isUseUpperDataLevel()
tim@65: && pStyle.getUpperLevel() < Integer.MAX_VALUE) {
tim@65: lUpperLevel = pStyle.getUpperLevel();
tim@65: }
tim@65: if (pStyle.isUseLowerDataLevel()
tim@65: && pStyle.getLowerLevel() > Integer.MIN_VALUE) {
tim@65: lLowerLevel = pStyle.getLowerLevel();
tim@65: }
tim@65: if (sDebug)
tim@65: sLogger.debug(" vor createDataset()");
tim@65: XYDataset lSet = createDataset(pTimeSeriesName, tempF, lUpperLevel,
tim@65: lLowerLevel,pParameterId,pMeasurementId,pFeatureId);
tim@65: if (sDebug)
tim@65: sLogger.debug(" nach createDataset()");
tim@65: final Color[] color = {Color.black, Color.red, Color.green, Color.blue};
tim@65: DateAxis domain = new DateAxis("Zeit [UTC]");
tim@65: NumberAxis axis;
tim@65: StandardXYItemRenderer renderer = new StandardXYItemRenderer();
tim@65: XYPlot plot = new XYPlot();
tim@65: //Global settings
tim@65:
tim@65: plot.setOrientation(PlotOrientation.VERTICAL);
tim@65: plot.setBackgroundPaint(Color.lightGray);
tim@65: plot.setDomainGridlinePaint(Color.white);
tim@65: plot.setRangeGridlinePaint(Color.white);
tim@65: plot.setAxisOffset(new RectangleInsets(5.0,5.0,5.0,5.0));
tim@65: //plot.getRangeAxis().setFixedDimension(10.0);
tim@65: plot.setDomainAxis(domain);
tim@65: plot.setDomainAxisLocation(AxisLocation.BOTTOM_OR_LEFT);
tim@65: if (pParameterId.length == 1) {
tim@65: axis = new NumberAxis(pParameterId[0].getTitle());
tim@65: if(pParameterId[0].getTitle().contains("richtung")){
tim@65: NumberAxis axis1 = new NumberAxis(
tim@65: ((String) pParameterId[0].getTitle()));//,new Range(0.0,360.0));
tim@65: axis1.setTickUnit(new NumberTickUnit(30.0));
tim@65: axis1.setUpperBound(360.0);
tim@65: axis1.setLowerBound(0.0);
tim@65: //axis1.setDisplayRange(0.0,360.0);
tim@65: plot.setRangeAxis( axis1);
tim@65: }else{
tim@65: axis.setFixedDimension(10.0);
tim@65: axis.setAutoRangeIncludesZero(false);
tim@65: plot.setRangeAxis(axis);
tim@65: }
tim@65: axis.configure();
tim@65: plot.setRangeAxisLocation( AxisLocation.BOTTOM_OR_LEFT);
tim@65: plot.setRenderer(renderer);
tim@65: plot.setDataset(lSet);
tim@65: } else {
tim@65: // Individual settings for different parameters
tim@65: for (int i = 0; i < lSet.getSeriesCount(); i++) {
tim@65:
tim@65: plot.setDataset(i, getDataset((TimeSeriesCollection) lSet, i));
tim@65: Color mColor=color[i % color.length]; // zyklische Farbvergabe
tim@65: mColor = color[0];
tim@65: // if ( pParameterId.length==1){
tim@65:
tim@65: if(((String) lSet.getSeriesKey(i)).contains("richtung")){
tim@65: NumberAxis axis1 = new NumberAxis(((String) lSet.getSeriesKey(i)));//,new Range(0.0,360.0));
tim@65: axis1.setTickUnit(new NumberTickUnit(30.0));
tim@65: //axis1.setDisplayRange(0.0,360.0);
tim@65: axis1.setLabelPaint(mColor);
tim@65: axis1.setTickLabelPaint(mColor);
tim@65: axis1.setUpperBound(360.0);
tim@65: axis1.setLowerBound(0.0);
tim@65: plot.setRangeAxis(i, axis1);
tim@65:
tim@65:
tim@65: }
tim@65: else {
tim@65: axis = new NumberAxis((String) lSet.getSeriesKey(i));
tim@65: axis.setFixedDimension(10.0);
tim@65: axis.setAutoRangeIncludesZero(false);
tim@65: axis.setLabelPaint(mColor);
tim@65: axis.setTickLabelPaint(mColor);
tim@65: plot.setRangeAxis(i, axis);
tim@65: axis.configure();
tim@65: }
tim@65: if (i % 2 != 0)
tim@65: plot.setRangeAxisLocation(i, AxisLocation.BOTTOM_OR_RIGHT);
tim@65: else
tim@65: plot.setRangeAxisLocation(i, AxisLocation.BOTTOM_OR_LEFT);
tim@65: plot.mapDatasetToRangeAxis(i, i);
tim@65: // }
tim@65: renderer = new StandardXYItemRenderer();
tim@65: renderer.setSeriesPaint(i, mColor);
tim@65: // renderer.setSeriesStroke(i,stroke[j]);
tim@65: plot.setRenderer(i, renderer);
tim@65: }
tim@65: }
tim@65: JFreeChart chart = new JFreeChart(
tim@65: pLabels.getTitle(),
tim@65: new Font ("SansSerif",Font.BOLD,24),
tim@65: plot,true);
tim@65:
tim@65:
tim@65: setStyle(chart, pStyle);
tim@65: configureRenderingOptions(chart);
tim@65: if (sDebug)
tim@65: sLogger.debug(" vor encodeChart()");
tim@65:
tim@65: return encodeChart(chart, pStyle);
tim@65: }
tim@65: private static XYDataset getDataset(TimeSeriesCollection T, int pIndex){ //throws TechnicalException{
tim@65: //if (T.getSeriesCount() < pIndex) throw TechnicalException();
tim@65: TimeSeriesCollection TSC = new TimeSeriesCollection();
tim@65: TSC.addSeries(T.getSeries(pIndex));
tim@65: return (XYDataset) TSC;
tim@65: }
tim@65: public synchronized TempFile createScatterPlot(ChartStyle pStyle,
tim@65: ResultSet pResults) throws TechnicalException, IOException {
tim@65: ScatterPlot lPlot = new ScatterPlot("ScatterPlot", pResults);
tim@65: return encodeChart(lPlot.getChart(), pStyle);
tim@65: }
tim@65:
tim@65: private void configureRenderingOptions(JFreeChart pJfreechart) {
tim@65: org.jfree.chart.renderer.xy.XYItemRenderer xyitemrenderer = ((XYPlot) pJfreechart
tim@65: .getPlot()).getRenderer();
tim@65: if (xyitemrenderer instanceof XYLineAndShapeRenderer) {
tim@65: XYLineAndShapeRenderer xylineandshaperenderer = (XYLineAndShapeRenderer) xyitemrenderer;
tim@65: xylineandshaperenderer.setBaseShapesVisible(true);
tim@65: xylineandshaperenderer.setBaseShapesFilled(true);
tim@65: }
tim@65: }
tim@65:
tim@65: private void setStyle(JFreeChart pJfreechart, ChartStyle pStyle) {
tim@65: if (sDebug)
tim@65: sLogger.debug("setStyle()");
tim@65: pJfreechart.setBackgroundPaint(pStyle.getCanvasColor());
tim@65: XYPlot xyplot = (XYPlot) pJfreechart.getPlot();
tim@65: xyplot.setBackgroundPaint(pStyle.getPlotBackgroundColor());
tim@65: xyplot.setDomainGridlinePaint(pStyle.getDomainGridlineColor());
tim@65: xyplot.setRangeGridlinePaint(pStyle.getRangeGridlineColor());
tim@65:
tim@65: Insets lOffsets = pStyle.getAxisOffset();
tim@65: RectangleInsets lRectangleInsets = new RectangleInsets(lOffsets.mUpper,
tim@65: lOffsets.mLeft, lOffsets.mLower, lOffsets.mRight);
tim@65: xyplot.setAxisOffset(lRectangleInsets);
tim@65: xyplot.setDomainCrosshairVisible(pStyle.isDomainCrosshairVisible());
tim@65: xyplot.setRangeCrosshairVisible(pStyle.isRangeCrosshairVisible());
tim@65:
tim@65: }
tim@65:
tim@65:
tim@65: private TimeSeries createTimeSeries(String pTimeSeriesName, TempFile tempF,
tim@65: int lUpperCut, int lLowerCut,int pStart,int pEnd, Date dStart, Date dEnd) throws TechnicalException{
tim@65: if (sDebug)
tim@65: sLogger.debug("createTimeSeries()");
tim@65: Row lRow0, lRow1, lRowVorEnd;
tim@65:
tim@65: Date lDate=null, lDate0=null;
tim@65: DiagramRenderer mDiagramRenderer = new DiagramRenderer();
tim@65:
tim@65: CSVReader reader = null;
tim@65: TimeSeries lTimeseries = new TimeSeries(pTimeSeriesName,
tim@65: org.jfree.data.time.Minute.class);
tim@65: try {
tim@65: reader = new CSVReader (new FileReader(tempF.getFile()), ';');
tim@65:
tim@65:
tim@65:
tim@65: long maxGap=0, lDateDiff=0;
tim@65: double lValue=0;
tim@65: String [] lRow = null;
tim@65:
tim@65: int i = 0;
tim@65: while ((lRow = reader.readNext()) != null){
tim@65:
tim@65: if (i >= pStart+1 && i <= pEnd){
tim@65: if (i == pStart+1){
tim@65: lRow0 = new Row(lRow);//
tim@65:
tim@65: // Handle Gaps > 0.5% timeserieslength, i.e do not draw here
tim@65: // +TODO mache maxGap variabel über diagram options
tim@65: maxGap = (dEnd.getTime() - dStart.getTime()) / 200; // 0,5 prozent der Länge
tim@65: if (maxGap < 3600000) maxGap=3600010;
tim@65: if (maxGap <(dEnd.getTime() - dStart.getTime())/(pEnd-pStart))
tim@65: maxGap = (dEnd.getTime() - dStart.getTime())/(pEnd-pStart) + 1000;
tim@65:
tim@65: if (sDebug)
tim@65: sLogger.debug("MaxGap : "+maxGap/1000+" Länge : "+(dEnd.getTime() - dStart.getTime())/1000+
tim@65: "Intervall "+(dEnd.getTime() - dStart.getTime())/(pEnd-pStart)/1000);
tim@65: lDate = lRow0.getDateValue(0);
tim@65: lDate0 = lDate;
tim@65: lValue = lRow0.getDoubleValue(1);
tim@65: if (lValue > lLowerCut && lValue < lUpperCut){
tim@65: //lTimeseries.addOrUpdate(new Minute(lDate), lValue);
tim@65: lTimeseries.add(new Minute(lDate), lValue);
tim@65: }
tim@65: }
tim@65: //for (int i = pStart+1; i <= pEnd; i++) {
tim@65: lRow1 = new Row (lRow);
tim@65: lDate = lRow1.getDateValue(0);
tim@65: lValue = lRow1.getDoubleValue(1);
tim@65: lDateDiff = lDate.getTime() - lDate0.getTime();
tim@65: if (lDateDiff > maxGap) {
tim@65: // add 1 minute in millisecs to left hand side Date
tim@65: // and insert Dummy to break line
tim@65: lDate0.setTime((lDate0.getTime() + 60000));
tim@65: lTimeseries.addOrUpdate(new Minute(lDate0), null);
tim@65: lTimeseries.addOrUpdate(new Minute(lDate), lValue);
tim@65: //lTimeseries.add(new Minute(lDate0), null);
tim@65: } else if (lDateDiff == 0) {
tim@65: if (sDebug)
tim@65: sLogger.debug("Datediff: "+lDateDiff+" bei index : "+i+" Datum : "+lDate+" "+lDate0);
tim@65: }
tim@65: else if (lValue > lLowerCut && lValue < lUpperCut) {
tim@65: lTimeseries.addOrUpdate(new Minute(lDate), lValue);
tim@65: //lTimeseries.add(new Minute(lDate), lValue);
tim@65: }
tim@65: lRow0 = lRow1;
tim@65: lDate0 = lDate;
tim@65: }
tim@65: i++;
tim@65: }
tim@65:
tim@65:
tim@65: } catch (OutOfMemoryError e) {
tim@65: sLogger.error(e.getMessage(), e);
tim@65: return lTimeseries;
tim@65:
tim@65: } catch (Exception e) { //TechnicalException
tim@65: sLogger.error(e.getMessage(), e);
tim@65: }
tim@65: finally {
tim@65: try{
tim@65: reader.close();
tim@65: }
tim@65: catch (Exception e){
tim@65: sLogger.error(e.getMessage(), e);
tim@65: }
tim@65: }
tim@65:
tim@65: return lTimeseries;
tim@65: }
tim@65:
tim@65: private XYDataset createDataset(String pTimeseriesName, TempFile tempF,
tim@65: int lUpperCut, int lLowerCut,IdValue[] pParameterId,
tim@65: IdValue[] pMeasurementId, IdValue[] pFeatureID) throws TechnicalException {
tim@65:
tim@65: CSVReader reader=null;
tim@65: TimeSeriesCollection lTimeSeriesCollection = new TimeSeriesCollection();
tim@65: try{
tim@65: for (int i=0;i