Axis out of scale problem

A discussion forum for JFreeChart (a 2D chart library for the Java platform).
Locked
yccheok
Posts: 48
Joined: Mon Feb 16, 2009 4:58 am

Axis out of scale problem

Post by yccheok » Sat Mar 19, 2011 5:06 pm

Currently, I have a chart which looks as follow :

Image

Its x-axis is out of scale. When I manually single click on the chart, it will look like this :

Image

What API I can call on the ChartPanel, in order to simulate the mouse click behavior, so that I can get the correct scale before I show up the chart?

yccheok
Posts: 48
Joined: Mon Feb 16, 2009 4:58 am

Re: Axis out of scale problem

Post by yccheok » Fri Mar 25, 2011 2:48 pm

Here is the demo code which demonstrate this problem.

Code: Select all

package problem;

import java.awt.Color;
import java.awt.Dimension;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.Date;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.StandardChartTheme;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.StandardXYItemRenderer;
import org.jfree.data.time.Day;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;
import org.jfree.data.xy.XYDataset;


/**
 *
 * @author yccheok
 */
public class InvestmentFlowChartJDialog extends javax.swing.JDialog {

    /** Creates new form InvestmentFlowChartJDialog */
    public InvestmentFlowChartJDialog(java.awt.Frame parent, boolean modal) {
        super(parent, modal);
        initComponents();

        final JFreeChart freeChart = createChart();

        // Apply theme.
        final StandardChartTheme chartTheme = (StandardChartTheme)org.jfree.chart.StandardChartTheme.createJFreeTheme();
        chartTheme.setShadowVisible(false);
        chartTheme.setPlotBackgroundPaint(Color.WHITE);
        chartTheme.setDomainGridlinePaint(Color.LIGHT_GRAY);
        chartTheme.setRangeGridlinePaint(Color.LIGHT_GRAY);
        chartTheme.setPlotOutlinePaint(Color.LIGHT_GRAY);
        chartTheme.apply(freeChart);

        this.chartPanel = new ChartPanel(freeChart, true, true, true, true, true);

        // Make chartPanel able to receive key event.
        // So that we may use arrow left/right key to move around yellow
        // information boxes. We may also use up/down key to perform combo box
        // selection.
        this.chartPanel.setFocusable(true);
        this.chartPanel.requestFocus();

        getContentPane().add(this.chartPanel, java.awt.BorderLayout.CENTER);

        loadDimension();
    }

    // Add change listener to chart panel to handle zoom-in.
    private void addChangeListener(ChartPanel chartPanel) {
    }
    
    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">
    private void initComponents() {

        jPanel2 = new javax.swing.JPanel();
        jComboBox1 = new javax.swing.JComboBox();
        jPanel1 = new javax.swing.JPanel();

        setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
        setTitle("Testing");
        addWindowListener(new java.awt.event.WindowAdapter() {
            public void windowClosing(java.awt.event.WindowEvent evt) {
                formWindowClosing(evt);
            }
        });
        getContentPane().setLayout(new java.awt.BorderLayout(0, 5));

        jPanel2.setLayout(new java.awt.BorderLayout());

        jComboBox1.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Hello", "World" }));
        jComboBox1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jComboBox1ActionPerformed(evt);
            }
        });
        jPanel2.add(jComboBox1, java.awt.BorderLayout.EAST);

        getContentPane().add(jPanel2, java.awt.BorderLayout.SOUTH);

        jPanel1.setBackground(new java.awt.Color(255, 255, 255));
        getContentPane().add(jPanel1, java.awt.BorderLayout.EAST);

        java.awt.Dimension screenSize = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
        setBounds((screenSize.width-750)/2, (screenSize.height-500)/2, 750, 500);
    }// </editor-fold>

    private void formWindowClosing(java.awt.event.WindowEvent evt) {                                   
    }                                  

    private void jComboBox1ActionPerformed(java.awt.event.ActionEvent evt) {                                           
    }                                          

    private void loadDimension() {
        Dimension dimension = new java.awt.Dimension(783, 539);
        if (dimension != null) {
            java.awt.Dimension screenSize = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
            setBounds((screenSize.width-(int)dimension.getWidth())/2, (screenSize.height-(int)dimension.getHeight())/2, (int)dimension.getWidth(), (int)dimension.getHeight());
        }
    }

    // Use synchronized, as it will be accessed by monitor and createChart
    // method simultaneously.
    private synchronized void updateROITimeSeries() {
        final TimeSeries _ROITimeSeries = this.ROITimeSeries;
        _ROITimeSeries.addOrUpdate(new Day(new Date(1115136000000L)), 40.0);
        _ROITimeSeries.addOrUpdate(new Day(new Date(1157385600000L)), 90.0);
        _ROITimeSeries.addOrUpdate(new Day(new Date(1192723200000L)), 140.0);
        _ROITimeSeries.addOrUpdate(new Day(new Date(1224518400000L)), 200.0);
        _ROITimeSeries.addOrUpdate(new Day(new Date(1251907200000L)), 4300);
        _ROITimeSeries.addOrUpdate(new Day(new Date(1251993600000L)), 4380.0);
    }

    private XYDataset createInvestDataset() {
        final TimeSeries series = new TimeSeries("Invest");
        series.add(new Day(new Date(1123171200000L)), 2570.0);
        return new TimeSeriesCollection(series);
    }

    // Synchronized against updateROITimeSeries.
    private synchronized JFreeChart createChart() {
        final XYDataset priceData = this.createInvestDataset();

        JFreeChart chart = ChartFactory.createTimeSeriesChart(
            " ",
            "Date",
            "Value",
            priceData,
            true,       // create legend?
            true,       // generate tooltips?
            false       // generate URLs?
        );
        
        XYPlot plot = chart.getXYPlot();

        NumberAxis rangeAxis1 = (NumberAxis) plot.getRangeAxis();
        final NumberFormat currencyFormat = new DecimalFormat("'" + "$".replace("'", "''") + "'#,##0");
        rangeAxis1.setNumberFormatOverride(currencyFormat);
        
        plot.setRenderer(1, new StandardXYItemRenderer());
        this.ROITimeSeries = new TimeSeries("Return of Investment");
        plot.setDataset(1, new TimeSeriesCollection(this.ROITimeSeries));
        this.updateROITimeSeries();

        return chart;
    }

    /* For ROI charting information. */
    private volatile TimeSeries ROITimeSeries = null;

    private ChartPanel chartPanel;

    public static void main(String[] args) {
        // TODO code application logic here
        InvestmentFlowChartJDialog dialog = new InvestmentFlowChartJDialog(null, true);
        dialog.setVisible(true);
    }
    
    // Variables declaration - do not modify
    private javax.swing.JComboBox jComboBox1;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JPanel jPanel2;
    // End of variables declaration
}


paradoxoff
Posts: 1634
Joined: Sat Feb 17, 2007 1:51 pm

Re: Axis out of scale problem

Post by paradoxoff » Sat Mar 26, 2011 9:50 am

I tried your code and could reproduce the behaviour. Unfortunately, I have not been able to really understand the behaviour. After a couple of things, i tried the following: I made the JFreeChart variable a private member of your Dialog class, added a refresh() method to your dialog class that would cause a re-rendering of the chart by calling chart.setNotify(false) followed by calling chart.setNotify(true), and called that new method after your Dialog has been made visible. But that didn't work, though I was convinced before that it would.
it turned out that when I made the dialog and the included ChgartPanel a little larger, I got back the original tick marks at one point (starting may 2005 with a distance of 4 months).
The size that the ChartPanel is using fro rendering the JFreeChart is the return value of ChartPanel.getSize(). It seems that this value is different from the size that the Container (i. e. your dialog) is giving for the ChartPanel to lay itself out. But then I would expect to see more rendering problems than just an improper tick unit. Strange. Could be a bug deep inside Swing.
Sorry that I couldn´t help more.

yccheok
Posts: 48
Joined: Mon Feb 16, 2009 4:58 am

Re: Axis out of scale problem

Post by yccheok » Sun Mar 27, 2011 5:45 am

There is a workaround for this problem,

Before showing up the dialog box, call.

dialog.pack
dialog.setBounds - As I need to decide the dialog size.
dialog.setVisible

The key is to call dialog pack.

However, there is a problem after dialog box is visible. Sometimes, I need to perform chart switching, (add and remove different chart panel), after dialog is visible.

// dialog is already visible.
remove old chart panel
add new chart panel
dialog.pack
dialog.setBounds - As I need to decide the dialog size.

Note that, users will not experience a smooth user experience, as they will realize there is a sudden change of dialog box size.

Locked