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 :

http://dive4elements.wald.intevation.org