JFreechart Candlestick-Diagramm seltsames Verhalten beim Ziehen

Dies ist eine Folgefrage aus dieser Frage .

Was passiert, ist folgendes:

Wenn ich den Graphen starte und den Graphen herumschiebe, passiert etwas Seltsames: In einem bestimmten Intervall scheint es alle 7 Perioden, die Candlesticks werden kleiner und kleiner, bis sie nur noch ein Streifen sind. Wenn ich dann weiter ziehe, werden sie wieder dicker, bis sie wieder normale Größe haben. Dies scheint für alle 7 Perioden zu geschehen.

Ein Beispiel für dieses Phänomen ist auf den folgenden 3 Bildern dargestellt:

Bildbeschreibung hier eingebenBildbeschreibung hier eingebenBildbeschreibung hier eingeben

Der folgende Code zeigt genau, was ich meine. Einfach kompilieren und ausführen. Dann drücken und halten Sie CTRL und klicken und halten Sie mit der Maus auf das Diagramm. Versuchen Sie nun, den Graphen nach rechts oder links zu ziehen. Nach einer gewissen “Schleppdistanz” werden Sie den Fehler bemerken.

Meine Frage: Wie verhindere ich das?

Code:

  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 dataItems = new ArrayList(); 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); } }); } } 

Aktualisieren

Dieser Bug ist jetzt ein gemeldeter Fehler auf der Sourceforge-Seite von JFreeChart.

Dieser Fehler kann hier verfolgt werden .

    Ich kann den beschriebenen Effekt reproduzieren. Wie zuvor wird der Effekt nur mit einer SegmentedTimeline . Es ist nicht offensichtlich mit der DefaultTimeline . Es scheint mit dem Ziehen über die “versteckten” Wochenenden einer Montag-bis-Freitag-Timeline zusammenzufallen , aber ich sehe keinen offensichtlichen Fehler.

    Eine Umgehungslösung könnte darin bestehen, den Benutzer die TimeLine mithilfe eines benachbarten Steuerelements auswählen zu lassen, wie in diesem Beispiel vorgeschlagen . Da DefaultTimeline private , müssen Sie das Ergebnis von getTimeline() setTimeline() bevor Sie setTimeline() im Handler des Steuerelements aufrufen.

    Nachtrag: Hier ist eine Variation des Programms, das eine JCheckBox um die Timeline JCheckBox . Klicken Sie auf das Kontrollkästchen, um die SegmentedTimeline zu aktivieren. Schwenken Sie horizontal, um den Effekt zu sehen (Control-Klick auf Windows; Option-Klick auf Mac).

    Standardzeitleiste

    Segmentierte Zeitleiste

     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 dataItems = new ArrayList(); 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); } }); } }