Panning on PeriodAxis -- double rounding, range expanding

A discussion forum for JFreeChart (a 2D chart library for the Java platform).
Locked
medloh
Posts: 16
Joined: Tue May 07, 2013 11:26 pm
antibot: No, of course not.

Panning on PeriodAxis -- double rounding, range expanding

Post by medloh » Fri Jul 26, 2013 12:46 am

I was seeing weird behavior after enabling domain panning on a chart with a domain PeriodAxis. On each panning tick the chart's domain axis would grow a little bit. After some googling I found this post:

http://sourceforge.net/p/jfreechart/bugs/1089/

I subclassed PeriodAxis, overrode it's pan method and put some Sys.outs in it, and I am seeing something like the link above describes. In a nutshell, the Range of my PeriodAxis is expanding by exactley 60,000 every pan tick. I assume its due to Range's strictfp arithmetic??

Maybe this is fixed in the latest version of JFreeChart? But unfortunately we're kind of stuck with an older version of JFreeChart due to circumstances outside my control. So, I'm trying to determine the best way to fix it in my version. Interestingly, it kind of works if I just add 30,000 to the lower bound and subtract 30,000 from the upper bound. Any suggestions for a better fix? The link above suggests a fix, but I don't really understand how to implement it.

david.gilbert
JFreeChart Project Leader
Posts: 11734
Joined: Fri Mar 14, 2003 10:29 am
antibot: No, of course not.
Contact:

Re: Panning on PeriodAxis -- double rounding, range expandin

Post by david.gilbert » Fri Jul 26, 2013 1:05 pm

It is not fixed in the current release, but I will take a look at it and see if it can be fixed for the next release.
David Gilbert
JFreeChart Project Leader

:idea: Read my blog
:idea: Support JFree via the Github sponsorship program

medloh
Posts: 16
Joined: Tue May 07, 2013 11:26 pm
antibot: No, of course not.

Re: Panning on PeriodAxis -- double rounding, range expandin

Post by medloh » Fri Jul 26, 2013 6:43 pm

Here's the temporary fix I'm going with, that seems to work for our use case. Our PeriodAxis's Range is showing 16 minutes worth of data.

It's far from perfect, as it normalizes all spanning ticks to move the same amount, and assumes that adding 30000 to lower and subtracting 30000 to upper is ok to do. :lol:

Code: Select all


		PeriodAxis axisDomain = new PanFixPeriodAxis(null);
		axisDomain.setAutoRangeTimePeriodClass(Minute.class);
		axisDomain.setMajorTickTimePeriodClass(Minute.class);
                ...
		plot.setDomainAxis(axisDomain);


class PanFixPeriodAxis extends PeriodAxis
{

	public PanFixPeriodAxis(String label) {
		super(label);
	}
	
//    DecimalFormat df2 = new DecimalFormat( "#,###,###,###,##0.0000" ); // more readable debug stmts.
	
    /**
     * Slides the axis range by the specified percentage.
     *
     * @param percent  the percentage.
     * @since 1.0.13
     */
    public void pan(double percent)
    {
    	/* Problem -- Period Axis's range expands when panning due to strictfp double rounding
    	 * in Range class.  In our specific case, it expands by exactley 60,000 (1 minute?) each span tick.
    	 */

    	Range range = getRange();
    	//        double length = range.getLength();
    	//        double adj = length * percent;
    	//        long adj2 = (long)(adj);

    	double             adj =  60000;
    	if ( percent < 0 ) adj = -60000;

    	//System.out.println( "pan() percent=" + df2.format(percent) +
    	//		", lowerBound=" + df2.format(range.getLowerBound()) + ", upperBound=" + df2.format(range.getUpperBound()) +
    	//		", adj=" + df2.format(adj) + ", adj2=" + adj2 +  ", length=" + df2.format(length)  );   	

    	//        double lower = range.getLowerBound() + adj2;
    	//        double upper = range.getUpperBound() + adj2;
    	long lower = (long) (range.getLowerBound() + adj);
    	long upper = (long) (range.getUpperBound() + adj);

    	// horrible hack, but this kind of fixes it.        
    	upper -= 30000;
    	lower += 30000;

    	//        setRange(lower, upper);
    	setLowerBound( lower );
    	setUpperBound( upper );
    	Range r2 = getRange();

    	//        System.out.println( "New Vals: lower=" + df2.format(lower) +  ",    upper=" + df2.format(upper) );
    	//        System.out.println( "       r2.lower=" + df2.format(r2.getLowerBound()) + ", r2.upper" + df2.format(r2.getUpperBound()) +
    	//        		", length" + getRange().getLength() );   	
    }

}



medloh
Posts: 16
Joined: Tue May 07, 2013 11:26 pm
antibot: No, of course not.

Re: Panning on PeriodAxis -- double rounding, range expandin

Post by medloh » Fri Aug 09, 2013 10:00 pm

Just thought I'd pass on a slightly better solution we found for this problem. Turns out that panning worked much better using Seconds rather than Minutes. It still has rounding errors and expands most panning ticks, but the expansion is by the second instead of by the minute, so it's not so noticeable. We switched over to code like this and most of our panning problems went away:

Code: Select all

		PeriodAxis axisDomain = new PeriodAxis(null);
		axisDomain.setAutoRangeTimePeriodClass(Second.class);
		axisDomain.setMajorTickTimePeriodClass(Second.class);
		PeriodAxisLabelInfo[] info = new PeriodAxisLabelInfo[1];
		info[0] = new PeriodAxisLabelInfo(Second.class,
				new SimpleDateFormat("K:mm a"), new RectangleInsets(2, 2, 2, 2),
				new Font("SansSerif", Font.BOLD, 10), Color.blue, false,
				new BasicStroke(0.0f), Color.lightGray);
		axisDomain.setLabelInfo(info);
		plot.setDomainAxis(axisDomain);
The only issue after the change was the grid was showing way too many lines for our taste. Not sure if we solved that problem in the most elegant way, but we ended up overriding XYPlot's drawDomainGridlines() to only draw grid lines on minute boundries:

Code: Select all

					// Only show grid lines per minute
					if ( t%60000 == 0 )
					{	
					
					((AbstractXYItemRenderer) r).drawDomainLine(g2, this,
							getDomainAxis(), dataArea, tick.getValue(),
							gridPaint, gridStroke);
					}
and then we had to create our chart by calling a custom version ChartFactory.createTimeSeriesChart() that instantiated the custom XYPlot class instead of XYPlot.

Only thing left is to figure out how to customize the tick marks to what we want...

tukosito
Posts: 3
Joined: Mon Aug 19, 2013 10:34 am
antibot: No, of course not.

Re: Panning on PeriodAxis -- double rounding, range expandin

Post by tukosito » Fri Mar 21, 2014 4:04 pm

After facing the same problem I've found that setting the autorange time period class to Millisecond.class solved the issue:

PeriodAxis axis = ....
axis.setAutoRangeTimePeriodClass( Millisecond.class );

Note that even having set it to Millisecond I'm using the axis to display bigger periods (such as hours, days, etc) and still works fine. Note that I haven't tested the auto range feature in the chart because I use my own implementation.

Locked