CombinedDomainXYPlot - mouse wheel zoom behavior [Fixed!!!]

A discussion forum for JFreeChart (a 2D chart library for the Java platform).
Locked
gengar
Posts: 26
Joined: Thu Mar 18, 2010 12:28 am
antibot: No, of course not.

CombinedDomainXYPlot - mouse wheel zoom behavior [Fixed!!!]

Post by gengar » Thu Mar 18, 2010 12:49 am

I find that the mouse wheel zoom behavior of a CombinedDomainXYPlot is different from a XYPlot.
When you scroll the mouse wheel in a XYPlot, the zoom will be anchored on the cursor. This is not the case in a CombinedDomainXYPlot. I have attached a sample program below.

To see what I mean, here is a little test that you could do.
In the upper subplot of the combined plot:
1. Place your cursor at (10,10).
2. Scroll you mouse wheel.
3. You would see that the "V" curve is sliding towards the bottom.
In the lower subplot of the combined plot:
1. Place your cursor at (10,10).
2. Scroll you mouse wheel.
3. You would see that the "V" curve is sliding towards the top.

I suspect that the subplot vertical coordinates are not calculated correctly. I am guessing that the CombinedRangeXYPlot would have a similar problem. Whether this is a bug or not, I am looking for a solution. Thanks in advance!

sample program:

Code: Select all

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.plot.CombinedDomainXYPlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.StandardXYItemRenderer;
import org.jfree.chart.renderer.xy.XYItemRenderer;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;

public class CombinedXYChartTest {

    public CombinedXYChartTest()
    {
        
    }

    private JFreeChart createCombinedChart()
    {

        XYSeries s1 = new XYSeries("#1");
        s1.add(0.0,20.0);
        s1.add(10.0,10.0);
        s1.add(20.0,20.0);
        XYSeriesCollection c1 = new XYSeriesCollection();
        c1.addSeries(s1);
        final XYItemRenderer renderer1 = new StandardXYItemRenderer();
        final NumberAxis rangeAxis1 = new NumberAxis("Range #1");
        //rangeAxis1.setAutoRangeIncludesZero(false);
        final XYPlot subplot1 = new XYPlot(c1, null, rangeAxis1, renderer1);
        subplot1.setRangeAxisLocation(AxisLocation.TOP_OR_LEFT);

        XYSeries s2 = new XYSeries("#2");
        s2.add(0.0,20.0);
        s2.add(10.0,10.0);
        s2.add(20.0,20.0);
        XYSeriesCollection c2 = new XYSeriesCollection();
        c2.addSeries(s2);
        final XYItemRenderer renderer2 = new StandardXYItemRenderer();
        final NumberAxis rangeAxis2 = new NumberAxis("Range #2");
        //rangeAxis2.setAutoRangeIncludesZero(false);
        final XYPlot subplot2 = new XYPlot(c2, null, rangeAxis2, renderer2);

        subplot2.setRangeAxisLocation(AxisLocation.BOTTOM_OR_LEFT);
        
        CombinedDomainXYPlot cplot = new CombinedDomainXYPlot(new NumberAxis("Domain"));
        cplot.add(subplot1, 1);
        cplot.add(subplot2, 1);
        cplot.setOrientation(PlotOrientation.VERTICAL);
        
        return new JFreeChart(cplot);
    }

    private JFreeChart createChart()
    {
        XYSeries s1 = new XYSeries("#1");
        s1.add(0.0,20.0);
        s1.add(10.0,10.0);
        s1.add(20.0,20.0);
        XYSeriesCollection c1 = new XYSeriesCollection();
        c1.addSeries(s1);
        final XYItemRenderer renderer1 = new StandardXYItemRenderer();
        final NumberAxis rangeAxis1 = new NumberAxis("Range");
        final NumberAxis domainAxis1 = new NumberAxis("Domain");
        final XYPlot plot = new XYPlot(c1, domainAxis1, rangeAxis1, renderer1);        
        
        return new JFreeChart(plot);
    }

    public static void main(String[] args)
    {
        CombinedXYChartTest test = new CombinedXYChartTest();

        ChartPanel combinedPanel = new ChartPanel(test.createCombinedChart());
        combinedPanel.setZoomAroundAnchor(true);
        combinedPanel.setMouseWheelEnabled(true);
        JFrame combinedFrame = new JFrame();
        combinedFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        combinedFrame.getContentPane().add(combinedPanel);
        combinedFrame.pack();
        combinedFrame.setVisible(true);

        ChartPanel panel = new ChartPanel(test.createChart());
        panel.setZoomAroundAnchor(true);
        panel.setMouseWheelEnabled(true);
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.getContentPane().add(panel);
        frame.pack();
        frame.setLocation(100,100);
        frame.setVisible(true);
    }

}
Last edited by gengar on Fri Mar 19, 2010 9:00 pm, edited 1 time in total.

gengar
Posts: 26
Joined: Thu Mar 18, 2010 12:28 am
antibot: No, of course not.

Re: CombinedDomainXYPlot - mouse wheel zoom behavior

Post by gengar » Fri Mar 19, 2010 8:57 pm

Hi guys,

That was indeed a bug. It was in the "zoomRangeAxes" method. The method was passing the CombinedDomainXYPlot's PlotRenderingInfo, but the subplot's PlotRenderingInfo should be passed instead. It looks like CombinedRangeXYPlot has the same bug, too.

This is the fixed code:

Code: Select all

        public void zoomRangeAxes(double factor, PlotRenderingInfo state,
                                  Point2D source, boolean useAnchor) {
            // delegate 'state' and 'source' argument checks...
            XYPlot subplot = findSubplot(state, source);
            if (subplot != null) {
                //subplot.zoomRangeAxes(factor, state, source, useAnchor); // This is passing the CombinedDomainXYPlot's PlotRenderingInfo; the subplot's PlotRenderingInfo should be passed instead.
                subplot.zoomRangeAxes(factor, state.getSubplotInfo(state.getSubplotIndex(source)), source, useAnchor);
            }
            else {
                // if the source point doesn't fall within a subplot, we do the
               // zoom on all subplots...
                Iterator iterator = getSubplots().iterator();
                while (iterator.hasNext()) {
                    subplot = (XYPlot) iterator.next();
                    subplot.zoomRangeAxes(factor, state, source, useAnchor);                    
                }
            }
        }
I have included another sample program below, which you could compare with my prevous sample program to see the difference!! 8)

Code: Select all

import java.awt.geom.Point2D;
import java.util.Iterator;
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.plot.CombinedDomainXYPlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.PlotRenderingInfo;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.StandardXYItemRenderer;
import org.jfree.chart.renderer.xy.XYItemRenderer;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;

public class CombinedXYChartTest2 {

    public CombinedXYChartTest2()
    {
        
    }

    private JFreeChart createCombinedChart()
    {

        XYSeries s1 = new XYSeries("#1");
        s1.add(0.0,20.0);
        s1.add(10.0,10.0);
        s1.add(20.0,20.0);
        XYSeriesCollection c1 = new XYSeriesCollection();
        c1.addSeries(s1);
        final XYItemRenderer renderer1 = new StandardXYItemRenderer();
        final NumberAxis rangeAxis1 = new NumberAxis("Range #1");
        //rangeAxis1.setAutoRangeIncludesZero(false);
        final XYPlot subplot1 = new XYPlot(c1, null, rangeAxis1, renderer1);
        subplot1.setRangeAxisLocation(AxisLocation.TOP_OR_LEFT);

        XYSeries s2 = new XYSeries("#2");
        s2.add(0.0,20.0);
        s2.add(10.0,10.0);
        s2.add(20.0,20.0);
        XYSeriesCollection c2 = new XYSeriesCollection();
        c2.addSeries(s2);
        final XYItemRenderer renderer2 = new StandardXYItemRenderer();
        final NumberAxis rangeAxis2 = new NumberAxis("Range #2");
        //rangeAxis2.setAutoRangeIncludesZero(false);
        final XYPlot subplot2 = new XYPlot(c2, null, rangeAxis2, renderer2);

        subplot2.setRangeAxisLocation(AxisLocation.BOTTOM_OR_LEFT);
        
        MyCombinedDomainXYPlot cplot = new MyCombinedDomainXYPlot(new NumberAxis("Domain"));
        cplot.add(subplot1, 1);
        cplot.add(subplot2, 1);
        cplot.setOrientation(PlotOrientation.VERTICAL);
        
        return new JFreeChart(cplot);
    }

    private JFreeChart createChart()
    {
        XYSeries s1 = new XYSeries("#1");
        s1.add(0.0,20.0);
        s1.add(10.0,10.0);
        s1.add(20.0,20.0);
        XYSeriesCollection c1 = new XYSeriesCollection();
        c1.addSeries(s1);
        final XYItemRenderer renderer1 = new StandardXYItemRenderer();
        final NumberAxis rangeAxis1 = new NumberAxis("Range");
        final NumberAxis domainAxis1 = new NumberAxis("Domain");
        final XYPlot plot = new XYPlot(c1, domainAxis1, rangeAxis1, renderer1);        
        
        return new JFreeChart(plot);
    }

    public static void main(String[] args)
    {
        CombinedXYChartTest2 test = new CombinedXYChartTest2();

        ChartPanel combinedPanel = new ChartPanel(test.createCombinedChart());
        combinedPanel.setZoomAroundAnchor(true);
        combinedPanel.setMouseWheelEnabled(true);
        JFrame combinedFrame = new JFrame();
        combinedFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        combinedFrame.getContentPane().add(combinedPanel);
        combinedFrame.pack();
        combinedFrame.setVisible(true);

        ChartPanel panel = new ChartPanel(test.createChart());
        panel.setZoomAroundAnchor(true);
        panel.setMouseWheelEnabled(true);
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.getContentPane().add(panel);
        frame.pack();
        frame.setLocation(100,100);
        frame.setVisible(true);
    }

    private class MyCombinedDomainXYPlot extends CombinedDomainXYPlot {

        public MyCombinedDomainXYPlot(ValueAxis domainAxis) {
            super(domainAxis);
        }

        @Override
        public void zoomRangeAxes(double factor, PlotRenderingInfo state,
                                  Point2D source, boolean useAnchor) {
            // delegate 'state' and 'source' argument checks...
            XYPlot subplot = findSubplot(state, source);
            if (subplot != null) {
                //subplot.zoomRangeAxes(factor, state, source, useAnchor);
                subplot.zoomRangeAxes(factor, state.getSubplotInfo(state.getSubplotIndex(source)), source, useAnchor);
            }
            else {
                // if the source point doesn't fall within a subplot, we do the
               // zoom on all subplots...
                Iterator iterator = getSubplots().iterator();
                while (iterator.hasNext()) {
                    subplot = (XYPlot) iterator.next();
                    subplot.zoomRangeAxes(factor, state, source, useAnchor);
                }
            }
        }
    }

}

alexSB
Posts: 2
Joined: Wed Apr 28, 2010 12:46 pm
antibot: No, of course not.

Re: CombinedDomainXYPlot - mouse wheel zoom behavior [Fixed!!!]

Post by alexSB » Wed Apr 28, 2010 12:56 pm

Hi, know you as block zoomOUT for not show negative values?
Thank You

gengar
Posts: 26
Joined: Thu Mar 18, 2010 12:28 am
antibot: No, of course not.

Re: CombinedDomainXYPlot - mouse wheel zoom behavior [Fixed!!!]

Post by gengar » Wed Apr 28, 2010 7:36 pm

Sorry, I don't understand what you are asking.

Locked