Mercurial > dive4elements > gnv-client
comparison gnv-artifacts/src/main/java/de/intevation/gnv/chart/DefaultHistogram.java @ 875:5e9efdda6894
merged gnv-artifacts/1.0
author | Thomas Arendsen Hein <thomas@intevation.de> |
---|---|
date | Fri, 28 Sep 2012 12:13:56 +0200 |
parents | 22c18083225e |
children | 8430269ec73b |
comparison
equal
deleted
inserted
replaced
722:bb3ffe7d719e | 875:5e9efdda6894 |
---|---|
1 package de.intevation.gnv.chart; | |
2 | |
3 import java.text.NumberFormat; | |
4 import java.text.ParseException; | |
5 | |
6 import java.util.Locale; | |
7 import java.util.Map; | |
8 | |
9 import org.apache.log4j.Logger; | |
10 | |
11 import org.jfree.chart.ChartTheme; | |
12 | |
13 import org.jfree.chart.plot.XYPlot; | |
14 | |
15 import org.jfree.data.statistics.HistogramDataset; | |
16 | |
17 /** | |
18 * Default implementation of {@link de.intevation.gnv.chart.AbstractHistogram}. | |
19 * | |
20 * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> | |
21 */ | |
22 public class DefaultHistogram | |
23 extends AbstractHistogram | |
24 { | |
25 /** | |
26 * Default bin count. | |
27 * TODO find a better default value | |
28 */ | |
29 public static final int DEFAULT_BINS = 15; | |
30 | |
31 /** | |
32 * Constant field for limitating the number of bin in a single histogram. | |
33 */ | |
34 public static final int MAXIMAL_BINS = 20; | |
35 | |
36 /** | |
37 * Default key to retrieve the number of bins from {@link | |
38 * #requestParameter}. | |
39 */ | |
40 public static final String REQUEST_KEY_BIN_COUNT = "bincount"; | |
41 | |
42 /** | |
43 * Default key to retrieve the width of a single bin from {@link | |
44 * #requestParameter}. | |
45 */ | |
46 public static final String REQUEST_KEY_BIN_WIDTH = "binwidth"; | |
47 | |
48 /** | |
49 * Default key to retrieve the chart width from {@link #requestParameter}. | |
50 */ | |
51 public static final String REQUEST_KEY_CHART_WIDTH = "width"; | |
52 | |
53 /** | |
54 * Default key to retrieve the <code>Locale</code> object from {@link | |
55 * #requestParameter} used for i18n support. | |
56 */ | |
57 public static final String REQUEST_KEY_LOCALE = "locale"; | |
58 | |
59 /** | |
60 * Default key to retrieve the object from {@link #requestParameter}. It | |
61 * defines which value this chart has to be used for bin calculation. You | |
62 * can either adjust the number of bins or the width of a single bin. | |
63 */ | |
64 public static final String REQUEST_KEY_BIN_CHOICE = "bintype"; | |
65 | |
66 /** | |
67 * Logger used for logging with log4j. | |
68 */ | |
69 private static Logger logger = Logger.getLogger(DefaultHistogram.class); | |
70 | |
71 /** | |
72 * Object storing some further parameter used for chart settings. | |
73 */ | |
74 protected Map requestParameter; | |
75 | |
76 | |
77 /** | |
78 * Constructor to create DefaultHistogram objects. | |
79 * | |
80 * @param labels Labels to decorate this chart. | |
81 * @param data Raw data to be displayed in histogram. | |
82 * @param theme Theme used to adjust the chart look. | |
83 * @param requestParameter Object which serves some further settings. | |
84 */ | |
85 public DefaultHistogram( | |
86 ChartLabels labels, Object[] data, ChartTheme theme, Map requestParameter | |
87 ) { | |
88 super(labels, data, theme); | |
89 this.requestParameter = requestParameter; | |
90 } | |
91 | |
92 | |
93 @Override | |
94 protected void applyDatasets() { | |
95 XYPlot plot = (XYPlot) chart.getPlot(); | |
96 | |
97 // prepare data and create add them to histogram dataset | |
98 String name = (String) data[0]; | |
99 double[] values = toDouble((Double[]) data[1]); | |
100 int bins = getBinCount(values); | |
101 | |
102 HistogramDataset dataset = new HistogramDataset(); | |
103 dataset.addSeries(name, values, bins); | |
104 | |
105 plot.setDataset(0, dataset); | |
106 } | |
107 | |
108 | |
109 /** | |
110 * Method which scans the hole bunch of values and returns an array with | |
111 * contains min and max value. Min value is stored at position 0, max value | |
112 * is stored at position 1 in that array. | |
113 * | |
114 * @param values Array which contains all values | |
115 * | |
116 * @return Array which contains min and max value | |
117 */ | |
118 protected double[] getMinMax(double[] values) { | |
119 double[] minmax = new double[2]; | |
120 minmax[0] = Double.MAX_VALUE; | |
121 minmax[1] = Double.MIN_VALUE; | |
122 | |
123 int length = values.length; | |
124 for (int i = 0; i < length; i++) { | |
125 minmax[0] = values[i] < minmax[0] ? values[i] : minmax[0]; | |
126 minmax[1] = values[i] > minmax[1] ? values[i] : minmax[1]; | |
127 } | |
128 | |
129 return minmax; | |
130 } | |
131 | |
132 | |
133 /** | |
134 * Turn a Double[] into a double[]. | |
135 * | |
136 * @param array Doube[] | |
137 * | |
138 * @return double[] | |
139 */ | |
140 protected double[] toDouble(Double[] array) { | |
141 int length = array.length; | |
142 double[] values = new double[length]; | |
143 | |
144 for(int i = 0; i < length; i++) { | |
145 values[i] = array[i].doubleValue(); | |
146 } | |
147 | |
148 return values; | |
149 } | |
150 | |
151 | |
152 /** | |
153 * Method to calculate the number of bins this chart should be parted into. | |
154 * The real calculation takes place in {@link #getBinCountByNumber} and | |
155 * {@link #getBinCountByWidth}. This method switches between these methods | |
156 * depending on the object stored in {@link #requestParameter}. | |
157 * | |
158 * @param values All values used in this histogram | |
159 * | |
160 * @return Number of bins | |
161 */ | |
162 protected int getBinCount(double[] values) { | |
163 String param = (String) requestParameter.get(REQUEST_KEY_BIN_CHOICE); | |
164 | |
165 if (param != null && param.equalsIgnoreCase(REQUEST_KEY_BIN_WIDTH)) { | |
166 return getBinCountByWidth(values); | |
167 } | |
168 else { | |
169 return getBinCountByNumber(); | |
170 } | |
171 } | |
172 | |
173 | |
174 /** | |
175 * Method to retrieve the number of bins. If {@link #requestParameter} | |
176 * contains a valid <code>Integer</code> at | |
177 * <code>REQUEST_KEY_BIN_COUNT</code> and this is smaller than or equal | |
178 * {@link #MAXIMAL_BINS}, this value is used. If no valid | |
179 * <code>Integer</code> is given or if the value in {@link #requestParameter} | |
180 * is bigger than {@link #MAXIMAL_BINS}, {@link #DEFAULT_BINS} is used. | |
181 * | |
182 * @return Number of bins | |
183 */ | |
184 protected int getBinCountByNumber() { | |
185 int bins = -1; | |
186 String param = (String) requestParameter.get(REQUEST_KEY_BIN_COUNT); | |
187 | |
188 try { | |
189 bins = Integer.parseInt(param); | |
190 bins = bins <= 0 ? DEFAULT_BINS : bins; | |
191 bins = bins > MAXIMAL_BINS ? MAXIMAL_BINS : bins; | |
192 | |
193 return bins; | |
194 } | |
195 catch (NumberFormatException nfe) { | |
196 logger.warn("Invalid number of bins for histogram chart: " + param); | |
197 logger.warn("Return default bins: " + DEFAULT_BINS); | |
198 | |
199 return DEFAULT_BINS; | |
200 } | |
201 } | |
202 | |
203 | |
204 /** | |
205 * Serves the number of bins depending on a given width for each bin, but | |
206 * maximum bin count is limited by {@link #MAXIMAL_BINS}. | |
207 * | |
208 * @param values All values in this histogram | |
209 * | |
210 * @return Number of bins | |
211 */ | |
212 protected int getBinCountByWidth(double[] values) { | |
213 int bins = -1; | |
214 String param = (String) requestParameter.get(REQUEST_KEY_BIN_WIDTH); | |
215 Locale locale = (Locale) requestParameter.get(REQUEST_KEY_LOCALE); | |
216 NumberFormat format = NumberFormat.getInstance(locale); | |
217 | |
218 try { | |
219 double[] minmax = getMinMax(values); | |
220 double totalWidth = minmax[1] - minmax[0]; | |
221 Number number = format.parse(param); | |
222 double binWidth = -1d; | |
223 | |
224 if (number instanceof Double) { | |
225 binWidth = ((Double) number).doubleValue(); | |
226 } | |
227 else if (number instanceof Long) { | |
228 binWidth = ((Long) number).doubleValue(); | |
229 } | |
230 else if (number instanceof Integer) { | |
231 binWidth = ((Integer) number).doubleValue(); | |
232 } | |
233 else { | |
234 logger.warn("Invalid bin width for histogram chart: " + param); | |
235 logger.warn("Return default bins: " + DEFAULT_BINS); | |
236 | |
237 return DEFAULT_BINS; | |
238 } | |
239 | |
240 double tmpBins = totalWidth / binWidth; | |
241 | |
242 bins = (int) Math.round(tmpBins); | |
243 bins = bins <= 0 ? DEFAULT_BINS : bins; | |
244 bins = bins > MAXIMAL_BINS ? MAXIMAL_BINS : bins; | |
245 | |
246 return bins; | |
247 } | |
248 catch (ParseException pe) { | |
249 logger.warn("Invalid bin width for histogram chart: " + param); | |
250 logger.warn("Return default bins: " + DEFAULT_BINS); | |
251 | |
252 return DEFAULT_BINS; | |
253 } | |
254 catch (NumberFormatException nfe) { | |
255 logger.warn("Invalid bin width for histogram chart: " + param); | |
256 logger.warn("Return default bins: " + DEFAULT_BINS); | |
257 | |
258 return DEFAULT_BINS; | |
259 } | |
260 } | |
261 } | |
262 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 : |