Salvatorelab
Salvatorelab

Reputation: 11873

jFreeChart. height of subplots inside combined chart bug?

I'm using jFreeChart to display this kind of plot: chart example

Well, the problem is that when the program runs on a monitor with >800px height the dark shadows and the 45 dashed line are not painted correctly.

I've found that the problem is caused by a wrong value returned by:

chartPanel.getChartRenderingInfo().getPlotInfo().getSubplotInfo(0).getDataArea()

The dataArea is not correct, the height is wrong, and thus the shadows are not painted where expected. But this only happens when resizing the window above ~800px height.

I've managed to reproduce the error with a small SSCCE (jcommon and jfreechart needed):

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.geom.Rectangle2D;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;

import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.CombinedDomainXYPlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYItemRenderer;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.data.time.TimeSeriesCollection;
import org.jfree.ui.RectangleEdge;
import org.jfree.ui.RectangleInsets;

public class Window extends JFrame implements ComponentListener {
    private static final long serialVersionUID = 1L;
    private JPanel contentPane;
    private XYPlot subplotTop;
    private XYPlot subplotBottom;
    private CombinedDomainXYPlot plot;
    private JFreeChart chart;
    private ChartPanel chartPanel;
    private JLabel label;

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    Window frame = new Window();
                    frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    public Window() {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setBounds(100, 100, 700, 500);
        contentPane = new JPanel();
        contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
        contentPane.setLayout(new BorderLayout(0, 0));
        setContentPane(contentPane);

        JPanel example = new JPanel();
        label = new JLabel("Resize this window (do not use the \"maximize\" button");
        example.add( label );
        contentPane.add( example, BorderLayout.NORTH );

        createTopChart();
        createBottomChart();
        createCombinedChart();
        chartPanel = new ChartPanel(chart);
        this.add(chartPanel, BorderLayout.CENTER);

        //window resize listener
        this.addComponentListener(this);
    }

    private void createTopChart() {
        subplotTop = new XYPlot();
        subplotTop.setDomainPannable(true);
        subplotTop.setBackgroundPaint(Color.lightGray);
        subplotTop.setDomainGridlinePaint(Color.white);
        subplotTop.setRangeGridlinePaint(Color.white);

        XYItemRenderer renderer = new XYLineAndShapeRenderer(true, false);
        subplotTop.setRenderer(renderer);

        NumberAxis range = new NumberAxis("dBA");
        range.setRange(30, 120);
        range.setAutoRange(false);
        subplotTop.setRangeAxis(range);

        TimeSeriesCollection dataset_L = randomDataset(30,120);
        subplotTop.setDataset(dataset_L);
    }

    private void createBottomChart(){
        subplotBottom = new XYPlot();
        subplotBottom.setDomainPannable(true);
        subplotBottom.setBackgroundPaint(Color.lightGray);
        subplotBottom.setDomainGridlinePaint(Color.white);
        subplotBottom.setRangeGridlinePaint(Color.white);

        XYItemRenderer renderer = new XYLineAndShapeRenderer(true, false);
        subplotBottom.setRenderer(renderer);

        NumberAxis range = new NumberAxis("%");
        range.setRange(-10, 100);
        range.setAutoRange(false);
        subplotBottom.setRangeAxis(range);

        TimeSeriesCollection dataset_P = randomDataset(0,100);
        subplotBottom.setDataset(dataset_P);
    }

    private void createCombinedChart() {    
        plot = new CombinedDomainXYPlot();
        plot.setGap(30);
        plot.add(subplotTop, 4);
        plot.add(subplotBottom, 1);
        plot.setOrientation(PlotOrientation.VERTICAL);

        chart = new JFreeChart("Title", new Font("Arial", Font.BOLD, 18), plot, true);
        chart.getLegend().setVisible(false);
        chart.getLegend().setPosition(RectangleEdge.RIGHT);
        chart.getTitle().setMargin(new RectangleInsets(15,5,15,5));
        chart.getTitle().setPaint(Color.BLACK);
    }

    private TimeSeriesCollection randomDataset(float min, float max) {
        return null;
    }

    private void showAreas() {
        Rectangle2D screenDataAreaChartPanel = this.chartPanel.getScreenDataArea();
        System.out.println("screenDataAreaChartPanel: "+screenDataAreaChartPanel);

        Rectangle2D plotArea = this.chartPanel.getChartRenderingInfo().getPlotInfo().getPlotArea();
        System.out.println("getPlotArea: "+plotArea.toString());

        Rectangle2D dataAreaPlot = this.chartPanel.getChartRenderingInfo().getPlotInfo().getDataArea();
        System.out.println("getDataArea: "+dataAreaPlot.toString());

        Rectangle2D dataAreaSubplotTop = this.chartPanel.getChartRenderingInfo().getPlotInfo().getSubplotInfo(0).getDataArea();
        Rectangle2D dataAreaSubplotBottom = this.chartPanel.getChartRenderingInfo().getPlotInfo().getSubplotInfo(1).getDataArea();
        System.out.println("dataAreaSubplotTop: "+dataAreaSubplotTop.toString());
        System.out.println("dataAreaSubplotBottom: "+dataAreaSubplotBottom.toString());

        System.out.println();

        label.setText("ScreenDataArea.height="+Math.round(screenDataAreaChartPanel.getHeight())+
                ". SubPlotTop.heigth="+Math.round(dataAreaSubplotTop.getHeight())+
                ". SubPlotBottom.heigth="+Math.round(dataAreaSubplotBottom.getHeight()));
        repaint();
    }

    @Override
    public void componentHidden(ComponentEvent e) {}

    @Override
    public void componentMoved(ComponentEvent e) { }

    @Override
    public void componentResized(ComponentEvent e) {
        chartPanel.repaint();
        chartPanel.revalidate();
        this.repaint();
        showAreas();
    }

    @Override
    public void componentShown(ComponentEvent e) { }
}

I've used jfreechart v1.0.14 and jcommon v1.0.18. In the example there are three values above the chart. You will see that the three values grow while you make the window bigger, but at about 800px height, the first value will keep growing while the others don't. Why?
If you don't have a big screen resolution you probably won't see the error, as it happened to me.

Am I doing something wrong? Is that a bug?

Upvotes: 1

Views: 1823

Answers (2)

loucru1
loucru1

Reputation: 13

I myself had a similar issue.

The issue seems to stem from the chart panel limiting its default maximum size causing the subplot data area to stop updating correctly.

Increasing the max height/width should solve your issue.

panel.setMaximumHeight(2000);
panel.setMaximumSize(1500);

See this bug post for more information. http://sourceforge.net/p/jfreechart/bugs/911/

Upvotes: 1

trashgod
trashgod

Reputation: 205785

A few notes:

  • You may be looking for one of the org.jfree.chart.annotations, in which "coordinates are specified in data space;" a few examples are seen here.

  • A JFreeChart is not a component; a ChartPanel is a component that repaint's the panel in response to assorted chart events; a ComponentListener is rarely warranted.

  • Don't use setBounds(); instead, pack() the enclosing Window; override getPreferredSize() in the ChartPanel if the default is unsatisfactory.

  • Do construct and manipulate Swing GUI objects only on the event dispatch thread.

Upvotes: 1

Related Questions