Get value of a point on xy chart

A discussion forum for JFreeChart (a 2D chart library for the Java platform).
pixaround
Posts: 10
Joined: Sat Jan 26, 2008 11:39 pm

Get value of a point on xy chart

Post by pixaround » Sun Feb 10, 2008 9:17 pm

How can I get the value of a single point (both x and y axis) when using mouse point to that point on xy chart or a vertical line scroll through the chart ?
Please help !!! Thanks

pixaround
Posts: 10
Joined: Sat Jan 26, 2008 11:39 pm

Post by pixaround » Tue Feb 12, 2008 11:33 pm

idea plzzzz

dlucas
Posts: 19
Joined: Sat Dec 29, 2007 5:07 am
Location: Boston (USA)

Post by dlucas » Wed Feb 13, 2008 12:24 am

You will find examples of how to do this in the demo program under Miscellaneous/Crosshairs/Crosshair Demo 1-4. I am currently studying these demos myself and hope to figure out how to get the data points to display their values on a mouse-over event in addition to the text boxes.
Best regards,

Don

pixaround
Posts: 10
Joined: Sat Jan 26, 2008 11:39 pm

Post by pixaround » Wed Feb 13, 2008 3:59 am

Is there anyway I can get the source code for these demo files ? I'm doing school proj. Thanks
My email is phu.t.tran@ou.edu

dlucas
Posts: 19
Joined: Sat Dec 29, 2007 5:07 am
Location: Boston (USA)

Post by dlucas » Wed Feb 13, 2008 5:37 am

The source to the demo is part of the $50 documentation package that the author sells separately. I can't send it to you, but perhaps when David sees this he will have other options.

Alternatively, if one of the other users who sees this has working code in this topic area, they will send you an excerpt from their own code.

Personally, I haven't got this part of the package figured out yet so I'm afraid that I can't help you.
Best regards,

Don

pixaround
Posts: 10
Joined: Sat Jan 26, 2008 11:39 pm

Post by pixaround » Wed Feb 13, 2008 6:00 am

Ok through JFreeChart API, I can set the crosshair using these methods
xyplot.setDomainCrosshairVisible(true);
xyplot.setDomainCrosshairLockedOnData(true); xyplot.setRangeCrosshairVisible(true);
xyplot.setRangeCrosshairLockedOnData(true);

I can get the value by these two methods

xyplot.getRangeCrosshairValue();
xyplot.getDomainCrosshairValue();

I just need a suggestion about how to get the value whenever someone click at some points on the chart. Can mouse listener do that ? Thanks

pixaround
Posts: 10
Joined: Sat Jan 26, 2008 11:39 pm

Post by pixaround » Wed Feb 13, 2008 3:31 pm

I just try to get the value to print out to the console. It always lags behind. For ex I click on the point(2,3). It prints out the previous point clicked. If I click another point, it will print out 2 3. Idea ? Thanks

chartPanel.addChartMouseListener(this);

public void chartMouseClicked(ChartMouseEvent e) {
System.out.println(plot.getRangeCrosshairValue());
System.out.println(plot.getDomainCrosshairValue());
}

dlucas
Posts: 19
Joined: Sat Dec 29, 2007 5:07 am
Location: Boston (USA)

Post by dlucas » Wed Feb 13, 2008 11:52 pm

Did you figure out why it lags behind one point yet? I'm going to be working on this same issue this weekend and would appreciate knowing the solution.
Best regards,

Don

pixaround
Posts: 10
Joined: Sat Jan 26, 2008 11:39 pm

Post by pixaround » Thu Feb 14, 2008 1:09 am

According to Dave:
"The cross-hair values are updated during the chart redraw, so
you'll see in the cross-hair demos that the code must wait until the
chart has been redrawn before querying these valies."
I will look into it this weekend. Thanks

anamika21
Posts: 13
Joined: Mon Feb 25, 2008 3:20 pm

Post by anamika21 » Mon Feb 25, 2008 3:22 pm

were you able to solve the problem.. and did u add the mouse listener..if yes..could u plz also guide me for that..

anamika

dlucas
Posts: 19
Joined: Sat Dec 29, 2007 5:07 am
Location: Boston (USA)

Post by dlucas » Tue Feb 26, 2008 5:26 am

Hi -

Here is a code fragment that I wrote and is being used in an SWT Composite. It does the following:

1. If a left mouse click occurs (presumably on or near a point on my XYSeriesCollection based chart) the standard JFree chart mouse code will mark the point with both a horizontal and a vertical crosshair marker and my ChartMouseListener will read the X and Y data values from this point and display them in 2 SWT text labels that are located elsewhere in a very complex set of nested SWT composites in using a String.format compatible string of something like "X: %6.12f" and "Y: %6.12f" where the %6.12f is a double precision mixed mode floating point number conversion that receives the retrieved data values from the chart. Note that I have enabled the feature that causes the crosshairs to lock onto the nearest data point automatically elsewhere in the code. Also, note that the chart composite update() method is invoked prior to retrieving the chart mouse event. If you omit that step, you will retrieve the previous crosshair event rather than the current crosshair event as others have mentioned in this post already.

2. If a control-left mouse click occurs, my ChartMouseListener will drop both a horizontal and a vertical marker line (this is different than the crosshair marker which is not persistent). The vertical marker line also gets the X and Y data values stuffed into a marker annotation label. The constant "NL" is a system independent newline character string created elsewhere in the program.

3. If a shift-control-left mouse click occurs, the ChartMouseListener will attempt to remove a previously dropped set of marker lines, although you have to perform this close enough to the original data point that the mouse click finds the same point.

Some useful debug print statements were left in - you will want to delete those before you release any code.

Here is a code fragment and the entirety of the ChartMouseListener nested class:




package somePackage;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Stroke;
import java.awt.event.InputEvent;
import java.awt.event.MouseEvent;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.text.DateFormat;
import java.text.Format;
import java.util.Date;
import java.util.Properties;
import java.util.Vector;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.RowData;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Text;
import org.jdom.Element;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartMouseEvent;
import org.jfree.chart.ChartMouseListener;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.LogarithmicAxis;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.block.BlockBorder;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.ValueMarker;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYItemRenderer;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.chart.title.LegendTitle;
import org.jfree.chart.title.TextTitle;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.jfree.experimental.chart.annotations.XYTitleAnnotation;
import org.jfree.experimental.chart.swt.ChartComposite;
import org.jfree.ui.LengthAdjustmentType;
import org.jfree.ui.RectangleAnchor;
import org.jfree.ui.RectangleEdge;
import org.jfree.ui.RectangleInsets;
import org.jfree.ui.TextAnchor;

public class ScopeComposite extends Composite {

/**
* Note: JFree Chart mouse events require a special listener interface class
* implementation that is separate and different from the SWT mouse listener
* interface so that it will work with either Swing or SWT/JFace. At its core,
* JFreeChart is using AWT mouse events, not SWT mouse events. Care must be
* taken in how imports are organized since the classes have the same names.
*/
class MyChartMouseListener implements ChartMouseListener {
MouseEvent tr;
int x, y;
double chartX, chartY;
int ctrlShiftClickMask = InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK;

public void chartMouseClicked(ChartMouseEvent e) {
tr = e.getTrigger();
System.out.printf("MyChartMouseListener: ChartMouseEvent %s triggered by %s occurred\n", e.getSource().toString(), tr.paramString());

//Crosshair values are not valid until after the chart has been updated
scopeChartComposite.update();
scopeXYPlot = scopeChart.getXYPlot();

if (tr.getButton() == MouseEvent.BUTTON1) {
if ((tr.getModifiersEx() & ctrlShiftClickMask) == ctrlShiftClickMask) {
//Ctrl-Shift Click is used to remove an existing marker
ValueMarker marker = new ValueMarker(scopeXYPlot.getDomainCrosshairValue());
marker.setLabelOffsetType(LengthAdjustmentType.EXPAND);
marker.setPaint(markerLineColor);
marker.setLabel(String.format("X: %-1.3f%sY: %-1.3f", scopeXYPlot.getDomainCrosshairValue(), NL, scopeXYPlot.getRangeCrosshairValue()));
marker.setLabelPaint(markerLabelColor);
marker.setLabelAnchor(RectangleAnchor.TOP_RIGHT);
marker.setLabelTextAnchor(TextAnchor.TOP_LEFT);
marker.setLabelFont(markerLabelFont);
marker.setStroke(markerStroke);

scopeXYPlot.removeDomainMarker(marker);
marker = new ValueMarker(scopeXYPlot.getRangeCrosshairValue());
marker.setPaint(markerLineColor);
marker.setStroke(markerStroke);
scopeXYPlot.removeRangeMarker(marker);
System.out.printf("MyChartMouseListener: Ctrl-Shift-Click detected, marker removed [%s]\n", marker.getLabel());
scopeChartComposite.update();

} else if ((tr.getModifiersEx() & MouseEvent.CTRL_DOWN_MASK) == MouseEvent.CTRL_DOWN_MASK) {
//Left mouse Ctrl-Click occurred

ValueMarker marker = new ValueMarker(scopeXYPlot.getDomainCrosshairValue());
marker.setLabelOffsetType(LengthAdjustmentType.EXPAND);
marker.setPaint(markerLineColor);
marker.setLabel(String.format("X: %-1.3f%sY: %-1.3f", scopeXYPlot.getDomainCrosshairValue(), NL, scopeXYPlot.getRangeCrosshairValue()));
marker.setLabelPaint(markerLabelColor);
marker.setLabelAnchor(RectangleAnchor.TOP_RIGHT);
marker.setLabelTextAnchor(TextAnchor.TOP_LEFT);
marker.setLabelFont(markerLabelFont);
marker.setStroke(markerStroke);

scopeXYPlot.addDomainMarker(marker);
marker = new ValueMarker(scopeXYPlot.getRangeCrosshairValue());
marker.setPaint(markerLineColor);
marker.setStroke(markerStroke);
scopeXYPlot.addRangeMarker(marker);
System.out.printf("MyChartMouseListener: Ctrl-Click detected, marker added [%s]\n", marker.getLabel());
scopeChartComposite.update();

} else {
//Normal left mouse click occurred
System.out.printf("MyChartMouseListener: normal click detected; params = [%s] detected\n", tr.paramString());
double crossHairX = scopeXYPlot.getDomainCrosshairValue();
double crossHairY = scopeXYPlot.getRangeCrosshairValue();

XLabel.setText(String.format("X: (Sec)%s%8.4f", NL, crossHairX));
YLabel.setText(String.format("Y: (P/U)%s%8.4f", NL, crossHairY));
}
} else {
System.out.printf("MyChartMouseListener: some other button pressed [e=%s]\n", tr.paramString());
}
}

public void chartMouseMoved(ChartMouseEvent e) {
}
}

//The bulk of this class is omitted here
}





Here is the code fragment that added the ChartMouseListener:




MyChartMouseListener processChartMouseEvent = new MyChartMouseListener();


ChartComposite frame;

... omitted application specific code

frame.addChartMouseListener(processChartMouseEvent);



Hope that this helps everyone trying to figure out how to handle the mouse events and display specific data point values.


Also, as someone else remarked in another related post, a ChartMouseListener is NOT the same as a MouseListener! You will waste a lot of time if you get the two confused (I know, I did :wink: )

Sorry that my copy and paste somehow lost all of the leading white space characters - Is there some other way to include code in this Internet Explorer bulletin board based sorry excuse for a "text editor"?
Best regards,

Don

anamika21
Posts: 13
Joined: Mon Feb 25, 2008 3:20 pm

Post by anamika21 » Tue Feb 26, 2008 12:54 pm

Thx for the code..i have 2 question---

1) could u also tell me that do i need to implement the following code---
---public void chartMouseMoved(ChartMouseEvent e)
for MouseListener or any other method? my requirement is only to get the points when mouse is clicked?

2) do u know any method like ToolTip to see the points when clicked the mouse on graph?

thx in advance....

dlucas
Posts: 19
Joined: Sat Dec 29, 2007 5:07 am
Location: Boston (USA)

Post by dlucas » Tue Feb 26, 2008 3:43 pm

As you can see from the code fragment, I did not implement any code for ChartMouseMoved. Since ChartMouseListener is an interface, you must implement all of its defined methods, even if they are only blank.

I have made an initial attempt to get tool tips to work, but I have not been successful yet. Basically, nothing happens at all. I have seen several other posts regarding tool tips in SWT, but I haven't tried any of the advice yet. The consensus seems to be that tool tips had some problems under SWT, but that they have been fixed. However, I know that tool tips have not been implemented for all chart types across the board, so it may be that they haven't been implemented for my chart type - I really don't know yet.
Best regards,

Don

anamika21
Posts: 13
Joined: Mon Feb 25, 2008 3:20 pm

Problem with ScopeComposite

Post by anamika21 » Thu Mar 06, 2008 4:05 pm

Hello Don,

I have a prob in the mouselistener code..

could you please tell me what ---public class ScopeComposite extends Composite--- do?

i didnt find the package org.jfree.experimental.chart.swt.ChartComposite.

do i really need to implement the ScopeComposite? and do i need to make it public because i want to include it one existing public file so i cant make it public but when i made it comment...
// public class ScopeComposite extends Composite
it gave lot of error like it cant understand XYPlot and so on??

could you please tell me how to proceed?

Thx a lot
Anamika

dlucas
Posts: 19
Joined: Sat Dec 29, 2007 5:07 am
Location: Boston (USA)

Post by dlucas » Thu Mar 06, 2008 6:35 pm

ScopeComposite was just the name of my particular application class. You must have a class, but it does not need to extend Composite. It could be main(), for example, or "private class MyClass" for example.
"public class ScopeComposite extends Composite" is unique to my application - just ignore it.

The package org.jfree.experimental.chart.swt.ChartComposite is a required part of using JFreeChart in SWT. When you download the JFreeChart source code, you will get the experimental SWT support stuff. You must include that package in your class path as well. The "experimental" part of JFreeChart is where JFree.org puts code that is not considered to be fully released yet. That is currently the status of the SWT support.

If you don't want to re-build the JFreeChart source, I believe that all of the jar files are already available pre-compiled, including the experimental jar files. These jar files must show up on your class path, one way or another, or Java won't be able to find the classes. You will find these jar files in the outermost directory of the JFreeChart download from Sourceforge.net.
Best regards,

Don

Locked