Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JFreeChart : obtain data source value on mouse click

I have a JFreeChart instance that displays process memory status, initialized as follows:

m_data = new TimeSeriesCollection();
TimeSeries vmsize = new TimeSeries("VMSize");
TimeSeries resident = new TimeSeries("Resisdent");
TimeSeries shared = new TimeSeries("Shared memory");
TimeSeries code = new TimeSeries("Code");
TimeSeries data = new TimeSeries("Data");
m_data.addSeries(vmsize);
m_data.addSeries(resident);
m_data.addSeries(shared);
m_data.addSeries(code);
m_data.addSeries(data);
JFreeChart chart = ChartFactory.createTimeSeriesChart("Memory usage", "Time", "Size", m_data, true, true, false);
m_chart = new ChartPanel(chart);

Later I add values to each TimeSeries in the TimeSeriesCollection. I would like to somehow know - when the user clicks on the Chart - either what time associated with that columm, or even better - what is the index of the value.

I looked at the JFreeChart and ChartMouseListener classes, but I could not figure out how to do that (also the documentation of JFreeChart is annoyingly scarce, I guess they are trying to get people to buy their developer's guide).

like image 395
Omry Yadan Avatar asked Jul 22 '10 12:07

Omry Yadan


2 Answers

if you click dead on the item, the event.getEntity() function returns XYItem and then from there onwards

XYItemEntity xyitem=(XYItemEntity) event.getEntity(); // get clicked entity
XYDataset dataset = (XYDataset)xyitem.getDataset(); // get data set
System.out.println(xyitem.getItem()+" item of "+xyitem.getSeriesIndex()+"series");
System.out.println(dataset.getXValue(xyitem.getSeriesIndex(), xyitem.getItem()));
System.out.println(dataset.getYValue(xyitem.getSeriesIndex(), xyitem.getItem()));
Comparable comparable=dataset.getSeriesKey(0);
XYPlot xyplot = (XYPlot) event.getChart().getPlot();
System.out.println(xyplot.getRangeCrosshairValue());

however incase you do not click on the item itself but your crosshair is set to auto lock on data, in such case the crosshair will move to nearest item but since the item has not been clicked, you will not be able to get the XYItem and hence you cannot know the series and item index, to solve this problem there is this code below, it should be put in the catch clause while the above mentioned code should be in try clause

first define a function which will take crosshair value at domain and range and also Xydataset, this functions returns an inner class object that groups item index and series index

public static SeriesAndItemIndex getItemIndex(double domainVal,double rangeVal,XYDataset xydataset){
Comparable comparable;
int indexOf;
for(int i=0;i<xydataset.getSeriesCount();i++){

comparable =  xydataset.getSeriesKey(i);
     indexOf=xydataset.indexOf(comparable);
for(int j=0 ; j<xydataset.getItemCount(indexOf);j++){

    double x=xydataset.getXValue(indexOf, j);
    double y=xydataset.getYValue(indexOf, j);

    if(x == domainVal && y==rangeVal){
        return  new SeriesAndItemIndex(j,indexOf);//return item index and series index
                }


            }
        }
        return null;
    }

private static class SeriesAndItemIndex{ ///inner CLASS to group series and item clicked index
        public int itemIndex;
        public int seriesIndex;
        public SeriesAndItemIndex(int i,int s){
            itemIndex=i;
            seriesIndex=s;
        }

        @Override
        public String toString(){
            return "itemIndex="+itemIndex+",seriesIndex="+seriesIndex;
        }
    }

how to use it?

try{......code block from the top

}catch(Exception e){

Object source=event.getSource();
JFreeChart chartpanel=(JFreeChart)source;
XYPlot xyplot = (XYPlot) chartpanel.getPlot();
XYDataset xydataset= xyplot.getDataset();
double d=xyplot.getDomainCrosshairValue(); //get crosshair X value
double r =xyplot.getRangeCrosshairValue(); //get crosshair y value
SeriesAndItemIndex index=getItemIndex(d,r,xydataset);
if(index != null){
    System.out.println(index.toString());
}
}
like image 122
user482963 Avatar answered Sep 27 '22 17:09

user482963


hmm should work, if you replace the last two lines by something like this:

ChartPanel panel=new ChartPanel(ChartFactory.createTimeSeriesChart("Memory usage", "Time", "Size", m_data, true, true, false)));
panel.addChartMouseListener(new ChartMouseListener(){
    void chartMouseClicked(ChartMouseEvent e){
        [...do something on click...]
    }
    void chartMouseMoved(ChartMouseEvent e){
        [...do something on move...]
    }
});
return panel;
like image 33
fasseg Avatar answered Sep 27 '22 17:09

fasseg