How to get the coordinates of a point on mouse click with JFreeChart?
Asked Answered
B

4

7

I am trying to get the coordinates of the point clicked with the mouse on a scatter plot graph.

When you click on a point, "Click event!" and the coordinates are printed on the console. When you click on the "Test" button, "Test" and the coordinates are printed on the console.

Problem: The coordinates printed after clicking the button are up-to-date. The coordinates printed after clicking on a point are the one of the previously selected point.

How can I fix that (so when I click on a point, the coordinates of the new selected point are displayed) ?

package graph;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.util.Random;

import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartMouseEvent;
import org.jfree.chart.ChartMouseListener;
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;

/**
 * @see http://stackoverflow.com/questions/7231824
 * @see http://stackoverflow.com/questions/7205742
 * @see http://stackoverflow.com/questions/7208657
 * @see http://stackoverflow.com/questions/7071057
 */
public class GraphFrameOld extends JFrame {

    private static final int N = 32;
    private static final String title = "Scatter Plot Pannel";
    private static final Random rand = new Random();
    private final XYSeries added = new XYSeries("Added");

    private static XYPlot xyPlot;

    public GraphFrameOld(String s) {
        super(s);
        final ChartPanel chartPanel = createGraphPanel();

        this.add(chartPanel, BorderLayout.CENTER);
        JPanel control = new JPanel();
        control.add(new JButton(new AbstractAction("Add") {

            @Override
            public void actionPerformed(ActionEvent e) {
                for (int i = 0; i < N; i++) {
                    added.add(rand.nextDouble(), rand.nextDouble());
                }
            }
        }));

        control.add(new JButton(new AbstractAction("Test") {

            @Override
            public void actionPerformed(ActionEvent e) {
                System.out.println("Test");
                System.out.println(xyPlot.getDomainCrosshairValue() + " "
                        + xyPlot.getRangeCrosshairValue());

            }
        }));

        // add click event
        chartPanel.addChartMouseListener(new ChartMouseListener() {
            @Override
            public void chartMouseClicked(ChartMouseEvent e) {
                System.out.println("Click event!");
                XYPlot xyPlot2 = chartPanel.getChart().getXYPlot();
                  // Problem: the coordinates displayed are the one of the previously selected point !
                System.out.println(xyPlot2.getDomainCrosshairValue() + " "
                        + xyPlot2.getRangeCrosshairValue());
            }

            @Override
            public void chartMouseMoved(ChartMouseEvent arg0) {
            }
        });

        this.add(control, BorderLayout.SOUTH);
    }

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

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

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

            @Override
            public void run() {
                GraphFrameOld demo = new GraphFrameOld(title);
                demo.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                demo.pack();
                demo.setLocationRelativeTo(null);
                demo.setVisible(true);
            }
        });
    }
}
Belloc answered 13/3, 2012 at 14:45 Comment(0)
P
6

My guess is that your mouse listener gets called before the (internal) JFreeCharts listener is, so the cross hair point is not yet updated when your code executes (point to the previous selection still). Putting your chartMouseClicked code in an invokeLater should fix that.

Presuppose answered 13/3, 2012 at 16:28 Comment(0)
H
1

The problem is that the redrawing of the chart is also triggered by the mouse event and so it is not assured that this has finished at the time your event listener is triggered.

You should listen to another point which guarantees the redraw is finished. You can use the chartProgressListener and filter out when the redrawing has completed. The adapted code isn't very elegant and you might need some more checks, but it seems to do the job:

package graph;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.MouseEvent;
import java.util.Random;

import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartMouseEvent;
import org.jfree.chart.ChartMouseListener;
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.entity.ChartEntity;
import org.jfree.chart.event.*;
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;

/**
 * @see http://stackoverflow.com/questions/7231824
 * @see http://stackoverflow.com/questions/7205742
 * @see http://stackoverflow.com/questions/7208657
 * @see http://stackoverflow.com/questions/7071057
 */
public class GraphFrameOld extends JFrame {

    private static final int N = 32;
    private static final String title = "Scatter Plot Pannel";
    private static final Random rand = new Random();
    private final XYSeries added = new XYSeries("Added");

    private static XYPlot xyPlot;

    public GraphFrameOld(String s) {
    super(s);
    final ChartPanel chartPanel = createGraphPanel();

    this.add(chartPanel, BorderLayout.CENTER);
    JPanel control = new JPanel();
    control.add(new JButton(new AbstractAction("Add") {

        @Override
        public void actionPerformed(ActionEvent e) {
        for (int i = 0; i < N; i++) {
            added.add(rand.nextDouble(), rand.nextDouble());
        }
        }
    }));

    control.add(new JButton(new AbstractAction("Test") {

        @Override
        public void actionPerformed(ActionEvent e) {
        System.out.println("Test");
        System.out.println(xyPlot.getDomainCrosshairValue() + " "
            + xyPlot.getRangeCrosshairValue());

        }
    }));



    this.add(control, BorderLayout.SOUTH);
    }

    private ChartPanel createGraphPanel() {
    JFreeChart jfreechart = ChartFactory
        .createScatterPlot(title, "X", "Y", createSampleData(),
            PlotOrientation.VERTICAL, true, true, false);



    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.1));
    domain.setVerticalTickLabels(true);
    NumberAxis range = (NumberAxis) xyPlot.getRangeAxis();
    range.setRange(0.0, 1.0);
    range.setTickUnit(new NumberTickUnit(0.1));
    final ChartPanel result = new ChartPanel(jfreechart);

       jfreechart.addProgressListener(new ChartProgressListener() {

        @Override
        public void chartProgress(ChartProgressEvent cpe) {
        if(cpe.getType()==ChartProgressEvent.DRAWING_FINISHED){
         System.out.println("Click event!");
        XYPlot xyPlot2 = result.getChart().getXYPlot();
        System.out.println(xyPlot2.getDomainCrosshairValue() + " "
            + xyPlot2.getRangeCrosshairValue());
        }
        }
    });


    return result;
    }

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

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

        @Override
        public void run() {
        GraphFrameOld demo = new GraphFrameOld(title);
        demo.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        demo.pack();
        demo.setLocationRelativeTo(null);
        demo.setVisible(true);
        }
    });
    }
}
Hymanhymen answered 13/3, 2012 at 16:32 Comment(0)
D
0

Try extracting from ChartMouseEvent e:

e.x
e.y
Dipsomania answered 13/3, 2012 at 15:2 Comment(1)
I tried e.getChart().getXYPlot().getDomainCrosshairValue(). Same problemBelloc
L
0

e.getTrigger().getX()

worked for me!

System.out.println(e.getTrigger().getX() + " " + e.getTrigger().getY() );
Lysander answered 17/7, 2013 at 20:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.