1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 package org.spf4j.perf.impl.chart;
33
34 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
35 import java.awt.Color;
36 import java.awt.Graphics;
37 import java.awt.image.BufferedImage;
38 import org.jfree.chart.ChartFactory;
39 import org.jfree.chart.JFreeChart;
40 import org.jfree.chart.axis.DateAxis;
41 import org.jfree.chart.axis.NumberAxis;
42 import org.jfree.chart.labels.StandardXYSeriesLabelGenerator;
43 import org.jfree.chart.plot.XYPlot;
44 import org.jfree.chart.renderer.PaintScale;
45 import org.jfree.chart.renderer.xy.XYBlockRenderer;
46 import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
47 import org.jfree.chart.title.PaintScaleLegend;
48 import org.jfree.data.time.FixedMillisecond;
49 import org.jfree.data.time.TimeSeries;
50 import org.jfree.data.time.TimeSeriesCollection;
51 import org.jfree.data.xy.XYDataset;
52 import org.spf4j.base.Arrays;
53 import org.spf4j.base.Pair;
54
55
56
57
58
59 public final class Charts {
60
61 private Charts() {
62 }
63
64 @SuppressFBWarnings("CE_CLASS_ENVY")
65 public static JFreeChart createHeatJFreeChart(final String[] dsNames, final double[][] values,
66 final long startTimeMillis, final long stepMillis, final String uom, final String chartName) {
67 final QuantizedXYZDatasetImpl dataSet = new QuantizedXYZDatasetImpl(dsNames, values,
68 startTimeMillis, stepMillis);
69 NumberAxis xAxis = new NumberAxis("Time");
70 xAxis.setStandardTickUnits(dataSet.createXTickUnits());
71 xAxis.setLowerMargin(0);
72 xAxis.setUpperMargin(0);
73 xAxis.setVerticalTickLabels(true);
74 NumberAxis yAxis = new NumberAxis(uom);
75 yAxis.setStandardTickUnits(dataSet.createYTickUnits());
76 yAxis.setLowerMargin(0);
77 yAxis.setUpperMargin(0);
78 XYBlockRenderer renderer = new XYBlockRenderer();
79 PaintScale scale;
80 if (dataSet.getMinValue() >= dataSet.getMaxValue()) {
81 if (dataSet.getMinValue() == Double.POSITIVE_INFINITY) {
82 scale = new InverseGrayScale(0, 1);
83 } else {
84 scale = new InverseGrayScale(dataSet.getMinValue(), dataSet.getMaxValue() + 1);
85 }
86 } else {
87 scale = new InverseGrayScale(dataSet.getMinValue(), dataSet.getMaxValue());
88 }
89 renderer.setPaintScale(scale);
90 renderer.setBlockWidth(1);
91 renderer.setBlockHeight(1);
92 XYPlot plot = new XYPlot(dataSet, xAxis, yAxis, renderer);
93 plot.setBackgroundPaint(Color.white);
94 plot.setDomainGridlinesVisible(false);
95 plot.setRangeGridlinesVisible(false);
96 plot.setRangeMinorGridlinesVisible(false);
97 JFreeChart chart = new JFreeChart(chartName, plot);
98 PaintScaleLegend legend = new PaintScaleLegend(scale, new NumberAxis("Count"));
99 legend.setMargin(0, 5, 0, 5);
100 chart.addSubtitle(legend);
101 chart.removeLegend();
102 chart.setBackgroundPaint(Color.white);
103 return chart;
104 }
105
106 private static JFreeChart createJFreeChart(final String chartName, final String uom,
107 final XYDataset timeseriescollection) {
108 JFreeChart jfreechart = ChartFactory.createTimeSeriesChart(chartName,
109 "Time", uom, timeseriescollection, true, true, false);
110 XYPlot xyplot = (XYPlot) jfreechart.getPlot();
111 DateAxis dateaxis = (DateAxis) xyplot.getDomainAxis();
112 dateaxis.setVerticalTickLabels(true);
113 XYLineAndShapeRenderer xylineandshaperenderer = (XYLineAndShapeRenderer) xyplot.getRenderer();
114 xylineandshaperenderer.setDefaultShapesVisible(true);
115 xylineandshaperenderer.setUseFillPaint(true);
116 xylineandshaperenderer.setLegendItemToolTipGenerator(new StandardXYSeriesLabelGenerator("Tooltip {0}"));
117 return jfreechart;
118 }
119
120 public static BufferedImage createMinMaxAvgCountImg(final String chartName, final long[] timestamps,
121 final double[] min, final double[] max, final double[] total, final double[] count,
122 final String uom, final int width, final int height) {
123
124 BufferedImage bi = Charts.createTimeSeriesJFreeChart(chartName, timestamps,
125 new String[]{"min", "max", "avg"}, uom,
126 new double[][]{min, max, Arrays.divide(total, count)}).createBufferedImage(width, height - height / 3);
127 BufferedImage bi2 = Charts.createTimeSeriesJFreeChart(null, timestamps,
128 new String[]{"count"}, "count", new double[][]{count}).createBufferedImage(width, height / 3);
129 BufferedImage combined = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
130 final Graphics graphics = combined.getGraphics();
131 try {
132 graphics.drawImage(bi, 0, 0, null);
133 graphics.drawImage(bi2, 0, height - height / 3, null);
134 } finally {
135 graphics.dispose();
136 }
137 return combined;
138 }
139
140 public static BufferedImage generateCountTotalChart(final String groupName, final long[][] timestamps,
141 final String[] measurementNames, final String uom1, final double[][] measurements, final int width,
142 final int height, final String[] measurementNames2, final String uom2, final double[][] measurements2) {
143 BufferedImage count = Charts.createTimeSeriesJFreeChart("Measurements for "
144 + groupName + " generated by spf4j",
145 timestamps, measurementNames, uom1, measurements).createBufferedImage(width, height / 2);
146 BufferedImage total = Charts.createTimeSeriesJFreeChart(null,
147 timestamps, measurementNames2, uom2, measurements2).createBufferedImage(width, height / 2);
148 BufferedImage combined = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
149 final Graphics graphics = combined.getGraphics();
150 try {
151 graphics.drawImage(count, 0, 0, null);
152 graphics.drawImage(total, 0, height / 2, null);
153 } finally {
154 graphics.dispose();
155 }
156 return combined;
157 }
158
159 private static TimeSeriesCollection createTimeSeriesCollection(final String[] measurementNames,
160 final long[] timestamps, final double[][] measurements) {
161 TimeSeriesCollection timeseriescollection = new TimeSeriesCollection();
162 for (int i = 0; i < measurementNames.length; i++) {
163 TimeSeries tseries = new TimeSeries(measurementNames[i]);
164 for (int j = 0; j < timestamps.length; j++) {
165 FixedMillisecond ts = new FixedMillisecond(timestamps[j]);
166 tseries.add(ts, measurements[i][j]);
167 }
168 timeseriescollection.addSeries(tseries);
169 }
170 return timeseriescollection;
171 }
172
173 public static JFreeChart createTimeSeriesJFreeChart(final String chartName, final long[] timestamps,
174 final String[] measurementNames, final String uom, final double[][] measurements) {
175 TimeSeriesCollection timeseriescollection
176 = createTimeSeriesCollection(measurementNames, timestamps, measurements);
177 return createJFreeChart(chartName, uom, timeseriescollection);
178 }
179
180 private static TimeSeriesCollection createTimeSeriesCollection(final String[] measurementNames,
181 final long[][] timestamps, final double[][] measurements) {
182 TimeSeriesCollection timeseriescollection = new TimeSeriesCollection();
183 for (int i = 0; i < measurementNames.length; i++) {
184 TimeSeries tseries = new TimeSeries(measurementNames[i]);
185 for (int j = 0; j < timestamps[i].length; j++) {
186 FixedMillisecond ts = new FixedMillisecond(timestamps[i][j]);
187 tseries.add(ts, measurements[i][j]);
188 }
189 timeseriescollection.addSeries(tseries);
190 }
191 return timeseriescollection;
192 }
193
194 public static JFreeChart createTimeSeriesJFreeChart(final String chartName, final long[][] timestamps,
195 final String[] measurementNames, final String uom, final double[][] measurements) {
196 TimeSeriesCollection timeseriescollection
197 = createTimeSeriesCollection(measurementNames, timestamps, measurements);
198 return createJFreeChart(chartName, uom, timeseriescollection);
199 }
200
201 public static Pair<long[], double[][]> fillGaps(final long[] timestamps,
202 final long[][] data, final int sampleTime, final int nrColumns) {
203 long startTime = timestamps[0];
204 int nrSamples = (int) ((timestamps[timestamps.length - 1] - startTime) / sampleTime) + 1;
205 long[] lts = new long[nrSamples];
206 double[][] dr = new double[nrSamples][];
207 long nextTime = startTime;
208 int j = 0;
209 int maxDeviation = sampleTime / 2;
210 double[] nodata = new double[nrColumns];
211 for (int i = 0; i < nrColumns; i++) {
212 nodata[i] = Double.NaN;
213 }
214 for (int i = 0; i < nrSamples; i++) {
215 lts[i] = nextTime;
216
217 if (Math.abs(timestamps[j] - nextTime) < maxDeviation) {
218 dr[i] = Arrays.toDoubleArray(data[j]);
219 j++;
220 } else {
221 dr[i] = nodata;
222 }
223 nextTime += sampleTime;
224 }
225 return Pair.of(lts, dr);
226 }
227
228 }