comparison gnv-artifacts/src/main/java/de/intevation/gnv/chart/TimeSeriesChart.java @ 376:d8f3ef441bf2

merged gnv-artifacts/0.3
author Thomas Arendsen Hein <thomas@intevation.de>
date Fri, 28 Sep 2012 12:13:47 +0200
parents 2413273f1c13
children f14c5d1b5b71
comparison
equal deleted inserted replaced
293:6b0ef2324d02 376:d8f3ef441bf2
1 package de.intevation.gnv.chart;
2
3 import java.text.DateFormat;
4 import java.text.SimpleDateFormat;
5 import java.util.Collection;
6 import java.util.Date;
7 import java.util.HashMap;
8 import java.util.Iterator;
9 import java.util.Locale;
10
11 import org.apache.log4j.Logger;
12
13 import org.jfree.chart.ChartTheme;
14 import org.jfree.chart.ChartFactory;
15 import org.jfree.chart.axis.Axis;
16 import org.jfree.chart.axis.DateAxis;
17 import org.jfree.chart.plot.XYPlot;
18 import org.jfree.chart.plot.PlotOrientation;
19 import org.jfree.data.general.Series;
20 import org.jfree.data.time.TimeSeries;
21 import org.jfree.data.time.Minute;
22 import org.jfree.data.time.TimeSeriesCollection;
23
24 import de.intevation.gnv.artifacts.ressource.RessourceFactory;
25 import de.intevation.gnv.geobackend.base.Result;
26 import de.intevation.gnv.state.describedata.KeyValueDescibeData;
27 import de.intevation.gnv.timeseries.gap.TimeGap;
28
29
30 /**
31 * @author Ingo Weinzierl <ingo.weinzierl@intevation.de>
32 */
33 public class TimeSeriesChart
34 extends AbstractXYLineChart
35 {
36
37 private static final String DATE_FORMAT = "chart.timeseries.date.format";
38
39 public static final String DEFAULT_DATE_FORMAT = "dd-MMM-yyyy";
40
41 private static final long NO_TIME_GAP = Long.MAX_VALUE - 1000;
42
43 private static Logger log = Logger.getLogger(TimeSeriesChart.class);
44
45
46 public TimeSeriesChart(
47 ChartLabels labels,
48 ChartTheme theme,
49 Collection parameters,
50 Collection measurements,
51 Collection dates,
52 Collection result,
53 Collection timeGaps,
54 Locale locale,
55 boolean linesVisible,
56 boolean shapesVisible
57 ) {
58 this.labels = labels;
59 this.theme = theme;
60 this.parameters = parameters;
61 this.measurements = measurements;
62 this.dates = dates;
63 this.resultSet = result;
64 this.timeGaps = timeGaps;
65 this.locale = locale;
66 this.PLOT_ORIENTATION = PlotOrientation.VERTICAL;
67 this.linesVisible = linesVisible;
68 this.shapesVisible = shapesVisible;
69 this.datasets = new HashMap();
70 this.ranges = new HashMap();
71 }
72
73
74 protected void initChart() {
75 chart = ChartFactory.createTimeSeriesChart(
76 labels.getTitle(),
77 labels.getDomainAxisLabel(),
78 null,
79 null,
80 true,
81 false,
82 false
83 );
84 }
85
86
87 protected void initData() {
88 log.debug("init data for timeseries chart");
89
90 String breakPoint1 = null;
91 String breakPoint2 = null;
92 String breakPoint3 = null;
93
94 Iterator iter = resultSet.iterator();
95 Result row = null;
96 String seriesName = null;
97 String parameter = null;
98 TimeSeries series = null;
99
100 int idx = 0;
101 int startPos = 0;
102 int endPos = 0;
103 Date startDate = null;
104 Date endDate = null;
105
106 Result[] results =
107 (Result[]) resultSet.toArray(new Result[resultSet.size()]);
108
109 while (iter.hasNext()) {
110 row = (Result) iter.next();
111
112 // add current data to plot and prepare for next one
113 if (!row.getString("GROUP1").equals(breakPoint1) ||
114 !row.getString("GROUP2").equals(breakPoint2) ||
115 !row.getString("GROUP3").equals(breakPoint3)
116 ) {
117 log.debug("prepare data/plot for next dataset");
118
119 if(series != null) {
120 // add gaps before adding series to chart
121 startDate = results[startPos].getDate("XORDINATE");
122 endDate = results[endPos-1].getDate("XORDINATE");
123 addGaps(results,series,startDate,endDate,startPos,endPos);
124 addSeries(series, parameter, idx);
125
126 startPos = endPos + 1;
127 }
128
129 // prepare variables for next plot
130 breakPoint1 = row.getString("GROUP1");
131 breakPoint2 = row.getString("GROUP2");
132 breakPoint3 = row.getString("GROUP3");
133
134 seriesName = createSeriesName(
135 breakPoint1,
136 breakPoint2,
137 breakPoint3
138 );
139 parameter = findParameter(seriesName);
140
141 log.debug("next dataset is '" + seriesName + "'");
142 series = new TimeSeries(seriesName, Minute.class);
143 }
144
145 addValue(row, series);
146 storeMaxRange(row.getDouble("YORDINATE"), parameter);
147 endPos++;
148 }
149
150 // add the last dataset if existing to plot and prepare its axis
151 startDate = results[startPos].getDate("XORDINATE");
152 endDate = results[endPos-1].getDate("XORDINATE");
153 addGaps(results, series, startDate, endDate, startPos, endPos);
154 addSeries(series, parameter, idx);
155
156 addDatasets();
157 }
158
159
160 protected void addValue(Result row, Series series) {
161 ((TimeSeries) series).addOrUpdate(
162 new Minute(row.getDate("XORDINATE")),
163 row.getDouble("YORDINATE")
164 );
165 }
166
167
168 protected void addSeries(Series series, String parameter, int idx) {
169 log.debug("add series (" + parameter + ")to timeseries chart");
170
171 if (series == null) {
172 log.warn("no data to add");
173 return;
174 }
175
176 TimeSeriesCollection tsc = null;
177
178 if (datasets.containsKey(parameter))
179 tsc = (TimeSeriesCollection) datasets.get(parameter);
180 else
181 tsc = new TimeSeriesCollection();
182
183 tsc.addSeries((TimeSeries) series);
184 datasets.put(parameter, tsc);
185 }
186
187
188 protected void addDatasets() {
189 Iterator iter = parameters.iterator();
190 XYPlot plot = chart.getXYPlot();
191 int idx = 0;
192
193 TimeSeriesCollection tsc = null;
194 KeyValueDescibeData data = null;
195 String key = null;
196 while (iter.hasNext()) {
197 data = (KeyValueDescibeData) iter.next();
198 key = data.getValue();
199
200 if (datasets.containsKey(key)) {
201 tsc = (TimeSeriesCollection)datasets.get(key);
202 plot.setDataset(idx, tsc );
203 log.debug("Added " + key + " parameter to plot.");
204 prepareAxis(key, idx);
205 adjustRenderer(
206 idx++,
207 tsc.getSeriesCount(),
208 linesVisible,
209 shapesVisible
210 );
211 }
212 }
213 }
214
215
216 protected void localizeDomainAxis(Axis axis, Locale locale) {
217 if (locale == null)
218 return;
219
220 log.debug(
221 "Set language of axis [" + axis.getLabel() + "] " +
222 "to " + locale.toString()
223 );
224
225 String dateFormat = getMessage(locale, DATE_FORMAT,DEFAULT_DATE_FORMAT);
226 DateFormat format = new SimpleDateFormat(dateFormat, locale);
227 ((DateAxis) axis).setDateFormatOverride(format);
228 }
229
230
231 protected String getMessage(Locale locale, String key, String def) {
232 return RessourceFactory.getInstance().getRessource(locale, key, def);
233 }
234
235
236 protected String createSeriesName(
237 String breakPoint1,
238 String breakPoint2,
239 String breakPoint3
240 ) {
241 log.debug("create seriesname of timeseries chart");
242 return findValueTitle(parameters, breakPoint1) +
243 " " +
244 findValueTitle(measurements, breakPoint2) +
245 "m";
246 }
247
248
249 protected void addGaps(
250 Result[] results,
251 Series series,
252 Date startDate,
253 Date endDate,
254 int startPos,
255 int endPos
256 ) {
257 int gapID = results[startPos].getInteger("GAPID");
258 long maxDiff = calculateGapSize(
259 startDate, endDate, startPos, endPos, gapID
260 );
261
262 Date last = startDate;
263 for (int i = startPos+1; i < endPos; i++) {
264 Result res = results[i];
265 Date now = res.getDate("XORDINATE");
266
267 if ((now.getTime() - last.getTime()) > maxDiff) {
268 // add gap, add 1 minute to last date and add null value
269 log.info(
270 "Gap between " +
271 last.toString() + " and " + now.toString()
272 );
273 last.setTime(last.getTime() + 60000);
274 ((TimeSeries) series).addOrUpdate(new Minute(last), null);
275 }
276
277 last = now;
278 }
279 }
280
281
282 protected long calculateGapSize(
283 Date start,
284 Date end,
285 int startPos,
286 int endPos,
287 int gapID
288 ){
289 long maxGap = (end.getTime() - start.getTime()) / 20;
290 long interval = getTimeGapValue(start, end, startPos, endPos, gapID);
291
292 if (maxGap < interval)
293 maxGap = interval + 10;
294
295 return maxGap;
296 }
297
298
299 protected long getTimeGapValue(
300 Date dStart,
301 Date dEnd,
302 int pStart,
303 int pEnd,
304 int gapID
305 ){
306 long gap = 0;
307
308 if (gapID < 0 || gapID >= 99) {
309
310 if (gapID == -1) {
311 // no gaps in meshes
312 gap = NO_TIME_GAP;
313 }
314 else if (pEnd-pStart < 60) {
315 gap = (3/(pEnd-pStart)) * (dEnd.getTime() - dStart.getTime());
316 }
317 }
318 else{
319 Iterator it = timeGaps.iterator();
320
321 while (it.hasNext()) {
322 TimeGap tempTimeGap = (TimeGap) it.next();
323
324 if (tempTimeGap.getKey() == gapID){
325 String unit = tempTimeGap.getUnit();
326 int gapValue = tempTimeGap.getValue();
327
328 if (unit.equals(TimeGap.TIME_UNIT_MINUTE)) {
329 gap = gapValue * TimeGap.MINUTE_IN_MILLIS;
330 }
331 else if (unit.equals(TimeGap.TIME_UNIT_HOUR)) {
332 gap = gapValue * TimeGap.HOUR_IN_MILLIS;
333 }
334 else if (unit.equals(TimeGap.TIME_UNIT_DAY)) {
335 gap = gapValue * TimeGap.DAY_IN_MILLIS;
336 }
337 else if (unit.equals(TimeGap.TIME_UNIT_WEEK)) {
338 gap = gapValue * TimeGap.WEEK_IN_MILLIS;
339 }
340 else if (unit.equals(TimeGap.TIME_UNIT_MONTH)) {
341 gap = gapValue * (TimeGap.DAY_IN_MILLIS *30);
342 }
343 else if (unit.equals(TimeGap.TIME_UNIT_YEAR)) {
344 gap = gapValue * (TimeGap.DAY_IN_MILLIS *365);
345 }
346 break;
347 }
348 }
349 }
350
351 return gap;
352 }
353 }
354 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :

http://dive4elements.wald.intevation.org