同一数据上有多个轴

我试图在同一数据上有两个轴。

数据是几个DefaultTableXYDatasets 。 该图是一个XYPlot ,我有两个XYLineAndShapeRenderers和一个StackedXYAreaRenderer2

所有数据都以米为单位表示y值,我希望有一个轴以米为单位显示,一个轴以英尺显示。 现在这感觉很常见,但我无法决定最明显的方法。 一种方法是复制数据并使y值以英尺为单位,然后添加另一个NumberAxis并完成它。

但我认为NumberAxis会更明智,或者在NumberAxis注入一些function来扩展值。 或者我应该采用第一种方法?

你怎么看?

最终我决定使用这个解决方案,它可能不是最优雅但它有效。 我有第二个轴feetAxis ,并在名为meterAxis的第一个轴上添加了一个meterAxis 。 当meterAxis更改时,设置meterAxis的范围。

我使用了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); } }); } }); 

为避免重复数据,可以使用XYPlot方法mapDatasetToRangeAxes()将数据集索引映射到轴索引列表。 在下面的示例中, meters是主轴,相应的feet轴的范围相应地缩放,如此处所示。 请注意,需要invokeLater()以确保在meters轴的任何更改缩放feet轴。

图片

 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 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在两个系列,米和英尺之间进行切换,如相关示例所示。 使用XYLineAndShapeRenderer可用的方法,您可以隐藏第二个系列的线条,形状和图例。 系列本身必须可见才能建立轴范围。