JFreechart烛台图上拖动的怪异行为

这是这个问题的后续问题 。

会发生什么是以下几点:

当我启动图表并拖动图表时,发生了一些奇怪的事情:在一定的时间间隔内,似乎每隔7个时期,烛台就越来越小,直到它们只是一个条纹。 然后,当我拖得更远时,又变得更粗,直到它们再次变成正常大小。 这似乎每7个时期就会发生一次。

这种现象的一个例子显示在以下3张照片上:

在这里输入图像描述在这里输入图像描述在这里输入图像描述

下面的代码将显示我的意思。 只需编译并运行它。 然后按住CTRL ,并用鼠标在graphics上单击并按住。 现在尝试将graphics拖动到右侧或左侧。 经过一定的“拖拉距离”后,你会发现这个错误。

我的问题:如何防止/解决这个问题?

码:

  import org.jfree.chart.*; import org.jfree.chart.axis.*; import org.jfree.chart.plot.XYPlot; import org.jfree.chart.renderer.xy.CandlestickRenderer; import org.jfree.data.xy.*; import javax.swing.*; import java.awt.*; import java.io.*; import java.net.URL; import java.text.*; import java.util.*; import java.util.List; public class CandlestickDemo2 extends JFrame { public CandlestickDemo2(String stockSymbol) { super("CandlestickDemo"); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); DateAxis domainAxis = new DateAxis("Date"); NumberAxis rangeAxis = new NumberAxis("Price"); CandlestickRenderer renderer = new CandlestickRenderer(); XYDataset dataset = getDataSet(stockSymbol); XYPlot mainPlot = new XYPlot(dataset, domainAxis, rangeAxis, renderer); //Do some setting up, see the API Doc renderer.setSeriesPaint(0, Color.BLACK); renderer.setDrawVolume(false); rangeAxis.setAutoRangeIncludesZero(false); domainAxis.setTimeline( SegmentedTimeline.newMondayThroughFridayTimeline() ); //Now create the chart and chart panel JFreeChart chart = new JFreeChart(stockSymbol, null, mainPlot, false); ChartPanel chartPanel = new ChartPanel(chart, false); chartPanel.setPreferredSize(new Dimension(600, 300)); mainPlot.setDomainPannable(true); mainPlot.setRangePannable(true); this.add(chartPanel); this.pack(); } protected AbstractXYDataset getDataSet(String stockSymbol) { //This is the dataset we are going to create DefaultOHLCDataset result = null; //This is the data needed for the dataset OHLCDataItem[] data; //This is where we go get the data, replace with your own data source data = getData(stockSymbol); //Create a dataset, an Open, High, Low, Close dataset result = new DefaultOHLCDataset(stockSymbol, data); return result; } //This method uses yahoo finance to get the OHLC data protected OHLCDataItem[] getData(String stockSymbol) { List<OHLCDataItem> dataItems = new ArrayList<OHLCDataItem>(); try { String strUrl= "http://ichart.yahoo.com/table.csv?s=GOOG&a=2&b=1&c=2013&d=4&e=24&f=2013&g=d&ignore=.csv"; URL url = new URL(strUrl); BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream())); DateFormat df = new SimpleDateFormat("yMd"); String inputLine; in.readLine(); while ((inputLine = in.readLine()) != null) { StringTokenizer st = new StringTokenizer(inputLine, ","); Date date = df.parse( st.nextToken() ); double open = Double.parseDouble( st.nextToken() ); double high = Double.parseDouble( st.nextToken() ); double low = Double.parseDouble( st.nextToken() ); double close = Double.parseDouble( st.nextToken() ); double volume = Double.parseDouble( st.nextToken() ); double adjClose = Double.parseDouble( st.nextToken() ); OHLCDataItem item = new OHLCDataItem(date, open, high, low, close, volume); dataItems.add(item); } in.close(); } catch (Exception e) { e.printStackTrace(); } //Data from Yahoo is from newest to oldest. Reverse so it is oldest to newest Collections.reverse(dataItems); //Convert the list into an array OHLCDataItem[] data = dataItems.toArray(new OHLCDataItem[dataItems.size()]); return data; } public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { @Override public void run() { new CandlestickDemo2("GOOG").setVisible(true); } }); } } 

更新

这个bug现在是JFreeChart的sourceforge页面上的一个bug报告问题。

这个bug可以在这里跟踪。

我能够重现所描述的效果。 和以前一样 ,效果只能在SegmentedTimeline看到。 使用DefaultTimeline并不明显。 这似乎与在星期一到星期五时间线的“隐藏”周末拖延,但我没有看到一个明显的错误。

一种解决方法可能是让用户使用相邻控件selectTimeLine ,如本例中所示 。 由于DefaultTimelineprivate ,因此在调用控件的处理程序中的getTimeline()之前,需要保存getTimeline()的结果。

附录:下面是使用JCheckBox切换Timeline的程序的一个变体。 单击checkbox以启用SegmentedTimeline ; 水平平移以查看效果(按住Control键单击Windows;在Mac上单击选项)。

默认时间轴

分段时间轴

 import org.jfree.chart.*; import org.jfree.chart.axis.*; import org.jfree.chart.plot.XYPlot; import org.jfree.chart.renderer.xy.CandlestickRenderer; import org.jfree.data.xy.*; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.io.*; import java.net.URL; import java.text.*; import java.util.*; import java.util.List; /** * @see https://stackoverflow.com/a/18421887/230513 * @see http://www.jfree.org/forum/viewtopic.php?f=10&t=24521 */ public class CandlestickDemo2 extends JFrame { public CandlestickDemo2(String stockSymbol) { super("CandlestickDemo2"); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); final DateAxis domainAxis = new DateAxis("Date"); NumberAxis rangeAxis = new NumberAxis("Price"); CandlestickRenderer renderer = new CandlestickRenderer(); XYDataset dataset = getDataSet(stockSymbol); XYPlot mainPlot = new XYPlot(dataset, domainAxis, rangeAxis, renderer); //Do some setting up, see the API Doc renderer.setSeriesPaint(0, Color.BLACK); renderer.setDrawVolume(false); rangeAxis.setAutoRangeIncludesZero(false); //Now create the chart and chart panel JFreeChart chart = new JFreeChart(stockSymbol, null, mainPlot, false); ChartPanel chartPanel = new ChartPanel(chart, false); chartPanel.setPreferredSize(new Dimension(600, 300)); mainPlot.setDomainPannable(true); mainPlot.setRangePannable(true); this.add(chartPanel); // Add tiemline toggle final Timeline oldTimeline = domainAxis.getTimeline(); final Timeline newTimeline = SegmentedTimeline.newMondayThroughFridayTimeline(); this.add(new JCheckBox(new AbstractAction("Segmented Timeline") { @Override public void actionPerformed(ActionEvent e) { JCheckBox jcb = (JCheckBox) e.getSource(); if (jcb.isSelected()) { domainAxis.setTimeline(newTimeline); } else { domainAxis.setTimeline(oldTimeline); } } }), BorderLayout.SOUTH); this.pack(); this.setLocationRelativeTo(null); } private AbstractXYDataset getDataSet(String stockSymbol) { //This is the dataset we are going to create DefaultOHLCDataset result; //This is the data needed for the dataset OHLCDataItem[] data; //This is where we go get the data, replace with your own data source data = getData(stockSymbol); //Create a dataset, an Open, High, Low, Close dataset result = new DefaultOHLCDataset(stockSymbol, data); return result; } //This method uses yahoo finance to get the OHLC data protected OHLCDataItem[] getData(String stockSymbol) { List<OHLCDataItem> dataItems = new ArrayList<OHLCDataItem>(); try { String strUrl = "http://ichart.yahoo.com/table.csv?s=" + stockSymbol + "&a=4&b=1&c=2013&d=6&e=1&f=2013&g=d&ignore=.csv"; URL url = new URL(strUrl); BufferedReader in = new BufferedReader( new InputStreamReader(url.openStream())); DateFormat df = new SimpleDateFormat("yMd"); String inputLine; in.readLine(); while ((inputLine = in.readLine()) != null) { StringTokenizer st = new StringTokenizer(inputLine, ","); Date date = df.parse(st.nextToken()); double open = Double.parseDouble(st.nextToken()); double high = Double.parseDouble(st.nextToken()); double low = Double.parseDouble(st.nextToken()); double close = Double.parseDouble(st.nextToken()); double volume = Double.parseDouble(st.nextToken()); double adjClose = Double.parseDouble(st.nextToken()); OHLCDataItem item = new OHLCDataItem(date, open, high, low, close, volume); dataItems.add(item); } in.close(); } catch (Exception e) { e.printStackTrace(System.err); } //Data from Yahoo is from newest to oldest. Reverse so it is oldest to newest Collections.reverse(dataItems); //Convert the list into an array OHLCDataItem[] data = dataItems.toArray(new OHLCDataItem[dataItems.size()]); return data; } public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { @Override public void run() { new CandlestickDemo2("AAPL").setVisible(true); } }); } } 
Interesting Posts