Java 同一数据上的多个轴

Java 同一数据上的多个轴,java,jfreechart,Java,Jfreechart,我试图在同一数据上有两个轴 数据是两个defaulttablexydataset。该绘图是一个XYPlot,我有两个xylineandshaperender和一个stackedxyarearender2 y值的所有数据都以米为单位,我希望一个轴以米为单位显示数据,另一个轴以英尺为单位显示数据。现在这感觉像是一件普通的事情,但我无法决定最明显的方式。一种有效的方法是复制数据并将y值以英尺为单位,然后添加另一个NumberAxis并使用它 但是我认为将NumberAxis子类化,或者在NumberA

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

数据是两个
defaulttablexydataset
。该绘图是一个
XYPlot
,我有两个
xylineandshaperender
和一个
stackedxyarearender2

y值的所有数据都以米为单位,我希望一个轴以米为单位显示数据,另一个轴以英尺为单位显示数据。现在这感觉像是一件普通的事情,但我无法决定最明显的方式。一种有效的方法是复制数据并将y值以英尺为单位,然后添加另一个
NumberAxis
并使用它

但是我认为将
NumberAxis
子类化,或者在
NumberAxis
中注入一些功能来缩放值会更明智。还是我应该采用第一种方法


你觉得怎么样

为了避免重复数据,可以使用
XYPlot
方法将数据集索引映射到轴索引列表。在下面的示例中,
是主轴,相应的
英尺
轴的范围将相应地缩放,如图所示。请注意,需要使用
invokeLater()
,以确保在
轴发生任何变化后,缩放
英尺

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();
        });
    }
}

导入java.awt.EventQueue;
导入java.util.array;
导入java.util.List;
导入javax.swing.JFrame;
导入org.jfree.chart.ChartPanel;
导入org.jfree.chart.JFreeChart;
导入org.jfree.chart.axis.AxisLocation;
导入org.jfree.chart.axis.NumberAxis;
导入org.jfree.chart.axis.ValueAxis;
导入org.jfree.chart.event.AxisChangeEvent;
导入org.jfree.chart.plot.XYPlot;
导入org.jfree.chart.renderer.xy.XYItemRenderer;
导入org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
导入org.jfree.data.xy.XYDataset;
导入org.jfree.data.xy.XYSeries;
导入org.jfree.data.xy.XYSeriesCollection;
/**
*@见https://stackoverflow.com/q/13358758/230513
*/
公共类测试{
专用静态最终整数N=5;
私人静态最终双英尺每米=3.28084;
私有静态XYDataset createDataset(){
XYSeriesCollection数据=新的XYSeriesCollection();
最终XYSeries=新XYSeries(“数据”);
for(int i=-N;i{
EventQueue.invokeLater(()->{
刻度(英尺、米);
});
});
JFreeChart图表=新JFreeChart(“轴测试”,
JFreeChart.DEFAULT\u TITLE\u字体、绘图、true);
收益表;
}
专用空隙标尺(数轴英尺,数轴米){
英尺.设置范围(米.getLowerBound()*每米英尺,
米。getUpperBound()*每米英尺);
}
专用void display(){
JFrame f=新JFrame(“AxisTest”);
f、 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f、 添加(新图表面板(createChart(createDataset())));
f、 包装();
f、 setLocationRelativeTo(空);
f、 setVisible(真);
}
公共静态void main(字符串[]args){
EventQueue.invokeLater(()->{
新建AxisTest().display();
});
}
}

或者,您可以使用
JCheckBox
在两个系列(米和英尺)之间翻转,如本节所示。使用XYLineAndShapeRenderer可用的方法,可以隐藏第二个系列的线条、形状和图例。系列本身必须是可见的,才能建立轴范围。

最终我决定使用这个解决方案,它可能不是最优雅的,但它确实有效。我有第二个轴
feetAxis
,并在第一个轴上添加了一个名为
meterAxis
AxisChangeListener
。当
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);
                }
           });
       }
   });

在您的问题中,用编程语言替换自然语言。一个更好的开始对话的方法是:)有很多多轴的例子。是的,但我没有看到任何一个多轴对一个数据集的例子。我可能弄错了,我会再检查一遍