1.0.12 Infinite loop in DateAxis.refreshTicksHorizontal(...)

A discussion forum for JFreeChart (a 2D chart library for the Java platform).
avarvit
Posts: 3
Joined: Mon May 21, 2012 3:07 pm
antibot: No, of course not.

Re: 1.0.12 Infinite loop in DateAxis.refreshTicksHorizontal(

Post by avarvit » Wed May 23, 2012 2:15 pm

I tried both my fix and the fix in http://www.jfree.org/phpBB2/viewtopic.php?f=3&t=38026, and they both produce an ugly visual result. The reason is that the auto tick calculation does not take into account the fact that the timeline is segmented and thus (a) the ticks are more dense than they should because all calculations are done in a continuous time scale and excluded segments (e.g., weekends) are subtracted afterwards, and (b) that the ticks are un-evenly distributed, because other exception segments are not taken into account. I have come up with the following fix for both these errors circa line 1685 in DateAxis.java:

Code: Select all

                // begin avarvit patch
                if (timeline instanceof SegmentedTimeline) {
                	final SegmentedTimeline seg = (SegmentedTimeline) timeline;
                 	final long weekInMillis = 7 * 1000 * 3600 * 24;
                	if (weekInMillis == seg.getSegmentsGroupSize()) {
	                	final Calendar c1 = Calendar.getInstance(), c2 = Calendar.getInstance();
	                	c1.setTimeInMillis(currentTickTime);
	                	c2.setTimeInMillis(nextTickTime);
	                	final int w1 = c1.get(Calendar.DAY_OF_WEEK);
	                	final int w2 = c2.get(Calendar.DAY_OF_WEEK);
	                	c1.add (Calendar.DAY_OF_WEEK, -w1);
	                	c2.add (Calendar.DAY_OF_WEEK, -w2);
	                	final long fullWeeks = (c2.getTimeInMillis() - c1.getTimeInMillis()) / weekInMillis;
	                	nextTickTime += seg.getSegmentSize() * ((2 * fullWeeks) + w2 - w1);
                	}
                	else {
                    	nextTickTime = currentTickTime + (nextTickTime - currentTickTime) * seg.getSegmentsGroupSize() / seg.getSegmentsIncludedSize();
                	}
                	nextTickTime += seg.getSegmentSize() * seg.getExceptionSegmentCount(currentTickTime, nextTickTime);
                	tickDate = new Date(nextTickTime);
                }
                // end avarvit patch
Hope this helps!

kam
Posts: 1
Joined: Wed Dec 05, 2012 12:02 am
antibot: No, of course not.

Re: 1.0.12 Infinite loop in DateAxis.refreshTicksHorizontal(

Post by kam » Wed Dec 05, 2012 12:04 am

avarvit, thank you very much. Your solution works great!

lama_lel
Posts: 2
Joined: Thu Jan 10, 2013 2:58 pm
antibot: No, of course not.

Re: 1.0.12 Infinite loop in DateAxis.refreshTicksHorizontal(

Post by lama_lel » Thu Jan 10, 2013 3:04 pm

How to apply these changes to the lib? Or how to apply this changes to make it work?

timestored.com
Posts: 1
Joined: Fri Jun 28, 2013 6:48 pm
antibot: No, of course not.

Re: 1.0.12 Infinite loop in DateAxis.refreshTicksHorizontal(

Post by timestored.com » Fri Mar 07, 2014 1:27 am

Hi,

I think this bug is still present in 1.0.17, here's a code sample:

Code: Select all

package com.timestored.sqldash.chart;


import java.util.Date;

import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.DateAxis;
import org.jfree.chart.axis.DateTickUnit;
import org.jfree.chart.axis.DateTickUnitType;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.axis.SegmentedTimeline;
import org.jfree.chart.labels.HighLowItemLabelGenerator;
import org.jfree.chart.plot.CombinedDomainXYPlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.CandlestickRenderer;
import org.jfree.chart.renderer.xy.XYBarRenderer;
import org.jfree.data.time.Day;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;
import org.jfree.data.xy.DefaultHighLowDataset;
import org.jfree.data.xy.XYDataset;
import org.jfree.ui.ApplicationFrame;


public class CombinedXYPlotDemo1 extends ApplicationFrame {

    public CombinedXYPlotDemo1(final String title) {
        super(title);
        final JFreeChart chart = createCombinedChart();
        final ChartPanel panel = new ChartPanel(chart, true, true, true, false, true);
        setContentPane(panel);

    }

    private JFreeChart createCombinedChart() {

    	int n = 100;
    	final XYDataset  data1 = new DefaultHighLowDataset("Series 1", getDTS(n), arr(n, 5), arr(n, 2), 
    			arr(n, 3), arr(n, 4), arr(n, 100));

        // create dataset 2...
    	TimeSeriesCollection dataset2 = new TimeSeriesCollection();
    	TimeSeries tSeries = new TimeSeries("tlabel");
		for(int i=0; i<n; i++) {
			tSeries.addOrUpdate(new Day(new Date(90,1,i)), n+0.1);
		}
		dataset2.addSeries(tSeries);
		
		DateAxis timeAxis = new DateAxis("Date");
		// comment out the line below and no infinite loop occurs.
		timeAxis.setTimeline(SegmentedTimeline.newMondayThroughFridayTimeline());
		// or add these lines
//		timeAxis.setAutoTickUnitSelection(false);
//		timeAxis.setTickUnit(new DateTickUnit(DateTickUnitType.MONTH, 1));

		CandlestickRenderer candle = new CandlestickRenderer(4,false,new HighLowItemLabelGenerator());

		XYBarRenderer rr2 = new XYBarRenderer();
		XYPlot subplot1 = new XYPlot(data1, timeAxis, new NumberAxis("Price"), candle);
		XYPlot subplot2 = new XYPlot(dataset2, timeAxis, new NumberAxis("Volume"), rr2);

		CombinedDomainXYPlot plot = new CombinedDomainXYPlot(timeAxis);
		plot.add(subplot1, 3);
		plot.add(subplot2, 1);
		plot.setOrientation(PlotOrientation.VERTICAL);

        // return a new chart containing the overlaid plot...
        return new JFreeChart("CombinedDomainXYPlot Demo",
                              JFreeChart.DEFAULT_TITLE_FONT, plot, true);

    }


	public Date[] getDTS(int n) {
		Date[] dts = new Date[n];
    	for(int i=0; i<dts.length; i++) {
    		dts[i] = new Date(90,1,i);
    	}
		return dts;
	}

	public double[] arr(int length, double v) {
		double[] d = new double[length];
		for(int i=0; i<d.length; i++) {
			d[i] = v;
		}
		return d;
	}



    public static void main(final String[] args) {

        final CombinedXYPlotDemo1 demo = new CombinedXYPlotDemo1("CombinedDomainXYPlot Demo");
        demo.setSize(100, 100);
        demo.setVisible(true);

    }

}
And a big thanks to Dave for an excellent library.

Locked