Search code examples
javaswinglayoutjfreechartjsplitpane

jfreechart each plot in JSplitPane


Has anyone implemented a CombinedXYPlot type of plot with each plot in a JSplitPane rather than all plots in one JPanel? This way one of the size dimensions of each plot could be modified without affecting the other plots (eg the CombinedXYPlotDemo4 if each plot was in a splitpane the vertical height of each plot could be manually adjusted by dragging the JSplitPane divider).

Example code is below:

import java.awt.Color;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.Panel;
import java.util.Random;

import javax.swing.JFrame;
import javax.swing.JSplitPane;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.axis.NumberTickUnit;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYItemRenderer;
import org.jfree.data.xy.XYDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;

public class SplitPaneCharts extends JFrame {

    private static final int dataPoints = 100;

    public SplitPaneCharts() {
        super();
        this.getContentPane().setLayout(new FlowLayout());
        Panel panel1 = new Panel();
        ChartPanel chartPanel1 = createDemoPanel("Chart1");
        panel1.add(chartPanel1);
        Panel panel2 = new Panel();
        ChartPanel chartPanel2 = createDemoPanel("Chart2");
        panel2.add(chartPanel2);
        XYPlot plot1 = chartPanel1.getChart().getXYPlot();
        XYPlot plot2 = chartPanel2.getChart().getXYPlot();
        plot2.setDomainAxis(plot1.getDomainAxis());
        JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, panel1, panel2);
        this.getContentPane().add(splitPane);

    }

    private ChartPanel createDemoPanel(String title) {
        JFreeChart jfreechart = ChartFactory.createXYLineChart(title, "X", "Y", createSampleData(),
            PlotOrientation.VERTICAL, true, true, false);
        XYPlot xyPlot = (XYPlot) jfreechart.getPlot();
        xyPlot.setDomainCrosshairVisible(true);
        xyPlot.setRangeCrosshairVisible(true);
        XYItemRenderer renderer = xyPlot.getRenderer();
        renderer.setSeriesPaint(0, Color.red);
        NumberAxis domain = (NumberAxis) xyPlot.getDomainAxis();
        domain.setRange(0.00, 1.00);
        domain.setTickUnit(new NumberTickUnit(0.2));
        domain.setVerticalTickLabels(true);
        NumberAxis range = (NumberAxis) xyPlot.getRangeAxis();
        range.setRange(0.0, 1.0);
        range.setTickUnit(new NumberTickUnit(0.2));
        return new ChartPanel(jfreechart);
    }

    private XYDataset createSampleData() {
        XYSeriesCollection xySeriesCollection = new XYSeriesCollection();
        XYSeries series = new XYSeries("Data");
        Random rand = new Random();
        for (int i = 0; i < dataPoints; i++) {
            double x = rand.nextDouble();
            double y = rand.nextDouble();
            series.add(x, y);
        }
        xySeriesCollection.addSeries(series);
        return xySeriesCollection;
    }

    public static void main(String args[]) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                SplitPaneCharts splitPaneCharts = new SplitPaneCharts();
                splitPaneCharts.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                splitPaneCharts.pack();
                splitPaneCharts.setLocationRelativeTo(null);
                splitPaneCharts.setVisible(true);
            }
        });
    }
}

Several problems I encounter:

1) The chart is not resized when the area of the Pane is made smaller than the plot.

2) The popup menu is sometimes hidden/does not appear on RMB after the JSplitPane divider has been moved.

3) Ideally I would like to have the X axis in a separate Pane of its own and just show the data in another two Panes (ie 3 x SplitPanes). This is proving difficult to work out how to implement - I looked into showing an XYPlot where I set the dataArea to a thin horizontal line- and hence just drawing the X Axis. But as to how best implement this I am not sure.


Solution

    1. To get the charts to resize with the frame, specify a layout that ignores the chart's preferred size, e.g. GridLayout and the frame's BorderLayout.CENTER; don't nest panels unnecessarily.

      ChartPanel chartPanel1 = createDemoPanel("Chart1");
      ChartPanel chartPanel2 = createDemoPanel("Chart2");
      XYPlot plot1 = chartPanel1.getChart().getXYPlot();
      XYPlot plot2 = chartPanel2.getChart().getXYPlot();
      plot2.setDomainAxis(plot1.getDomainAxis());
      chartPanel1.setLayout(new GridLayout());
      chartPanel2.setLayout(new GridLayout());
      JSplitPane splitPane = new JSplitPane(
          JSplitPane.VERTICAL_SPLIT, chartPanel1, chartPanel2);
      add(splitPane, BorderLayout.CENTER);
      
    2. The context menu seems to work with GridLayout.

    3. You might experiment with CombinedDomainXYPlot, illustrated here.