Mercurial > dive4elements > gnv-client
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 : |