Mercurial > dive4elements > gnv-client
view gnv-artifacts/src/main/java/de/intevation/gnv/chart/TimeSeriesChart.java @ 340:07a64cfafdf1
Added gap detection in horizontal and vertical profile charts. Distinguish between meshes and other data sources.
gnv-artifacts/trunk@406 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author | Ingo Weinzierl <ingo.weinzierl@intevation.de> |
---|---|
date | Wed, 09 Dec 2009 10:22:20 +0000 |
parents | e964a3d8f7bc |
children | 2f84ac484d8c |
line wrap: on
line source
package de.intevation.gnv.chart; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.Locale; import org.apache.log4j.Logger; import org.jfree.chart.ChartTheme; import org.jfree.chart.ChartFactory; import org.jfree.chart.JFreeChart; import org.jfree.chart.axis.Axis; import org.jfree.chart.axis.DateAxis; import org.jfree.chart.plot.XYPlot; import org.jfree.chart.plot.PlotOrientation; import org.jfree.data.general.Series; import org.jfree.data.time.TimeSeries; import org.jfree.data.time.Minute; import org.jfree.data.time.TimeSeriesCollection; import de.intevation.gnv.geobackend.base.Result; import de.intevation.gnv.state.describedata.KeyValueDescibeData; import de.intevation.gnv.timeseries.gap.TimeGap; /** * @author Ingo Weinzierl <ingo.weinzierl@intevation.de> */ public class TimeSeriesChart extends AbstractXYLineChart { private static final String DATE_FORMAT = "dd-MMM"; private static final long NO_TIME_GAP = Long.MAX_VALUE - 1000; private static Logger log = Logger.getLogger(TimeSeriesChart.class); public TimeSeriesChart( ChartLabels labels, ChartTheme theme, Collection parameters, Collection measurements, Collection dates, Collection result, Collection timeGaps, Locale locale, boolean linesVisible, boolean shapesVisible ) { this.labels = labels; this.theme = theme; this.parameters = parameters; this.measurements = measurements; this.dates = dates; this.resultSet = result; this.timeGaps = timeGaps; this.locale = locale; this.PLOT_ORIENTATION = PlotOrientation.VERTICAL; this.linesVisible = linesVisible; this.shapesVisible = shapesVisible; this.datasets = new HashMap(); } protected void initChart() { chart = ChartFactory.createTimeSeriesChart( labels.getTitle(), labels.getDomainAxisLabel(), null, null, true, false, false ); } protected void initData() { log.debug("init data for timeseries chart"); String breakPoint1 = null; String breakPoint2 = null; String breakPoint3 = null; Iterator iter = resultSet.iterator(); Result row = null; String seriesName = null; TimeSeries series = null; int idx = 0; int startPos = 0; int endPos = 0; Date startDate = null; Date endDate = null; Result[] results = (Result[]) resultSet.toArray(new Result[resultSet.size()]); while (iter.hasNext()) { row = (Result) iter.next(); // add current data to plot and prepare for next one if (!row.getString("GROUP1").equals(breakPoint1) || !row.getString("GROUP2").equals(breakPoint2) || !row.getString("GROUP3").equals(breakPoint3) ) { log.debug("prepare data/plot for next dataset"); if(series != null) { // add gaps before adding series to chart startDate = results[startPos].getDate("XORDINATE"); endDate = results[endPos-1].getDate("XORDINATE"); addGaps(results,series,startDate,endDate,startPos,endPos); addSeries(series, seriesName, idx); startPos = endPos + 1; } // prepare variables for next plot breakPoint1 = row.getString("GROUP1"); breakPoint2 = row.getString("GROUP2"); breakPoint3 = row.getString("GROUP3"); seriesName = createSeriesName( breakPoint1, breakPoint2, breakPoint3 ); log.debug("next dataset is '" + seriesName + "'"); series = new TimeSeries(seriesName, Minute.class); } addValue(row, series); endPos++; } // add the last dataset if existing to plot and prepare its axis startDate = results[startPos].getDate("XORDINATE"); endDate = results[endPos-1].getDate("XORDINATE"); addGaps(results, series, startDate, endDate, startPos, endPos); addSeries(series, seriesName, idx); addDatasets(); } protected void addValue(Result row, Series series) { ((TimeSeries) series).addOrUpdate( new Minute(row.getDate("XORDINATE")), row.getDouble("YORDINATE") ); } protected void addSeries(Series series, String label, int idx) { log.debug("add series (" + label + ")to timeseries chart"); if (series == null) { log.warn("no data to add"); return; } TimeSeriesCollection tsc = null; String parameter = findParameter(label); if (datasets.containsKey(parameter)) tsc = (TimeSeriesCollection) datasets.get(parameter); else tsc = new TimeSeriesCollection(); tsc.addSeries((TimeSeries) series); datasets.put(parameter, tsc); } protected void addDatasets() { Iterator iter = parameters.iterator(); XYPlot plot = chart.getXYPlot(); int idx = 0; TimeSeriesCollection tsc = null; KeyValueDescibeData data = null; String key = null; while (iter.hasNext()) { data = (KeyValueDescibeData) iter.next(); key = data.getValue(); if (datasets.containsKey(key)) { tsc = (TimeSeriesCollection)datasets.get(key); plot.setDataset(idx, tsc ); log.debug("Added " + key + " parameter to plot."); prepareAxis(key, idx); adjustRenderer( idx++, tsc.getSeriesCount(), linesVisible, shapesVisible ); } } } protected void localizeDomainAxis(Axis axis, Locale locale) { if (locale == null) return; log.debug( "Set language of axis [" + axis.getLabel() + "] " + "to " + locale.toString() ); DateFormat format = new SimpleDateFormat(DATE_FORMAT, locale); ((DateAxis) axis).setDateFormatOverride(format); } protected String createSeriesName( String breakPoint1, String breakPoint2, String breakPoint3 ) { log.debug("create seriesname of timeseries chart"); return findValueTitle(parameters, breakPoint1) + " " + findValueTitle(measurements, breakPoint2) + "m"; } protected void addGaps( Result[] results, Series series, Date startDate, Date endDate, int startPos, int endPos ) { int gapID = results[startPos].getInteger("GAPID"); long maxDiff = calculateGapSize( startDate, endDate, startPos, endPos, gapID ); Date last = startDate; for (int i = startPos+1; i < endPos; i++) { Result res = results[i]; Date now = res.getDate("XORDINATE"); if ((now.getTime() - last.getTime()) > maxDiff) { // add gap, add 1 minute to last date and add null value log.info( "Gap between " + last.toString() + " and " + now.toString() ); last.setTime(last.getTime() + 60000); ((TimeSeries) series).addOrUpdate(new Minute(last), null); } last = now; } } protected long calculateGapSize( Date start, Date end, int startPos, int endPos, int gapID ){ long maxGap = (end.getTime() - start.getTime()) / 20; long interval = getTimeGapValue(start, end, startPos, endPos, gapID); if (maxGap < interval) maxGap = interval + 10; return maxGap; } protected long getTimeGapValue( Date dStart, Date dEnd, int pStart, int pEnd, int gapID ){ long gap = 0; if (gapID < 0 || gapID >= 99) { if (gapID == -1) { // no gaps in meshes gap = NO_TIME_GAP; } else if (pEnd-pStart < 60) { gap = (3/(pEnd-pStart)) * (dEnd.getTime() - dStart.getTime()); } } else{ Iterator it = timeGaps.iterator(); while (it.hasNext()) { TimeGap tempTimeGap = (TimeGap) it.next(); if (tempTimeGap.getKey() == gapID){ String unit = tempTimeGap.getUnit(); int gapValue = tempTimeGap.getValue(); if (unit.equals(TimeGap.TIME_UNIT_MINUTE)) { gap = gapValue * TimeGap.MINUTE_IN_MILLIS; } else if (unit.equals(TimeGap.TIME_UNIT_HOUR)) { gap = gapValue * TimeGap.HOUR_IN_MILLIS; } else if (unit.equals(TimeGap.TIME_UNIT_DAY)) { gap = gapValue * TimeGap.DAY_IN_MILLIS; } else if (unit.equals(TimeGap.TIME_UNIT_WEEK)) { gap = gapValue * TimeGap.WEEK_IN_MILLIS; } else if (unit.equals(TimeGap.TIME_UNIT_MONTH)) { gap = gapValue * (TimeGap.DAY_IN_MILLIS *30); } else if (unit.equals(TimeGap.TIME_UNIT_YEAR)) { gap = gapValue * (TimeGap.DAY_IN_MILLIS *365); } break; } } } return gap; } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :