我正在尝试在同一数据上有两个轴。
数据是DefaultTableXYDatasets
的几个。情节为XYPlot
,我有两个XYLineAndShapeRenderers
和一个StackedXYAreaRenderer2
。
y值的所有数据都以米为单位,我想让一个轴以米为单位显示,一个轴以英尺显示。现在这感觉像是常见的事情,但我无法决定最明显的方法。一种方法是复制数据并使y值以英尺为单位,然后添加另一个NumberAxis
并完成它。
但我认为继承NumberAxis
更为明智,或者在NumberAxis
中注入一些功能来扩展值。或者我应该采用第一种方法?
答案 0 :(得分:2)
最终我决定使用这个解决方案,它可能不是最优雅但它有效。我有第二个轴feetAxis
,并在名为AxisChangeListener
的第一个轴上添加了meterAxis
。当meterAxis
更改设置feetAxis
上的范围时。
我使用SwingUtilities.invokeLater
,否则当缩小图表时范围会不正确,那么feetAxis
只会从0变为1.不检查原因。
feetAxis = new NumberAxis("Height [ft]");
metersAxis = new NumberAxis("Height [m]");
pathPlot.setRangeAxis(0, metersAxis);
pathPlot.setRangeAxis(1, feetAxis);
metersAxis.addChangeListener(new AxisChangeListener() {
@Override
public void axisChanged(AxisChangeEvent event) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
feetAxis.setRange(metersAxis.getLowerBound() * MetersToFeet, metersAxis.getUpperBound() * MetersToFeet);
}
});
}
});
答案 1 :(得分:1)
为避免重复数据,您可以使用XYPlot
方法mapDatasetToRangeAxes()
将数据集索引映射到轴索引列表。在下面的示例中,meters
是主轴,相应的feet
轴的范围也相应缩放,如here所示。请注意,invokeLater()
轴需要{/ 1}}才能确保feet
轴在 meters
轴上的任何更改后缩放
import java.awt.EventQueue;
import java.util.Arrays;
import java.util.List;
import javax.swing.JFrame;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.AxisLocation;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.event.AxisChangeEvent;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYItemRenderer;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.data.xy.XYDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
/**
* @see https://stackoverflow.com/q/13358758/230513
*/
public class AxisTest {
private static final int N = 5;
private static final double FEET_PER_METER = 3.28084;
private static XYDataset createDataset() {
XYSeriesCollection data = new XYSeriesCollection();
final XYSeries series = new XYSeries("Data");
for (int i = -N; i < N * N; i++) {
series.add(i, i);
}
data.addSeries(series);
return data;
}
private JFreeChart createChart(XYDataset dataset) {
NumberAxis meters = new NumberAxis("Meters");
NumberAxis feet = new NumberAxis("Feet");
ValueAxis domain = new NumberAxis();
XYItemRenderer renderer = new XYLineAndShapeRenderer();
XYPlot plot = new XYPlot(dataset, domain, meters, renderer);
plot.setRangeAxis(1, feet);
plot.setRangeAxisLocation(1, AxisLocation.BOTTOM_OR_LEFT);
List<Integer> axes = Arrays.asList(0, 1);
plot.mapDatasetToRangeAxes(0, axes);
scaleRange(feet, meters);
meters.addChangeListener((AxisChangeEvent event) -> {
EventQueue.invokeLater(() -> {
scaleRange(feet, meters);
});
});
JFreeChart chart = new JFreeChart("Axis Test",
JFreeChart.DEFAULT_TITLE_FONT, plot, true);
return chart;
}
private void scaleRange(NumberAxis feet, NumberAxis meters) {
feet.setRange(meters.getLowerBound() * FEET_PER_METER,
meters.getUpperBound() * FEET_PER_METER);
}
private void display() {
JFrame f = new JFrame("AxisTest");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new ChartPanel(createChart(createDataset())));
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
new AxisTest().display();
});
}
}
或者,您可以使用JCheckBox
在两个系列之间翻转,米和米脚,如相关的example所示。使用XYLineAndShapeRenderer
可用的方法,您可以隐藏第二个系列的线条,形状和图例。系列本身必须可见才能确定轴范围。