Problems with new SamplingXYRenderer

A free public discussion forum for the JFreeChart class library.

Problems with new SamplingXYRenderer

Postby uvoigt » Wed Apr 22, 2009 10:33 am

Hi David,

I have tested the new SamplingXYRenderer for my purposes and found some issues. I have written a small test program to visualize the difference between the standard XYLineAndShapeRenderer and the new SamplingXYRenderer. As far as I have understood there should be no difference? The test program creates a dataset with lots of points and renderes this dataset with both renderers. If everything is ok only one color should be visible. The static variable showStandardRenderer switches the XYLineAndShapeRenderer on or off, so that only the new renderer is visible.

I think most of the problems are related to the handling of NaN values but I haven't gone into deep.
The legend is also a problem (only a black rectangle instead of blue is shown).

I hope that helps you to fix the problems soon. Please ask if something is not clear.

Ulrich

Code: Select all
import java.awt.BorderLayout;

import javax.swing.JPanel;
import javax.swing.JTabbedPane;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.StandardChartTheme;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.renderer.xy.SamplingXYLineRenderer;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.data.xy.XYDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.jfree.ui.ApplicationFrame;
import org.jfree.ui.RefineryUtilities;

public class SamplingXYRendererTest
    extends ApplicationFrame
{

    private static XYDataset datasetCopy;

    // set this to true to compare to the standard renderer with a red line
    private static final boolean showStandardRenderer = true;


    public SamplingXYRendererTest(String title)
    {
        super(title);

        XYDataset dataset = createDataset();
        final JFreeChart chart = createChart(dataset);
        ChartPanel chartPanel = new ChartPanel(chart);

        JPanel plPlot = new JPanel();
        plPlot.setLayout(new BorderLayout());
        plPlot.add(chartPanel, BorderLayout.CENTER);

        JPanel mainPanel = new JPanel();
        mainPanel.setLayout(new BorderLayout());
        JTabbedPane tabs = new JTabbedPane();
        tabs.addTab("Plot", plPlot);
        mainPanel.add(tabs, BorderLayout.CENTER);

        setContentPane(mainPanel);

    }

    private static JFreeChart createChart(XYDataset dataset)
    {
        ChartFactory.setChartTheme(StandardChartTheme.createLegacyTheme());
        JFreeChart chart = ChartFactory.createXYLineChart("XY Series Demo", "X", "Y", dataset,
            PlotOrientation.VERTICAL, true, false, false);

        SamplingXYLineRenderer renderer = new SamplingXYLineRenderer();
        XYLineAndShapeRenderer renderer2 = new XYLineAndShapeRenderer(true, false);

        chart.getXYPlot().setRenderer(0, renderer);

        if (showStandardRenderer)
        {
            chart.getXYPlot().setDataset(1, datasetCopy);
            chart.getXYPlot().setRenderer(1, renderer2);
        }

        return chart;
    }

    private static XYDataset createDataset()
    {
        XYSeries series = new XYSeries("Random Data 1");
        XYSeries seriesCopy = new XYSeries("Random Data Copy");
        double t = 0.0;
        double x = 0.0;
        for (int i = 0; i < 30000; i++)
        {
            double r = Math.random();
            if (r < 0.33)
            {
                x += Math.random();
            }
            else if (r < 0.66)
            {
                x -= Math.random();
            }
            if ((int)(r * 100) % 5 == 0)
            {
                series.add(t, Double.NaN);
                seriesCopy.add(t, Double.NaN);
            }
            else
            {
                series.add(t, x);
                seriesCopy.add(t, x);
            }
            t += Math.random();
        }

        t += Math.random();
        series.add(t, Double.NaN);
        seriesCopy.add(t, Double.NaN);

        datasetCopy = new XYSeriesCollection(seriesCopy);

        return new XYSeriesCollection(series);
    }

    public static JPanel createDemoPanel()
    {
        JFreeChart chart = createChart(createDataset());
        return new ChartPanel(chart);
    }

    public static void main(String[] args)
    {
        SamplingXYRendererTest demo = new SamplingXYRendererTest("SamplingXYRenderer Test");
        demo.pack();
        RefineryUtilities.centerFrameOnScreen(demo);
        demo.setVisible(true);

    }
}
uvoigt
 
Posts: 166
Joined: Mon Aug 23, 2004 10:50 am
Location: Germany

Re: Problems with new SamplingXYRenderer

Postby david.gilbert » Sat Apr 25, 2009 8:05 am

Thanks Ulrich, I'll take a look. You are probably right about the NaN values.
David Gilbert
JFreeChart Project Leader

:idea: Read my blog
:idea: Ask your company to buy the JFreeChart Developer Guide
:idea: Check out other products sold by my company Object Refinery Limited
david.gilbert
JFreeChart Project Leader
 
Posts: 11358
Joined: Fri Mar 14, 2003 10:29 am

Re: Problems with new SamplingXYRenderer

Postby paradoxoff » Sat Apr 25, 2009 8:35 am

Since I wanted to use the new renderer as well, I have tried to understand this behvaiour. It seems that the intervalPath (the vertical
line between the minimum and maximum y for a range of visually identical x values) is not drawn if there is a Double.NaN value within the range of "sampled" values. A patch is uploaded.
The missing legend shape has also been added.
Now, Ulrich program leads to the expected result: virtually identical lines for the SamplingXYLineRenderer and the XYLineAndShapeRenderer.
I did some benchmarking. Drawing the charts as PNG was 4x faster with the sampling renderer, and drawing to the Graphics2D of a BufferedImage was more than 10x faster! :)
paradoxoff
 
Posts: 1193
Joined: Sat Feb 17, 2007 1:51 pm

Re: Problems with new SamplingXYRenderer

Postby grimlock » Fri May 15, 2009 4:38 am

I'm having trouble getting tooltips to appear when using a SamplingXYLineRenderer, also noted in this thread: posting.php?mode=quote&f=3&p=76209

I think it is because in the drawItem() method in SamplingXYLineRenderer, there are no entities being added and hence no tooltip can be generated. Is this done on purpose as one of the speed up tricks of this renderer, or is this just an oversight?

I also noted the problem with the legend items being black boxes.

Otherwise, it is an excellent alternative renderer for large datasets.
grimlock
 
Posts: 22
Joined: Wed Jul 14, 2004 7:50 am

Re: Problems with new SamplingXYRenderer

Postby qzhang » Fri May 15, 2009 4:39 pm

I'm having problems with the SamplingXYLineRenderer, for the last values of the series, when there is a brutal change in the Y values. Depending on the size of the rendered image, a vertical line to the last point of the series may appear... or not.

Image
Image

This is a problem for graphs where the fact of viewing if a particular series goes back to 0 at the end is important. I think the SamplingXYItemRenderer should always draw the last value of the series to avoid this behavior.
qzhang
 
Posts: 3
Joined: Thu May 14, 2009 11:18 am

Re: Problems with new SamplingXYRenderer

Postby qzhang » Fri May 15, 2009 4:44 pm

grimlock wrote:I also noted the problem with the legend items being black boxes.


I have also noticed this legend problem. We found a way to correct it, by extending the SamplingXYItemRenderer, then in our new class we override the getLegendItem(...) method, like this :

Code: Select all
        @Override
   public LegendItem getLegendItem(int datasetIndex, int series) {
      final LegendItem wronglegendItem = super.getLegendItem(datasetIndex, series);

      String label = wronglegendItem.getLabel();
      String description = wronglegendItem.getDescription();
      String toolTipText = wronglegendItem.getToolTipText();
      String urlText = wronglegendItem.getURLText();
      
      Shape lineShape = this.getLegendLine();
      Stroke lineStroke = this.lookupSeriesStroke(series);
      Paint linePaint = this.lookupSeriesPaint(series);
      
      LegendItem correctLegendItem =  new LegendItem(label, description, toolTipText,
                urlText, lineShape, lineStroke, linePaint);
      
      
      return correctLegendItem;
   }
qzhang
 
Posts: 3
Joined: Thu May 14, 2009 11:18 am

Re: Problems with new SamplingXYRenderer

Postby donohoe » Mon Jun 08, 2009 6:36 pm

There is another bug - the OHLC are not reset when a new series is started (this causes the last series drawn to overlay the previous series). I've added this to the startSeriesPath method (also reset intervalpath for consistency).

Code: Select all
            this.intervalPath.reset();
            lastX = 0;
            openY = 0.0;
            highY = 0.0;
            lowY = 0.0;
            closeY = 0.0;


Also, adding a check for last item in the render takes care of the previous poster's valid point about always rendering the last point:

Code: Select all
if ((Math.abs(x - s.lastX) > s.dX) || item == s.getLastItemIndex()) {
donohoe
 
Posts: 2
Joined: Mon Jun 08, 2009 6:31 pm


Return to JFreeChart - General

Who is online

Users browsing this forum: Bing [Bot], Yahoo [Bot] and 19 guests