1 package nl.tudelft.simulation.dsol.swing.charts.histogram;
2
3 import java.awt.Color;
4 import java.awt.Graphics2D;
5 import java.awt.geom.Rectangle2D;
6 import java.text.DecimalFormatSymbols;
7 import java.text.NumberFormat;
8
9 import org.jfree.chart.axis.AxisSpace;
10 import org.jfree.chart.axis.AxisState;
11 import org.jfree.chart.axis.NumberAxis;
12 import org.jfree.chart.plot.Plot;
13 import org.jfree.chart.plot.PlotRenderingInfo;
14 import org.jfree.chart.plot.XYPlot;
15 import org.jfree.chart.ui.RectangleEdge;
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33 public class HistogramDomainAxis extends NumberAxis
34 {
35
36 private static final long serialVersionUID = 1L;
37
38
39 protected String[] labels = null;
40
41
42 protected double maxLabelHeight = -1;
43
44
45
46
47
48
49
50
51 public HistogramDomainAxis(final XYPlot parent, final String label, final double[] domain, final int numberOfBins)
52 {
53 super(label);
54 this.setAutoRange(false);
55 double binWidth = (domain[1] - domain[0]) / numberOfBins * 1.0;
56 this.setLowerBound(domain[0] - binWidth);
57 this.setUpperBound(domain[1] + binWidth);
58 this.setVerticalTickLabels(true);
59
60 this.setLabelFont(parent.getRangeAxis().getLabelFont());
61 this.setTickLabelFont(parent.getRangeAxis().getTickLabelFont());
62 this.labels = this.createLabels(domain, numberOfBins);
63 }
64
65
66 @Override
67 public double valueToJava2D(final double value, final Rectangle2D dataArea, final RectangleEdge edge)
68 {
69 double ratio = (value - this.getLowerBound()) / (this.getUpperBound() - this.getLowerBound());
70 return dataArea.getX() + ratio * (dataArea.getWidth());
71 }
72
73
74 @Override
75 public double java2DToValue(final double value, final Rectangle2D dataArea, final RectangleEdge edge)
76 {
77 double ratio = (value - dataArea.getX()) / dataArea.getWidth();
78 return this.getLowerBound() + ratio * (this.getUpperBound() - this.getLowerBound());
79 }
80
81
82 @Override
83 public AxisSpace reserveSpace(final Graphics2D g2, final Plot dataPlot, final Rectangle2D dataArea,
84 final RectangleEdge edge, final AxisSpace axisSpace)
85 {
86 if (this.maxLabelHeight == -1)
87 {
88 g2.setFont(this.getTickLabelFont());
89
90 for (int i = 0; i < this.labels.length; i++)
91 {
92
93 double height = g2.getFont().getStringBounds(this.labels[i], g2.getFontRenderContext()).getWidth();
94 if (height > this.maxLabelHeight)
95 {
96 this.maxLabelHeight = height + 3;
97 }
98 }
99 }
100 AxisSpace result = new AxisSpace();
101 result.add(this.maxLabelHeight, RectangleEdge.BOTTOM);
102 return result;
103 }
104
105
106
107
108
109
110
111 private String[] createLabels(final double[] domain, final int numberOfBins)
112 {
113 String[] result = new String[numberOfBins + 2];
114 NumberFormat formatter = NumberFormat.getInstance();
115 formatter.setMaximumFractionDigits(2);
116 double binWidth = (domain[1] - domain[0]) / numberOfBins * 1.0;
117 double start = domain[0];
118 for (int i = 1; i < numberOfBins + 1; i++)
119 {
120 result[i] = formatter.format(start);
121 start = start + binWidth;
122 }
123
124 DecimalFormatSymbols symbols = new DecimalFormatSymbols();
125 result[0] = "-" + symbols.getInfinity();
126 result[numberOfBins + 1] = symbols.getInfinity();
127 return result;
128 }
129
130
131 @Override
132 public AxisState draw(final Graphics2D g2, final double cursor, final Rectangle2D plotArea, final Rectangle2D dataArea,
133 final RectangleEdge edge, final PlotRenderingInfo arg5)
134 {
135 g2.setColor(Color.BLACK);
136 g2.setFont(this.getTickLabelFont());
137 double labelWidth = g2.getFont().getStringBounds(this.labels[0], g2.getFontRenderContext()).getHeight();
138 double width = dataArea.getWidth() / (this.labels.length) * 1.0;
139 double x = dataArea.getX() + 0.5 * width;
140 double y = dataArea.getY() + dataArea.getHeight();
141 g2.translate(x, y);
142 g2.rotate(-Math.PI / 2.0);
143 double offset = 0.0;
144 for (int i = 0; i < this.labels.length; i++)
145 {
146 double labelHeight = g2.getFont().getStringBounds(this.labels[i], g2.getFontRenderContext()).getWidth() + 3;
147 g2.drawString(this.labels[i], Math.round(-labelHeight), Math.round(offset + 0.33 * labelWidth));
148 offset = offset + width;
149 }
150 g2.rotate(Math.PI / 2.0);
151 g2.translate(-x, -y);
152 return new AxisState();
153 }
154 }