3

同じデータに 2 つの軸を持たせようとしています。

データは のカップルですDefaultTableXYDatasets。プロットは でXYPlot、2XYLineAndShapeRenderersと 1がありStackedXYAreaRenderer2ます。

すべてのデータは y 値のメートル単位であり、1 つの軸にメートルで表示し、1 つの軸にフィートで表示したいと考えています。今ではこれはよくあることのように感じますが、最も明白な方法を決めることはできません。機能する 1 つの方法は、データを複製して y 値をフィート単位で取得し、別の方法を追加NumberAxisしてそれで完了することです。

NumberAxisしかし、 をサブクラス化するか、何らかの機能を挿入NumberAxisして値をスケーリングする方が賢明だと思いました。または、最初のアプローチを使用する必要がありますか?

どう思いますか?

4

2 に答える 2

3

データの重複を避けるために、XYPlotメソッドmapDatasetToRangeAxes()を使用してデータセット インデックスを軸インデックスのリストにマッピングできます。以下の例では、metersが主軸であり、対応する軸の範囲は、ここfeetに示すように、それに応じてスケーリングされます。軸の変更に軸が確実にスケーリングされるようにする必要があることに注意してください。invokeLater()feetmeters

画像

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に示すように、 を使用してメートルとフィートの 2 つの系列を切り替えることができます。で利用可能な方法を使用して、2 番目の系列の線、形状、および凡例を非表示にすることができます。軸範囲を設定するには、シリーズ自体が表示されている必要があります。XYLineAndShapeRenderer

于 2012-11-13T14:46:32.487 に答える
3

最終的に私はこのソリューションに落ち着きました。これは最もエレガントではないかもしれませんが、うまくいきました。2 番目の軸があり、最初の軸feetAxisに を追加しました。変更により、範囲がオンに設定されます。AxisChangeListenermeterAxismeterAxisfeetAxis

そうSwingUtilities.invokeLaterしないと、チャートをズームアウトするときに範囲が正しくなくなり、 はfeetAxis0 から 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);
                }
           });
       }
   });
于 2012-11-13T15:19:03.973 に答える