Mercurial > dive4elements > gnv-client
view gnv-artifacts/src/main/java/de/intevation/gnv/chart/TimeSeriesChart.java @ 593:b248531fa20b
Added experimental support for extrapolation in "Horizontalschnitte"
gnv-artifacts/trunk@648 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author | Sascha L. Teichmann <sascha.teichmann@intevation.de> |
---|---|
date | Sun, 31 Jan 2010 21:50:15 +0000 |
parents | 4cbcc130cffc |
children | 83f8f98a4f11 |
line wrap: on
line source
package de.intevation.gnv.chart; import de.intevation.gnv.artifacts.ressource.RessourceFactory; import de.intevation.gnv.geobackend.base.Result; import de.intevation.gnv.state.describedata.KeyValueDescibeData; import de.intevation.gnv.timeseries.gap.TimeGap; 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 java.util.TimeZone; import org.apache.log4j.Logger; import org.jfree.chart.ChartFactory; import org.jfree.chart.ChartTheme; import org.jfree.chart.axis.Axis; import org.jfree.chart.axis.DateAxis; import org.jfree.chart.axis.DateTickUnit; import org.jfree.chart.axis.DateTickUnitType; import org.jfree.chart.axis.TickUnits; import org.jfree.chart.axis.TickUnitSource; import org.jfree.chart.axis.ValueAxis; import org.jfree.chart.plot.PlotOrientation; import org.jfree.chart.plot.XYPlot; import org.jfree.data.general.Series; import org.jfree.data.time.Minute; import org.jfree.data.time.TimeSeries; import org.jfree.data.time.TimeSeriesCollection; /** * @author Ingo Weinzierl (ingo.weinzierl@intevation.de) */ public class TimeSeriesChart extends AbstractXYLineChart { private static final String DATE_FORMAT = "chart.timeseries.date.format"; public static final String DEFAULT_DATE_FORMAT = "dd-MMM-yyyy"; 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(); this.ranges = new HashMap(); } protected void initChart() { chart = ChartFactory.createTimeSeriesChart( labels.getTitle(), labels.getDomainAxisLabel(), null, null, true, false, false ); XYPlot plot = (XYPlot) chart.getPlot(); plot.setDomainAxis(0, new DateAxis( labels.getDomainAxisLabel(), TimeZone.getDefault(), locale)); } 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; String parameter = 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, parameter, 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 ); parameter = findParameter(seriesName); log.debug("next dataset is '" + seriesName + "'"); series = new TimeSeries(seriesName, Minute.class); } addValue(row, series); storeMaxRange(row.getDouble("YORDINATE"), parameter); endPos++; } if (startPos < results.length && endPos-1 < results.length) { // 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, parameter, 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 parameter, int idx) { log.debug("add series (" + parameter + ")to timeseries chart"); if (series == null) { log.warn("no data to add"); return; } TimeSeriesCollection tsc = null; 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) { ((ValueAxis)axis).setStandardTickUnits(createStandardDateTickUnits( TimeZone.getDefault(), locale)); } public static TickUnitSource createStandardDateTickUnits( TimeZone zone, Locale locale) { /* * This method have been copied from JFreeChart's DateAxis class. * DateFormat objects are hard coded in DateAxis and cannot be adjusted. */ if (zone == null) { throw new IllegalArgumentException("Null 'zone' argument."); } if (locale == null) { throw new IllegalArgumentException("Null 'locale' argument."); } TickUnits units = new TickUnits(); // date formatters DateFormat f1 = new SimpleDateFormat("HH:mm:ss.SSS", locale); DateFormat f2 = new SimpleDateFormat("HH:mm:ss", locale); DateFormat f3 = new SimpleDateFormat("HH:mm", locale); DateFormat f4 = new SimpleDateFormat("d-MMM, HH:mm", locale); DateFormat f5 = new SimpleDateFormat("d-MMM yyyy", locale); DateFormat f6 = new SimpleDateFormat("MMM-yyyy", locale); DateFormat f7 = new SimpleDateFormat("yyyy", locale); f1.setTimeZone(zone); f2.setTimeZone(zone); f3.setTimeZone(zone); f4.setTimeZone(zone); f5.setTimeZone(zone); f6.setTimeZone(zone); f7.setTimeZone(zone); // milliseconds units.add(new DateTickUnit(DateTickUnitType.MILLISECOND, 1, f1)); units.add(new DateTickUnit(DateTickUnitType.MILLISECOND, 5, DateTickUnitType.MILLISECOND, 1, f1)); units.add(new DateTickUnit(DateTickUnitType.MILLISECOND, 10, DateTickUnitType.MILLISECOND, 1, f1)); units.add(new DateTickUnit(DateTickUnitType.MILLISECOND, 25, DateTickUnitType.MILLISECOND, 5, f1)); units.add(new DateTickUnit(DateTickUnitType.MILLISECOND, 50, DateTickUnitType.MILLISECOND, 10, f1)); units.add(new DateTickUnit(DateTickUnitType.MILLISECOND, 100, DateTickUnitType.MILLISECOND, 10, f1)); units.add(new DateTickUnit(DateTickUnitType.MILLISECOND, 250, DateTickUnitType.MILLISECOND, 10, f1)); units.add(new DateTickUnit(DateTickUnitType.MILLISECOND, 500, DateTickUnitType.MILLISECOND, 50, f1)); // seconds units.add(new DateTickUnit(DateTickUnitType.SECOND, 1, DateTickUnitType.MILLISECOND, 50, f2)); units.add(new DateTickUnit(DateTickUnitType.SECOND, 5, DateTickUnitType.SECOND, 1, f2)); units.add(new DateTickUnit(DateTickUnitType.SECOND, 10, DateTickUnitType.SECOND, 1, f2)); units.add(new DateTickUnit(DateTickUnitType.SECOND, 30, DateTickUnitType.SECOND, 5, f2)); // minutes units.add(new DateTickUnit(DateTickUnitType.MINUTE, 1, DateTickUnitType.SECOND, 5, f3)); units.add(new DateTickUnit(DateTickUnitType.MINUTE, 2, DateTickUnitType.SECOND, 10, f3)); units.add(new DateTickUnit(DateTickUnitType.MINUTE, 5, DateTickUnitType.MINUTE, 1, f3)); units.add(new DateTickUnit(DateTickUnitType.MINUTE, 10, DateTickUnitType.MINUTE, 1, f3)); units.add(new DateTickUnit(DateTickUnitType.MINUTE, 15, DateTickUnitType.MINUTE, 5, f3)); units.add(new DateTickUnit(DateTickUnitType.MINUTE, 20, DateTickUnitType.MINUTE, 5, f3)); units.add(new DateTickUnit(DateTickUnitType.MINUTE, 30, DateTickUnitType.MINUTE, 5, f3)); // hours units.add(new DateTickUnit(DateTickUnitType.HOUR, 1, DateTickUnitType.MINUTE, 5, f3)); units.add(new DateTickUnit(DateTickUnitType.HOUR, 2, DateTickUnitType.MINUTE, 10, f3)); units.add(new DateTickUnit(DateTickUnitType.HOUR, 4, DateTickUnitType.MINUTE, 30, f3)); units.add(new DateTickUnit(DateTickUnitType.HOUR, 6, DateTickUnitType.HOUR, 1, f3)); units.add(new DateTickUnit(DateTickUnitType.HOUR, 12, DateTickUnitType.HOUR, 1, f4)); // days units.add(new DateTickUnit(DateTickUnitType.DAY, 1, DateTickUnitType.HOUR, 1, f5)); units.add(new DateTickUnit(DateTickUnitType.DAY, 2, DateTickUnitType.HOUR, 1, f5)); units.add(new DateTickUnit(DateTickUnitType.DAY, 7, DateTickUnitType.DAY, 1, f5)); units.add(new DateTickUnit(DateTickUnitType.DAY, 15, DateTickUnitType.DAY, 1, f5)); // months units.add(new DateTickUnit(DateTickUnitType.MONTH, 1, DateTickUnitType.DAY, 1, f6)); units.add(new DateTickUnit(DateTickUnitType.MONTH, 2, DateTickUnitType.DAY, 1, f6)); units.add(new DateTickUnit(DateTickUnitType.MONTH, 3, DateTickUnitType.MONTH, 1, f6)); units.add(new DateTickUnit(DateTickUnitType.MONTH, 4, DateTickUnitType.MONTH, 1, f6)); units.add(new DateTickUnit(DateTickUnitType.MONTH, 6, DateTickUnitType.MONTH, 1, f6)); // years units.add(new DateTickUnit(DateTickUnitType.YEAR, 1, DateTickUnitType.MONTH, 1, f7)); units.add(new DateTickUnit(DateTickUnitType.YEAR, 2, DateTickUnitType.MONTH, 3, f7)); units.add(new DateTickUnit(DateTickUnitType.YEAR, 5, DateTickUnitType.YEAR, 1, f7)); units.add(new DateTickUnit(DateTickUnitType.YEAR, 10, DateTickUnitType.YEAR, 1, f7)); units.add(new DateTickUnit(DateTickUnitType.YEAR, 25, DateTickUnitType.YEAR, 5, f7)); units.add(new DateTickUnit(DateTickUnitType.YEAR, 50, DateTickUnitType.YEAR, 10, f7)); units.add(new DateTickUnit(DateTickUnitType.YEAR, 100, DateTickUnitType.YEAR, 20, f7)); return units; } protected String getMessage(Locale locale, String key, String def) { return RessourceFactory.getInstance().getRessource(locale, key, def); } 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 :