在JFreeChart中,如何获取图表上某个点的[x,y]值? [英] In JFreeChart how to get the [x,y] values of a certain point on the chart?

查看:76
本文介绍了在JFreeChart中,如何获取图表上某个点的[x,y]值?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这个问题与我以前的问题有关[

因此,如您从顶部屏幕截图中看到的那样,如果我在日期列表上单击2020-07-29,将加载图表,并且十字准线将自动聚焦于2020-07-29,相对信息将自动显示.在底部屏幕截图中,如果我单击日期2020-08-11,将加载图表图像,并将鼠标设置为2020-08-11,因此作为用户,我不必在图像上进行搜索并找到该日期的数据.

下面列出了我的简化应用程序:

  import java.awt.*;导入java.awt.event.*;导入java.text.*;导入java.util.*;导入javax.swing.*;导入org.jfree.chart.*;导入org.jfree.chart.axis.*;导入org.jfree.chart.entity.*;导入org.jfree.chart.plot.XYPlot;导入org.jfree.chart.renderer.xy.XYBarRenderer;导入org.jfree.data.time.*;导入org.jfree.data.xy.XYDataset;导入org.jfree.chart.labels.*;导入org.jfree.chart.panel.*;导入org.jfree.chart.plot.*;公共类PriceVolume_Chart扩展了JPanel实现ChartMouseListener////价格图表的演示应用程序.{ChartPanel面板;TimeSeries Price_series =新的TimeSeries(价格");TimeSeries Volume_Series =新的TimeSeries(卷");十字准线x十字线,y十字线;静态Vector< String>Volume_Color_Vector = new Vector();公共PriceVolume_Chart(字符串符号){JFreeChart chart = createChart(Symbol);panel = new ChartPanel(chart,true,true,true,false,true);panel.setPreferredSize(new Dimension(1000,500));panel.addChartMouseListener(this);CrosshairOverlay crosshairOverlay =新的CrosshairOverlay();float [] dash = {2f,0f,2f};BasicStroke bs = new BasicStroke(1,BasicStroke.CAP_BUTT,BasicStroke.JOIN_ROUND,1.0f,dash,2f);xCrosshair =新的Crosshair(Double.NaN,Color.GRAY,bs);xCrosshair.setLabelBackgroundPaint(new Color(0f,0f,0f,1f));xCrosshair.setLabelFont(xCrosshair.getLabelFont().deriveFont(14f));xCrosshair.setLabelPaint(new Color(1f,1f,1f,1f));xCrosshair.setLabelGenerator(new CrosshairLabelGenerator(){@Override公共字符串generateLabel(十字准线crosshair){long ms =(long)crosshair.getValue();TimeSeriesDataItem item = null;为(int i = 0; i< Volume_Series.getItemCount(); i ++){item = Volume_Series.getDataItem(i);如果(ms == item.getPeriod().getFirstMillisecond())中断;}long volume = item.getValue().longValue();返回NumberFormat.getInstance().format(volume);}});xCrosshair.setLabelVisible(true);yCrosshair =新的Crosshair(Double.NaN,Color.GRAY,bs);yCrosshair.setLabelBackgroundPaint(new Color(0f,0f,0f,1f));yCrosshair.setLabelFont(xCrosshair.getLabelFont().deriveFont(14f));yCrosshair.setLabelPaint(new Color(1f,1f,1f,1f));yCrosshair.setLabelVisible(true);crosshairOverlay.addDomainCrosshair(xCrosshair);crosshairOverlay.addRangeCrosshair(yCrosshair);panel.addOverlay(crosshairOverlay);添加(面板);/*xCrosshair.setValue(1.5959952E12);xCrosshair.setVisible(true);yCrosshair.setValue(45.230579);yCrosshair.setVisible(true);*/}私人JFreeChart createChart(String Symbol){createPriceDataset(Symbol);XYDataset priceData = new TimeSeriesCollection(Price_series);JFreeChart chart = ChartFactory.createTimeSeriesChart(Symbol,"Date",getYLabel("Price($)"),priceData,true,true,true);XYPlot plot = chart.getXYPlot();plot.setBackgroundPaint(new Color(192,196,196));NumberAxis rangeAxis1 =(NumberAxis)plot.getRangeAxis();rangeAxis1.setLowerMargin(0.40);//为音量条留出空间plot.getRenderer().setDefaultToolTipGenerator(新的StandardXYToolTipGenerator(StandardXYToolTipGenerator.DEFAULT_TOOL_TIP_FORMAT,new SimpleDateFormat("yyyy-MM-d"),NumberFormat.getCurrencyInstance()));NumberAxis rangeAxis2 = new NumberAxis("Volume");rangeAxis2.setUpperMargin(1.00);//为价格线留出空间rangeAxis2.setNumberFormatOverride(NumberFormat.getNumberInstance());plot.setRangeAxis(1,rangeAxis2);plot.setDataset(1,new TimeSeriesCollection(Volume_Series));plot.setRangeAxis(1,rangeAxis2);plot.mapDatasetToRangeAxis(1,1);MyRender Renderer = new MyRender();Renderer.setShadowVisible(false);plot.setRenderer(1,Renderer);DateAxis domainAxis =(DateAxis)plot.getDomainAxis();//考虑为对称性调整域轴的下边界.domainAxis.setLowerMargin(0.05);退货图表}私有无效createPriceDataset(字符串符号){String Lines [] = new String [21],Items [],Date;int年,月,日;长音量,Last_Volume = 0;双倍价格;第[0]行=日期,打开,高,低,关闭,调整关闭,成交量";第[1]行="2020-07-17,44.110001,44.369999,41.919998,42.509998,42.323395,849700";第[2]行="2020-07-20,41.630001,41.680000,39.669998,40.119999,39.943886,1319300&";第[3]行="2020-07-21,40.880001,42.860001,40.860001,42.270000,42.084450,2070300&";第[4]行="2020-07-22,41.919998,42.700001,41.090000,42.570000,42.383133,1317600&";第[5]行="2020-07-23,43.919998,46.389999,43.279999,44.759998,44.563519,1917700&";第[6]行="2020-07-24,46.500000,46.500000,43.950001,44.410000,44.215057,1384600&";第[7]行="2020-07-27,44.000000,44.240002,42.610001,43.860001,43.667469,799800";行[8] ="2020-07-28,43.389999,44.590000,42.930000,43.020000,42.831158,699700";第[9]行="2020-07-29,42.759998,45.590000,42.740002,45.430000,45.230579,826200";第[10]行="2020-07-30,44.160000,44.639999,42.959999,44.500000,44.304661,798100";第[11]行="2020-07-31,44.330002,44.419998,42.580002,44.360001,44.165276,1037800&";第[12]行="2020-08-03,44.560001,45.599998,43.419998,44.939999,44.742729,797000";行[13] ="2020-08-04,44.900002,45.500000,43.450001,43.540001,43.348877,971100";第[14]行="2020-08-05,44.860001,45.389999,43.650002,45.330002,45.131020,902000";第[15] ="2020-08-06,45.049999,46.279999,44.330002,45.299999,45.101147,645200";第[16] ="2020-08-07,44.849998,46.189999,44.189999,46.150002,45.947418,604900";第[17]行="2020-08-10,46.669998,48.410000,46.549999,47.290001,47.082417,960200";第[18]行="2020-08-11,49.110001,50.849998,48.799999,48.910000,48.695301,1187700&";第[19]行="2020-08-12,49.759998,50.009998,47.060001,47.840000,47.630001,752800'';第[20]行="2020-08-13,46.950001,48.369999,46.459999,47.110001,47.110001,535700'';为(int i = 1; i< Lines.length; i ++){Items = Lines [i] .split(,");Date = Items [0] .replace(-0",-");Price = Double.parseDouble(Items [5]);Volume = Long.parseLong(Items [6]);Items = Date.split(-");Year = Integer.parseInt(Items [0]);Month = Integer.parseInt(Items [1]);Day = Integer.parseInt(Items [2]);Price_series.add(新的Day(Day,Month,Year),Price);Volume_Series.add(new Day(Day,Month,Year),Volume);Volume_Color_Vector.add(Volume> = Last_Volume?"+":-");Last_Volume =音量;}}@Override公共无效chartMouseClicked(ChartMouseEvent事件){//忽略}公共无效chartMouseMoved(ChartMouseEvent cmevent){ChartEntity chartentity = cmevent.getEntity();如果(XYItemEntity的特权实例){XYItemEntity e =(XYItemEntity)charityity;XYDataset d = e.getDataset();int s = e.getSeriesIndex();int i = e.getItem();双x = d.getXValue(s,i);双重y = d.getYValue(s,i);Out("x =" + x +" y ="+ y");xCrosshair.setValue(x);yCrosshair.setValue(y);}}字符串getYLabel(字符串文本){字符串Result =";for(int i = 0; i< Text.length(); i ++)Result + = Text.charAt(i)+(i< Text.length()-1?//Out(结果);返回结果;}私有静态无效out(字符串消息){System.out.print(message);}私有静态无效Out(String message){System.out.println(message);}//创建并显示GUI.为了线程安全,应从事件调度线程中调用此方法.静态无效Create_And_Show_GUI(){final PriceVolume_Chart demo = new PriceVolume_Chart("ADS");JFrame frame = new JFrame("PriceVolume_Chart Frame");frame.add(演示);frame.addWindowListener(new WindowAdapter(){公共无效windowActivated(WindowEvent e){}公共无效windowClosed(WindowEvent e){}public void windowClosing(WindowEvent e){System.exit(0);}公共无效windowDeactivated(WindowEvent e){}public void windowDeiconified(WindowEvent e){demo.repaint();}public void windowGainedFocus(WindowEvent e){demo.repaint();}公共无效windowIconified(WindowEvent e){}公共无效windowLostFocus(WindowEvent e){}public void windowOpening(WindowEvent e){demo.repaint();}公共无效windowOpened(WindowEvent e){}public void windowResized(WindowEvent e){demo.repaint();}public void windowStateChanged(WindowEvent e){demo.repaint();}});frame.pack();frame.setLocationRelativeTo(null);frame.setVisible(true);}公共静态void main(String [] args){//为事件调度线程安排作业:创建并显示此应用程序的GUI.SwingUtilities.invokeLater(new Runnable(){public void run(){Create_And_Show_GUI();}});}}MyRender类扩展XYBarRenderer{@Override公共Paint getItemPaint(int row,int col){this.setBarAlignmentFactor(0.5);//System.out.println(row +" + col +"+" super.getItemPaint(row,col)));返回PriceVolume_Chart.Volume_Color_Vector.elementAt(col).equals("+")?super.getItemPaint(row,col):new Color(0.56f,0.2f,0.5f,1f);}} 

我知道如何在图表的某个点上设置十字准线[已注释掉:xCrosshair.setValue(1.5959952E12);],但我不知道某个图表上某个日期的[x,y]值,因此我的问题是:在像我在这里的JFreeChart上,如何获取a的[x,y]值验证日期[例如2020-07-29],或如何获取第N个日期的[x,y]值[例如9th date = 2020-07-29]吗?

解决方案

好吧,@ trashgod很鼓舞人心.我终于尝试了他的建议,并得到了想要的答案.这是基本的解决方案:

  TimeSeriesDataItem itemX = Volume_Series.getDataItem(Index);xCrosshair.setValue(itemX.getPeriod().getFirstMillisecond());TimeSeriesDataItem itemY = Price_series.getDataItem(Index);yCrosshair.setValue(itemY.getValue().doubleValue()); 

完整示例:

  import java.awt.*;导入java.awt.event.*;导入java.text.*;导入java.util.*;导入javax.swing.*;导入org.jfree.chart.*;导入org.jfree.chart.axis.*;导入org.jfree.chart.entity.*;导入org.jfree.chart.plot.XYPlot;导入org.jfree.chart.renderer.xy.XYBarRenderer;导入org.jfree.data.time.*;导入org.jfree.data.xy.XYDataset;导入org.jfree.chart.labels.*;导入org.jfree.chart.panel.*;导入org.jfree.chart.plot.*;公共类PriceVolume_Chart扩展了JPanel实现ChartMouseListener////价格图表的演示应用程序.{ChartPanel面板;TimeSeries Price_series =新的TimeSeries(价格");TimeSeries Volume_Series =新的TimeSeries(卷");十字准线x十字线,y十字线;静态Vector< String>Volume_Color_Vector = new Vector();私人int指数;公共PriceVolume_Chart(字符串符号,整数索引){JFreeChart chart = createChart(Symbol);panel = new ChartPanel(chart,true,true,true,false,true);panel.setPreferredSize(new Dimension(1000,500));panel.addChartMouseListener(this);CrosshairOverlay crosshairOverlay =新的CrosshairOverlay();float [] dash = {2f,0f,2f};BasicStroke bs = new BasicStroke(1,BasicStroke.CAP_BUTT,BasicStroke.JOIN_ROUND,1.0f,dash,2f);xCrosshair =新的Crosshair(Double.NaN,Color.GRAY,bs);xCrosshair.setLabelBackgroundPaint(new Color(0f,0f,0f,1f));xCrosshair.setLabelFont(xCrosshair.getLabelFont().deriveFont(14f));xCrosshair.setLabelPaint(new Color(1f,1f,1f,1f));xCrosshair.setLabelGenerator(new CrosshairLabelGenerator(){@Override公共字符串generateLabel(十字准线crosshair){long ms =(long)crosshair.getValue();TimeSeriesDataItem item = null;为(int i = 0; i< Volume_Series.getItemCount(); i ++){item = Volume_Series.getDataItem(i);如果(ms == item.getPeriod().getFirstMillisecond())中断;}long volume = item.getValue().longValue();返回NumberFormat.getInstance().format(volume);}});xCrosshair.setLabelVisible(true);yCrosshair =新的Crosshair(Double.NaN,Color.GRAY,bs);yCrosshair.setLabelBackgroundPaint(new Color(0f,0f,0f,1f));yCrosshair.setLabelFont(xCrosshair.getLabelFont().deriveFont(14f));yCrosshair.setLabelPaint(new Color(1f,1f,1f,1f));yCrosshair.setLabelVisible(true);crosshairOverlay.addDomainCrosshair(xCrosshair);crosshairOverlay.addRangeCrosshair(yCrosshair);panel.addOverlay(crosshairOverlay);添加(面板);TimeSeriesDataItem itemX = Volume_Series.getDataItem(Index);xCrosshair.setValue(itemX.getPeriod().getFirstMillisecond());TimeSeriesDataItem itemY = Price_series.getDataItem(Index);yCrosshair.setValue(itemY.getValue().doubleValue());}私人JFreeChart createChart(String Symbol){createPriceDataset(Symbol);XYDataset priceData = new TimeSeriesCollection(Price_series);JFreeChart chart = ChartFactory.createTimeSeriesChart(Symbol,"Date",getYLabel("Price($)"),priceData,true,true,true);XYPlot plot = chart.getXYPlot();plot.setBackgroundPaint(new Color(192,196,196));NumberAxis rangeAxis1 =(NumberAxis)plot.getRangeAxis();rangeAxis1.setLowerMargin(0.40);//为音量条留出空间plot.getRenderer().setDefaultToolTipGenerator(新的StandardXYToolTipGenerator(StandardXYToolTipGenerator.DEFAULT_TOOL_TIP_FORMAT,new SimpleDateFormat("yyyy-MM-d"),NumberFormat.getCurrencyInstance()));NumberAxis rangeAxis2 = new NumberAxis("Volume");rangeAxis2.setUpperMargin(1.00);//为价格线留出空间rangeAxis2.setNumberFormatOverride(NumberFormat.getNumberInstance());plot.setRangeAxis(1,rangeAxis2);plot.setDataset(1,new TimeSeriesCollection(Volume_Series));plot.setRangeAxis(1,rangeAxis2);plot.mapDatasetToRangeAxis(1,1);MyRender Renderer = new MyRender();Renderer.setShadowVisible(false);plot.setRenderer(1,Renderer);DateAxis domainAxis =(DateAxis)plot.getDomainAxis();//考虑为对称性调整域轴的下边界.domainAxis.setLowerMargin(0.05);退货图表}私有无效createPriceDataset(字符串符号){String Lines [] = new String [21],Items [],Date;int年,月,日;长音量,Last_Volume = 0;双倍价格;第[0]行=日期,打开,高,低,关闭,调整关闭,成交量";第[1]行="2020-07-17,44.110001,44.369999,41.919998,42.509998,42.323395,849700";第[2]行="2020-07-20,41.630001,41.680000,39.669998,40.119999,39.943886,1319300&";第[3]行="2020-07-21,40.880001,42.860001,40.860001,42.270000,42.084450,2070300&";第[4]行="2020-07-22,41.919998,42.700001,41.090000,42.570000,42.383133,1317600&";第[5]行="2020-07-23,43.919998,46.389999,43.279999,44.759998,44.563519,1917700&";第[6]行="2020-07-24,46.500000,46.500000,43.950001,44.410000,44.215057,1384600&";第[7]行="2020-07-27,44.000000,44.240002,42.610001,43.860001,43.667469,799800";行[8] ="2020-07-28,43.389999,44.590000,42.930000,43.020000,42.831158,699700";第[9]行="2020-07-29,42.759998,45.590000,42.740002,45.430000,45.230579,826200";第[10]行="2020-07-30,44.160000,44.639999,42.959999,44.500000,44.304661,798100";第[11]行="2020-07-31,44.330002,44.419998,42.580002,44.360001,44.165276,1037800&";第[12]行="2020-08-03,44.560001,45.599998,43.419998,44.939999,44.742729,797000";行[13] ="2020-08-04,44.900002,45.500000,43.450001,43.540001,43.348877,971100";第[14]行="2020-08-05,44.860001,45.389999,43.650002,45.330002,45.131020,902000";第[15] ="2020-08-06,45.049999,46.279999,44.330002,45.299999,45.101147,645200";第[16]行="2020-08-07,44.849998,46.189999,44.189999,46.150002,45.947418,604900";第[17]行="2020-08-10,46.669998,48.410000,46.549999,47.290001,47.082417,960200";第[18]行="2020-08-11,49.110001,50.849998,48.799999,48.910000,48.695301,1187700&";第[19]行="2020-08-12,49.759998,50.009998,47.060001,47.840000,47.630001,752800'';第[20]行="2020-08-13,46.950001,48.369999,46.459999,47.110001,47.110001,535700'';为(int i = 1; i< Lines.length; i ++){Items = Lines [i] .split(,");Date = Items [0] .replace(-0",-");Price = Double.parseDouble(Items [5]);Volume = Long.parseLong(Items [6]);Items = Date.split(-");Year = Integer.parseInt(Items [0]);Month = Integer.parseInt(Items [1]);Day = Integer.parseInt(Items [2]);Price_series.add(新的Day(Day,Month,Year),Price);Volume_Series.add(new Day(Day,Month,Year),Volume);Volume_Color_Vector.add(Volume> = Last_Volume?"+":-");Last_Volume =音量;}}@Override公共无效chartMouseClicked(ChartMouseEvent事件){//忽略}公共无效chartMouseMoved(ChartMouseEvent cmevent){ChartEntity chartentity = cmevent.getEntity();如果(XYItemEntity的特权实例){XYItemEntity e =(XYItemEntity)charityity;XYDataset d = e.getDataset();int s = e.getSeriesIndex();int i = e.getItem();双x = d.getXValue(s,i);双重y = d.getYValue(s,i);Out("x =" + x +" y ="+ y)";xCrosshair.setValue(x);yCrosshair.setValue(y);}}字符串getYLabel(字符串文本){字符串Result =";for(int i = 0; i< Text.length(); i ++)Result + = Text.charAt(i)+(i< Text.length()-1?//Out(结果);返回结果;}私有静态无效out(字符串消息){System.out.print(message);}私有静态无效Out(String message){System.out.println(message);}//创建并显示GUI.为了线程安全,应从事件调度线程中调用此方法.静态无效Create_And_Show_GUI(){final PriceVolume_Chart demo = new PriceVolume_Chart("ADS",19);JFrame frame = new JFrame("PriceVolume_Chart Frame");frame.add(演示);frame.addWindowListener(new WindowAdapter(){公共无效windowActivated(WindowEvent e){}公共无效windowClosed(WindowEvent e){}public void windowClosing(WindowEvent e){System.exit(0);}公共无效windowDeactivated(WindowEvent e){}public void windowDeiconified(WindowEvent e){demo.repaint();}public void windowGainedFocus(WindowEvent e){demo.repaint();}公共无效windowIconified(WindowEvent e){}公共无效windowLostFocus(WindowEvent e){}public void windowOpening(WindowEvent e){demo.repaint();}公共无效windowOpened(WindowEvent e){}public void windowResized(WindowEvent e){demo.repaint();}public void windowStateChanged(WindowEvent e){demo.repaint();}});frame.pack();frame.setLocationRelativeTo(null);frame.setVisible(true);}公共静态void main(String [] args){//为事件调度线程安排作业:创建并显示此应用程序的GUI.SwingUtilities.invokeLater(new Runnable(){public void run(){Create_And_Show_GUI();}});}}MyRender类扩展XYBarRenderer{@Override公共Paint getItemPaint(int row,int col){this.setBarAlignmentFactor(0.5);//System.out.println(row +" + col +"+" super.getItemPaint(row,col)));返回PriceVolume_Chart.Volume_Color_Vector.elementAt(col).equals("+")?super.getItemPaint(row,col):new Color(0.56f,0.2f,0.5f,1f);}} 

This question is related to my previous question [ How to display volume in the domain crosshair and set the crosshair programmatically? ], with the help of @trashgod, I got the answers for most of my questions, but one question is still unanswered, here I'll ask this question from a different angle.

In my Swing app, there is a list of dates with some data, when I click on a certain date, I want my app to display a chart and points to that date when the image shows up, so I don't have to move my mouse around to find and display info of that date. So the app screen shots look like the following.

So as you can see from the top screenshot, if I click on 2020-07-29 on the date list, the chart will load and the cross-hairs will be automatically focused on 2020-07-29, and the relative info will auto show up. In the bottom screenshot, if I click on the date 2020-08-11, the chart image will load and the mouse will be set on 2020-08-11, so as a user, I don't have to search on the image and find that date's data.

My simplified app is listed below :

import java.awt.*;
import java.awt.event.*;
import java.text.*;
import java.util.*;
import javax.swing.*;
import org.jfree.chart.*;
import org.jfree.chart.axis.*;
import org.jfree.chart.entity.*;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYBarRenderer;
import org.jfree.data.time.*;
import org.jfree.data.xy.XYDataset;
import org.jfree.chart.labels.*;
import org.jfree.chart.panel.*;
import org.jfree.chart.plot.*;

public class PriceVolume_Chart extends JPanel implements ChartMouseListener    // A demo application for price-volume chart.   
{
  ChartPanel panel;
  TimeSeries Price_series=new TimeSeries("Price");
  TimeSeries Volume_Series=new TimeSeries("Volume");
  Crosshair xCrosshair,yCrosshair;
  static Vector<String> Volume_Color_Vector=new Vector();

  public PriceVolume_Chart(String Symbol)
  {
    JFreeChart chart=createChart(Symbol);
    panel=new ChartPanel(chart,true,true,true,false,true);
    panel.setPreferredSize(new Dimension(1000,500));
    panel.addChartMouseListener(this);
    CrosshairOverlay crosshairOverlay=new CrosshairOverlay();
    float[] dash={2f,0f,2f};
    BasicStroke bs=new BasicStroke(1,BasicStroke.CAP_BUTT,BasicStroke.JOIN_ROUND,1.0f,dash,2f);

    xCrosshair=new Crosshair(Double.NaN,Color.GRAY,bs);
    xCrosshair.setLabelBackgroundPaint(new Color(0f,0f,0f,1f));
    xCrosshair.setLabelFont(xCrosshair.getLabelFont().deriveFont(14f));
    xCrosshair.setLabelPaint(new Color(1f,1f,1f,1f));
    
    xCrosshair.setLabelGenerator(new CrosshairLabelGenerator()
    {
      @Override
      public String generateLabel(Crosshair crosshair)
      {
        long ms=(long)crosshair.getValue();
        TimeSeriesDataItem item=null;
        for (int i=0;i<Volume_Series.getItemCount();i++)
        {
          item=Volume_Series.getDataItem(i);
          if (ms==item.getPeriod().getFirstMillisecond()) break;
        }
        long volume=item.getValue().longValue();
        return NumberFormat.getInstance().format(volume);
      }
    });

    xCrosshair.setLabelVisible(true);
    yCrosshair=new Crosshair(Double.NaN,Color.GRAY,bs);
    yCrosshair.setLabelBackgroundPaint(new Color(0f,0f,0f,1f));
    yCrosshair.setLabelFont(xCrosshair.getLabelFont().deriveFont(14f));
    yCrosshair.setLabelPaint(new Color(1f,1f,1f,1f));
    yCrosshair.setLabelVisible(true);
    crosshairOverlay.addDomainCrosshair(xCrosshair);
    crosshairOverlay.addRangeCrosshair(yCrosshair);
    panel.addOverlay(crosshairOverlay);
    add(panel);
/*
    xCrosshair.setValue(1.5959952E12);
    xCrosshair.setVisible(true);
    yCrosshair.setValue(45.230579);
    yCrosshair.setVisible(true);
*/
  }

  private JFreeChart createChart(String Symbol)
  {
    createPriceDataset(Symbol);
    XYDataset priceData=new TimeSeriesCollection(Price_series);
    JFreeChart chart=ChartFactory.createTimeSeriesChart(Symbol,"Date",getYLabel("Price ( $ )"),priceData,true,true,true);
    XYPlot plot=chart.getXYPlot();
    plot.setBackgroundPaint(new Color(192,196,196));
    NumberAxis rangeAxis1=(NumberAxis)plot.getRangeAxis();
    rangeAxis1.setLowerMargin(0.40);                                           // Leave room for volume bars
    plot.getRenderer().setDefaultToolTipGenerator(new StandardXYToolTipGenerator(StandardXYToolTipGenerator.DEFAULT_TOOL_TIP_FORMAT,new SimpleDateFormat("yyyy-MM-d"),NumberFormat.getCurrencyInstance()));

    NumberAxis rangeAxis2=new NumberAxis("Volume");
    rangeAxis2.setUpperMargin(1.00);                                           // Leave room for price line   
    rangeAxis2.setNumberFormatOverride(NumberFormat.getNumberInstance());
    plot.setRangeAxis(1,rangeAxis2);
    plot.setDataset(1,new TimeSeriesCollection(Volume_Series));
    plot.setRangeAxis(1,rangeAxis2);
    plot.mapDatasetToRangeAxis(1,1);
    MyRender Renderer=new MyRender();
    Renderer.setShadowVisible(false);
    plot.setRenderer(1,Renderer);

    DateAxis domainAxis=(DateAxis) plot.getDomainAxis();                     // Consider adjusting the lower margin of the domain axis for symmetry.
    domainAxis.setLowerMargin(0.05);

    return chart;
  }

  private void createPriceDataset(String Symbol)
  {
    String Lines[]=new String[21],Items[],Date;
    int Year, Month, Day;
    long Volume,Last_Volume=0;
    double Price;

    Lines[0]="Date,Open,High,Low,Close,Adj Close,Volume";
    Lines[1]="2020-07-17,44.110001,44.369999,41.919998,42.509998,42.323395,849700";
    Lines[2]="2020-07-20,41.630001,41.680000,39.669998,40.119999,39.943886,1319300";
    Lines[3]="2020-07-21,40.880001,42.860001,40.860001,42.270000,42.084450,2070300";
    Lines[4]="2020-07-22,41.919998,42.700001,41.090000,42.570000,42.383133,1317600";
    Lines[5]="2020-07-23,43.919998,46.389999,43.279999,44.759998,44.563519,1917700";
    Lines[6]="2020-07-24,46.500000,46.500000,43.950001,44.410000,44.215057,1384600";
    Lines[7]="2020-07-27,44.000000,44.240002,42.610001,43.860001,43.667469,799800";
    Lines[8]="2020-07-28,43.389999,44.590000,42.930000,43.020000,42.831158,699700";
    Lines[9]="2020-07-29,42.759998,45.590000,42.740002,45.430000,45.230579,826200";
    Lines[10]="2020-07-30,44.160000,44.639999,42.959999,44.500000,44.304661,798100";
    Lines[11]="2020-07-31,44.330002,44.419998,42.580002,44.360001,44.165276,1037800";
    Lines[12]="2020-08-03,44.560001,45.599998,43.419998,44.939999,44.742729,797000";
    Lines[13]="2020-08-04,44.900002,45.500000,43.450001,43.540001,43.348877,971100";
    Lines[14]="2020-08-05,44.860001,45.389999,43.650002,45.330002,45.131020,902000";
    Lines[15]="2020-08-06,45.049999,46.279999,44.330002,45.299999,45.101147,645200";
    Lines[16]="2020-08-07,44.849998,46.189999,44.189999,46.150002,45.947418,604900";
    Lines[17]="2020-08-10,46.669998,48.410000,46.549999,47.290001,47.082417,960200";
    Lines[18]="2020-08-11,49.110001,50.849998,48.799999,48.910000,48.695301,1187700";
    Lines[19]="2020-08-12,49.759998,50.009998,47.060001,47.840000,47.630001,752800";
    Lines[20]="2020-08-13,46.950001,48.369999,46.459999,47.110001,47.110001,535700";

    for (int i=1;i<Lines.length;i++)
    {
      Items=Lines[i].split(",");
      Date=Items[0].replace("-0","-");
      Price=Double.parseDouble(Items[5]);
      Volume=Long.parseLong(Items[6]);
      Items=Date.split("-");
      Year=Integer.parseInt(Items[0]);
      Month=Integer.parseInt(Items[1]);
      Day=Integer.parseInt(Items[2]);
      Price_series.add(new Day(Day,Month,Year),Price);
      Volume_Series.add(new Day(Day,Month,Year),Volume);
      Volume_Color_Vector.add(Volume>=Last_Volume?"+":"-");
      Last_Volume=Volume;
    }
  }

  @Override
  public void chartMouseClicked(ChartMouseEvent event)
  {
    // ignore
  }

  public void chartMouseMoved(ChartMouseEvent cmevent)
  {
    ChartEntity chartentity=cmevent.getEntity();
    if (chartentity instanceof XYItemEntity)
    {
      XYItemEntity e=(XYItemEntity)chartentity;
      XYDataset d=e.getDataset();
      int s=e.getSeriesIndex();
      int i=e.getItem();
      double x=d.getXValue(s,i);
      double y=d.getYValue(s,i);
      Out("x = "+x+"  y = "+y);
      xCrosshair.setValue(x);
      yCrosshair.setValue(y);
    }
  }

  String getYLabel(String Text)
  {
    String Result="";

    for (int i=0;i<Text.length();i++) Result+=Text.charAt(i)+(i<Text.length()-1?"\u2009":"");
//    Out(Result);
    return Result;
  }

  private static void out(String message) { System.out.print(message); }

  private static void Out(String message) { System.out.println(message); }

  // Create the GUI and show it. For thread safety, this method should be invoked from the event-dispatching thread.
  static void Create_And_Show_GUI()
  {
    final PriceVolume_Chart demo=new PriceVolume_Chart("ADS");

    JFrame frame=new JFrame("PriceVolume_Chart Frame");
    frame.add(demo);
    frame.addWindowListener(new WindowAdapter()
    {
      public void windowActivated(WindowEvent e) { }
      public void windowClosed(WindowEvent e) { }
      public void windowClosing(WindowEvent e) { System.exit(0); }
      public void windowDeactivated(WindowEvent e) { }
      public void windowDeiconified(WindowEvent e) { demo.repaint(); }
      public void windowGainedFocus(WindowEvent e) { demo.repaint(); }
      public void windowIconified(WindowEvent e) { }
      public void windowLostFocus(WindowEvent e) { }
      public void windowOpening(WindowEvent e) { demo.repaint(); }
      public void windowOpened(WindowEvent e) { }
      public void windowResized(WindowEvent e) { demo.repaint(); }
      public void windowStateChanged(WindowEvent e) { demo.repaint(); }
    });
    frame.pack();
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);
  }

  public static void main(String[] args)
  {
    // Schedule a job for the event-dispatching thread : creating and showing this application's GUI.
    SwingUtilities.invokeLater(new Runnable() { public void run() { Create_And_Show_GUI(); } });
  }
}

class MyRender extends XYBarRenderer
{
  @Override
  public Paint getItemPaint(int row,int col)
  {
    this.setBarAlignmentFactor(0.5);
//    System.out.println(row+" "+col+" "+super.getItemPaint(row,col));
    return PriceVolume_Chart.Volume_Color_Vector.elementAt(col).equals("+")?super.getItemPaint(row,col):new Color(0.56f,0.2f,0.5f,1f);
  }
} 

I know how to set the cross-hair on a certain point on the chart [ Commented out : xCrosshair.setValue(1.5959952E12); ], yet I do not know the [x,y] values of a certain date on a certain chart, therefore my question is : on a JFreeChart like the one I have here, how to get the [x,y] values of a vertain date [ e.g. 2020-07-29 ], or how to get the [x,y] values of the N-th date [ e.g. 9-th date = 2020-07-29 ] ?

解决方案

Alright, @trashgod was inspirational. I finally tried his suggestions and got to the answer I was looking for; here is the essential solution:

TimeSeriesDataItem itemX = Volume_Series.getDataItem(Index);
xCrosshair.setValue(itemX.getPeriod().getFirstMillisecond());

TimeSeriesDataItem itemY = Price_series.getDataItem(Index);
yCrosshair.setValue(itemY.getValue().doubleValue());

Complete example:

import java.awt.*;
import java.awt.event.*;
import java.text.*;
import java.util.*;
import javax.swing.*;
import org.jfree.chart.*;
import org.jfree.chart.axis.*;
import org.jfree.chart.entity.*;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYBarRenderer;
import org.jfree.data.time.*;
import org.jfree.data.xy.XYDataset;
import org.jfree.chart.labels.*;
import org.jfree.chart.panel.*;
import org.jfree.chart.plot.*;

public class PriceVolume_Chart extends JPanel implements ChartMouseListener   // A demo application for price-volume chart.   
{
  ChartPanel panel;
  TimeSeries Price_series=new TimeSeries("Price");
  TimeSeries Volume_Series=new TimeSeries("Volume");
  Crosshair xCrosshair,yCrosshair;
  static Vector<String> Volume_Color_Vector=new Vector();
  private int index;

  public PriceVolume_Chart(String Symbol,int Index)
  {
    JFreeChart chart=createChart(Symbol);
    panel=new ChartPanel(chart,true,true,true,false,true);
    panel.setPreferredSize(new Dimension(1000,500));
    panel.addChartMouseListener(this);
    CrosshairOverlay crosshairOverlay=new CrosshairOverlay();
    float[] dash={2f,0f,2f};
    BasicStroke bs=new BasicStroke(1,BasicStroke.CAP_BUTT,BasicStroke.JOIN_ROUND,1.0f,dash,2f);

    xCrosshair=new Crosshair(Double.NaN,Color.GRAY,bs);
    xCrosshair.setLabelBackgroundPaint(new Color(0f,0f,0f,1f));
    xCrosshair.setLabelFont(xCrosshair.getLabelFont().deriveFont(14f));
    xCrosshair.setLabelPaint(new Color(1f,1f,1f,1f));
    
    xCrosshair.setLabelGenerator(new CrosshairLabelGenerator()
    {
      @Override
      public String generateLabel(Crosshair crosshair)
      {
        long ms=(long)crosshair.getValue();
        TimeSeriesDataItem item=null;
        for (int i=0;i<Volume_Series.getItemCount();i++)
        {
          item=Volume_Series.getDataItem(i);
          if (ms==item.getPeriod().getFirstMillisecond()) break;
        }
        long volume=item.getValue().longValue();
        return NumberFormat.getInstance().format(volume);
      }
    });

    xCrosshair.setLabelVisible(true);
    yCrosshair=new Crosshair(Double.NaN,Color.GRAY,bs);
    yCrosshair.setLabelBackgroundPaint(new Color(0f,0f,0f,1f));
    yCrosshair.setLabelFont(xCrosshair.getLabelFont().deriveFont(14f));
    yCrosshair.setLabelPaint(new Color(1f,1f,1f,1f));
    yCrosshair.setLabelVisible(true);
    crosshairOverlay.addDomainCrosshair(xCrosshair);
    crosshairOverlay.addRangeCrosshair(yCrosshair);
    panel.addOverlay(crosshairOverlay);
    add(panel);
    
    TimeSeriesDataItem itemX=Volume_Series.getDataItem(Index);
    xCrosshair.setValue(itemX.getPeriod().getFirstMillisecond());
    
    TimeSeriesDataItem itemY=Price_series.getDataItem(Index);
    yCrosshair.setValue(itemY.getValue().doubleValue());
  }

  private JFreeChart createChart(String Symbol)
  {
    createPriceDataset(Symbol);
    XYDataset priceData=new TimeSeriesCollection(Price_series);
    JFreeChart chart=ChartFactory.createTimeSeriesChart(Symbol,"Date",getYLabel("Price ( $ )"),priceData,true,true,true);
    XYPlot plot=chart.getXYPlot();
    plot.setBackgroundPaint(new Color(192,196,196));
    NumberAxis rangeAxis1=(NumberAxis)plot.getRangeAxis();
    rangeAxis1.setLowerMargin(0.40);                                           // Leave room for volume bars
    plot.getRenderer().setDefaultToolTipGenerator(new StandardXYToolTipGenerator(StandardXYToolTipGenerator.DEFAULT_TOOL_TIP_FORMAT,new SimpleDateFormat("yyyy-MM-d"),NumberFormat.getCurrencyInstance()));

    NumberAxis rangeAxis2=new NumberAxis("Volume");
    rangeAxis2.setUpperMargin(1.00);                                           // Leave room for price line   
    rangeAxis2.setNumberFormatOverride(NumberFormat.getNumberInstance());
    plot.setRangeAxis(1,rangeAxis2);
    plot.setDataset(1,new TimeSeriesCollection(Volume_Series));
    plot.setRangeAxis(1,rangeAxis2);
    plot.mapDatasetToRangeAxis(1,1);
    MyRender Renderer=new MyRender();
    Renderer.setShadowVisible(false);
    plot.setRenderer(1,Renderer);

    DateAxis domainAxis=(DateAxis) plot.getDomainAxis();                     // Consider adjusting the lower margin of the domain axis for symmetry.
    domainAxis.setLowerMargin(0.05);

    return chart;
  }

  private void createPriceDataset(String Symbol)
  {
    String Lines[]=new String[21],Items[],Date;
    int Year, Month, Day;
    long Volume,Last_Volume=0;
    double Price;

    Lines[0]="Date,Open,High,Low,Close,Adj Close,Volume";
    Lines[1]="2020-07-17,44.110001,44.369999,41.919998,42.509998,42.323395,849700";
    Lines[2]="2020-07-20,41.630001,41.680000,39.669998,40.119999,39.943886,1319300";
    Lines[3]="2020-07-21,40.880001,42.860001,40.860001,42.270000,42.084450,2070300";
    Lines[4]="2020-07-22,41.919998,42.700001,41.090000,42.570000,42.383133,1317600";
    Lines[5]="2020-07-23,43.919998,46.389999,43.279999,44.759998,44.563519,1917700";
    Lines[6]="2020-07-24,46.500000,46.500000,43.950001,44.410000,44.215057,1384600";
    Lines[7]="2020-07-27,44.000000,44.240002,42.610001,43.860001,43.667469,799800";
    Lines[8]="2020-07-28,43.389999,44.590000,42.930000,43.020000,42.831158,699700";
    Lines[9]="2020-07-29,42.759998,45.590000,42.740002,45.430000,45.230579,826200";
    Lines[10]="2020-07-30,44.160000,44.639999,42.959999,44.500000,44.304661,798100";
    Lines[11]="2020-07-31,44.330002,44.419998,42.580002,44.360001,44.165276,1037800";
    Lines[12]="2020-08-03,44.560001,45.599998,43.419998,44.939999,44.742729,797000";
    Lines[13]="2020-08-04,44.900002,45.500000,43.450001,43.540001,43.348877,971100";
    Lines[14]="2020-08-05,44.860001,45.389999,43.650002,45.330002,45.131020,902000";
    Lines[15]="2020-08-06,45.049999,46.279999,44.330002,45.299999,45.101147,645200";
    Lines[16]="2020-08-07,44.849998,46.189999,44.189999,46.150002,45.947418,604900";
    Lines[17]="2020-08-10,46.669998,48.410000,46.549999,47.290001,47.082417,960200";
    Lines[18]="2020-08-11,49.110001,50.849998,48.799999,48.910000,48.695301,1187700";
    Lines[19]="2020-08-12,49.759998,50.009998,47.060001,47.840000,47.630001,752800";
    Lines[20]="2020-08-13,46.950001,48.369999,46.459999,47.110001,47.110001,535700";

    for (int i=1;i<Lines.length;i++)
    {
      Items=Lines[i].split(",");
      Date=Items[0].replace("-0","-");
      Price=Double.parseDouble(Items[5]);
      Volume=Long.parseLong(Items[6]);
      Items=Date.split("-");
      Year=Integer.parseInt(Items[0]);
      Month=Integer.parseInt(Items[1]);
      Day=Integer.parseInt(Items[2]);
      Price_series.add(new Day(Day,Month,Year),Price);
      Volume_Series.add(new Day(Day,Month,Year),Volume);
      Volume_Color_Vector.add(Volume>=Last_Volume?"+":"-");
      Last_Volume=Volume;
    }
  }

  @Override
  public void chartMouseClicked(ChartMouseEvent event)
  {
    // ignore
  }

  public void chartMouseMoved(ChartMouseEvent cmevent)
  {
    ChartEntity chartentity=cmevent.getEntity();
    if (chartentity instanceof XYItemEntity)
    {
      XYItemEntity e=(XYItemEntity)chartentity;
      XYDataset d=e.getDataset();
      int s=e.getSeriesIndex();
      int i=e.getItem();
      double x=d.getXValue(s,i);
      double y=d.getYValue(s,i);
      Out("x = "+x+"  y = "+y);
      xCrosshair.setValue(x);
      yCrosshair.setValue(y);
    }
  }

  String getYLabel(String Text)
  {
    String Result="";

    for (int i=0;i<Text.length();i++) Result+=Text.charAt(i)+(i<Text.length()-1?"\u2009":"");
//    Out(Result);
    return Result;
  }

  private static void out(String message) { System.out.print(message); }

  private static void Out(String message) { System.out.println(message); }

  // Create the GUI and show it. For thread safety, this method should be invoked from the event-dispatching thread.
  static void Create_And_Show_GUI()
  {
    final PriceVolume_Chart demo=new PriceVolume_Chart("ADS",19);

    JFrame frame=new JFrame("PriceVolume_Chart Frame");
    frame.add(demo);
    frame.addWindowListener(new WindowAdapter()
    {
      public void windowActivated(WindowEvent e) { }
      public void windowClosed(WindowEvent e) { }
      public void windowClosing(WindowEvent e) { System.exit(0); }
      public void windowDeactivated(WindowEvent e) { }
      public void windowDeiconified(WindowEvent e) { demo.repaint(); }
      public void windowGainedFocus(WindowEvent e) { demo.repaint(); }
      public void windowIconified(WindowEvent e) { }
      public void windowLostFocus(WindowEvent e) { }
      public void windowOpening(WindowEvent e) { demo.repaint(); }
      public void windowOpened(WindowEvent e) { }
      public void windowResized(WindowEvent e) { demo.repaint(); }
      public void windowStateChanged(WindowEvent e) { demo.repaint(); }
    });
    frame.pack();
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);
  }

  public static void main(String[] args)
  {
    // Schedule a job for the event-dispatching thread : creating and showing this application's GUI.
    SwingUtilities.invokeLater(new Runnable() { public void run() { Create_And_Show_GUI(); } });
  }
}

class MyRender extends XYBarRenderer
{
  @Override
  public Paint getItemPaint(int row,int col)
  {
    this.setBarAlignmentFactor(0.5);
//    System.out.println(row+" "+col+" "+super.getItemPaint(row,col));
    return PriceVolume_Chart.Volume_Color_Vector.elementAt(col).equals("+")?super.getItemPaint(row,col):new Color(0.56f,0.2f,0.5f,1f);
  }
}

这篇关于在JFreeChart中,如何获取图表上某个点的[x,y]值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆