Potential bug with setSeriesVisible on StackedXYBarRenderer

A free public discussion forum for the JFreeChart class library.

Potential bug with setSeriesVisible on StackedXYBarRenderer

Postby Kristian » Mon Jul 26, 2010 7:59 pm

This post relates to version 1.0.13, system does not seem to be relevent.

I'm attempting to do something similar to the HideSeriesDemoXs but using the StackedXYBarRenderer (i.e. have a chart where check boxes change the visibility of a series). When I swap the visibility of a series with setSeriesVisible I see the series dissapear (and reappear) from the key but the actual bars still stay. Is this the correct way?

The code should be similar to HideSeriesDemo1.java
Code: Select all
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JCheckBox;
import javax.swing.JPanel;

import org.jfree.chart.ChartPanel;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.StackedXYBarRenderer;
import org.jfree.chart.renderer.xy.XYItemRenderer;
import org.jfree.data.xy.DefaultTableXYDataset;
import org.jfree.data.xy.XYDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.ui.ApplicationFrame;
import org.jfree.ui.RefineryUtilities;

/**
* Illustrates that series in stack bars cannot be set to non visible
*/
public class DynamicSetVisibleOnStackedBars extends ApplicationFrame {
   private static final long serialVersionUID = 1L;
   
   static class MyDemoPanel extends JPanel implements ActionListener {
      private static final long serialVersionUID = 1L;
      
      private XYItemRenderer renderer;
      
      public MyDemoPanel() {
         super(new BorderLayout());
         XYDataset dataset = createSampleDataset();
         JFreeChart chart = createChart(dataset);
         ChartPanel chartPanel = new ChartPanel(chart);
         JPanel boxPanel = new JPanel();
         JCheckBox box1 = new JCheckBox("Series 1");
         box1.setActionCommand("S1");
         box1.addActionListener(this);
         box1.setSelected(true);
         JCheckBox box2 = new JCheckBox("Series 2");
         box2.setActionCommand("S2");
         box2.addActionListener(this);
         box2.setSelected(true);
         boxPanel.add(box1);
         boxPanel.add(box2);
         add(chartPanel);
         add(boxPanel, BorderLayout.SOUTH);
         chartPanel.setPreferredSize(new java.awt.Dimension(500, 270));
      }
      
      private XYDataset createSampleDataset() {
         DefaultTableXYDataset dataset = new DefaultTableXYDataset();
         
         XYSeries s1 = new XYSeries("Series 1", true, false);
         s1.add(1.0, 5.0);
         s1.add(2.0, 15.5);
         s1.add(3.0, 9.5);
         s1.add(4.0, 7.5);
         dataset.addSeries(s1);
         
         XYSeries s2 = new XYSeries("Series 2", true, false);
         s2.add(1, 5.0);
         s2.add(2, 15.5);
         s2.add(3, 9.5);
         s2.add(4, 3.5);
         dataset.addSeries(s2);
         
         return dataset;
      }
      
      private JFreeChart createChart(XYDataset dataset) {
         
         NumberAxis domainAxis = new NumberAxis("X");
         domainAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
         NumberAxis rangeAxis = new NumberAxis("Y");
         StackedXYBarRenderer renderer = new StackedXYBarRenderer(0.10);
         this.renderer = renderer;
         renderer.setDrawBarOutline(false);
         
         XYPlot plot = new XYPlot(dataset, domainAxis, rangeAxis, renderer);
         JFreeChart chart = new JFreeChart("Stacked XY Bar Chart Demo", plot);
         ChartUtilities.applyCurrentTheme(chart);
         return chart;
      }
      
      public void actionPerformed(ActionEvent e) {
         int series = -1;
         if (e.getActionCommand().equals("S1")) {
            series = 0;
         } else if (e.getActionCommand().equals("S2")) {
            series = 1;
         }
         
         if (series >= 0) {
            boolean visible = this.renderer.getItemVisible(series, 0);
            this.renderer.setSeriesVisible(series, new Boolean(!visible));
         }
      }
      
   }
   
   public DynamicSetVisibleOnStackedBars(String title) {
      super(title);
      setContentPane(new MyDemoPanel());
   }
   
   public static JPanel createDemoPanel() {
      return new MyDemoPanel();
   }
   
   public static void main(String[] args) {
      DynamicSetVisibleOnStackedBars demo = new DynamicSetVisibleOnStackedBars("JFreeChart: DynamicSetVisibleOnStackedBars.java");
      demo.pack();
      RefineryUtilities.centerFrameOnScreen(demo);
      demo.setVisible(true);
   }
   
}
Kristian
 
Posts: 7
Joined: Thu Aug 27, 2009 4:34 pm

Re: Potential bug with setSeriesVisible on StackedXYBarRenderer

Postby matinh » Tue Jul 27, 2010 7:13 am

Hi!

I'm not sure wheter it's a bug or a feature. When you set some series visible, others (which are stacked on the invisible series) migth look like "floating around". However, it would be simple to fix this behavior by just creating your own renderer derived from StackedXYBarRenderer and overwrite the drawItem() method like this:

Code: Select all
    public void drawItem(Graphics2D g2,
                         XYItemRendererState state,
                         Rectangle2D dataArea,
                         PlotRenderingInfo info,
                         XYPlot plot,
                         ValueAxis domainAxis,
                         ValueAxis rangeAxis,
                         XYDataset dataset,
                         int series,
                         int item,
                         CrosshairState crosshairState,
                         int pass) {
        if (!getItemVisible(series, item)) {
            return;
        }
        super.drawItem(g2, state, dataArea, info, plot, domainAxis, rangeAxis, dataset, series, item, crosshairState, pass);
    }

Could you please file a bug-report on the sourceforge.net project page and link back to this topic.

hth,
- martin
matinh
 
Posts: 471
Joined: Fri Aug 11, 2006 10:08 am
Location: Austria

Re: Potential bug with setSeriesVisible on StackedXYBarRenderer

Postby Kristian » Tue Jul 27, 2010 2:13 pm

Thanks for getting back to me so quickly.

Yeah your fix does get around part of the issue. But I think it might be nice to not have the series floating in the air :).

There is a bug report filed here: https://sourceforge.net/tracker/?func=d ... tid=115494.

EDIT: clean up
Last edited by Kristian on Tue Jul 27, 2010 2:23 pm, edited 1 time in total.
Kristian
 
Posts: 7
Joined: Thu Aug 27, 2009 4:34 pm

Re: Potential bug with setSeriesVisible on StackedXYBarRenderer

Postby Kristian » Tue Jul 27, 2010 2:21 pm

For clarity I have included sample of the proposed work around. If you hide series 2 you can see the issues most clearly.

Code: Select all
import java.awt.BorderLayout;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Rectangle2D;

import javax.swing.JCheckBox;
import javax.swing.JPanel;

import org.jfree.chart.ChartPanel;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.plot.CrosshairState;
import org.jfree.chart.plot.PlotRenderingInfo;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.StackedXYBarRenderer;
import org.jfree.chart.renderer.xy.XYItemRenderer;
import org.jfree.chart.renderer.xy.XYItemRendererState;
import org.jfree.data.xy.DefaultTableXYDataset;
import org.jfree.data.xy.XYDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.ui.ApplicationFrame;
import org.jfree.ui.RefineryUtilities;

/**
* Illustrates that series in stack bars cannot be set to non visible
*/
public class FloatingStackedBarsWorkAround extends ApplicationFrame {
   private static final long serialVersionUID = 1L;
   
   static class MyDemoPanel extends JPanel implements ActionListener {
      private static final long serialVersionUID = 1L;
      
      private XYItemRenderer renderer;
      
      public MyDemoPanel() {
         super(new BorderLayout());
         XYDataset dataset = createSampleDataset();
         JFreeChart chart = createChart(dataset);
         ChartPanel chartPanel = new ChartPanel(chart);
         
         JPanel boxPanel = new JPanel();
         JCheckBox box1 = new JCheckBox("Series 1");
         box1.setActionCommand("S1");
         box1.addActionListener(this);
         box1.setSelected(true);
         
         JCheckBox box2 = new JCheckBox("Series 2");
         box2.setActionCommand("S2");
         box2.addActionListener(this);
         box2.setSelected(true);
         
         JCheckBox box3 = new JCheckBox("Series 3");
         box3.setActionCommand("S3");
         box3.addActionListener(this);
         box3.setSelected(true);
         
         boxPanel.add(box1);
         boxPanel.add(box2);
         boxPanel.add(box3);
         
         add(chartPanel);
         add(boxPanel, BorderLayout.SOUTH);
         chartPanel.setPreferredSize(new java.awt.Dimension(500, 270));
      }
      
      private XYDataset createSampleDataset() {
         DefaultTableXYDataset dataset = new DefaultTableXYDataset();
         
         XYSeries s1 = new XYSeries("Series 1", true, false);
         s1.add(1.0, 5.0);
         s1.add(2.0, 15.5);
         s1.add(3.0, 9.5);
         s1.add(4.0, 7.5);
         dataset.addSeries(s1);
         
         XYSeries s2 = new XYSeries("Series 2", true, false);
         s2.add(1, 5.0);
         s2.add(2, 15.5);
         s2.add(3, 9.5);
         s2.add(4, 3.5);
         dataset.addSeries(s2);
         
         XYSeries s3 = new XYSeries("Series 3", true, false);
         s3.add(1, 5.0);
         s3.add(2, 15.5);
         s3.add(3, 9.5);
         s3.add(4, 3.5);
         dataset.addSeries(s3);
         
         return dataset;
      }
      
      private JFreeChart createChart(XYDataset dataset) {
         
         NumberAxis domainAxis = new NumberAxis("X");
         domainAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
         NumberAxis rangeAxis = new NumberAxis("Y");
         StackedXYBarRendererFloating renderer = new StackedXYBarRendererFloating(0.10);
         this.renderer = renderer;
         renderer.setDrawBarOutline(false);
         
         XYPlot plot = new XYPlot(dataset, domainAxis, rangeAxis, renderer);
         JFreeChart chart = new JFreeChart("Stacked XY Bar Chart Demo", plot);
         ChartUtilities.applyCurrentTheme(chart);
         return chart;
      }
      
      public void actionPerformed(ActionEvent e) {
         int series = -1;
         if (e.getActionCommand().equals("S1")) {
            series = 0;
         } else if (e.getActionCommand().equals("S2")) {
            series = 1;
         } else if (e.getActionCommand().equals("S3")) {
            series = 2;
         }
         
         if (series >= 0) {
            boolean visible = this.renderer.getItemVisible(series, 0);
            this.renderer.setSeriesVisible(series, new Boolean(!visible));
         }
      }
      
   }
   
   public FloatingStackedBarsWorkAround(String title) {
      super(title);
      setContentPane(new MyDemoPanel());
   }
   
   public static JPanel createDemoPanel() {
      return new MyDemoPanel();
   }
   
   public static void main(String[] args) {
      FloatingStackedBarsWorkAround demo = new FloatingStackedBarsWorkAround("JFreeChart: DynamicSetVisibleOnStackedBars.java");
      demo.pack();
      RefineryUtilities.centerFrameOnScreen(demo);
      demo.setVisible(true);
   }
   
   public static class StackedXYBarRendererFloating extends StackedXYBarRenderer {
      private static final long serialVersionUID = 1L;
      
      private StackedXYBarRendererFloating() {
         super();
      }
      
      private StackedXYBarRendererFloating(double margin) {
         super(margin);
      }
      
      public void drawItem(Graphics2D g2, XYItemRendererState state, Rectangle2D dataArea, PlotRenderingInfo info, XYPlot plot, ValueAxis domainAxis, ValueAxis rangeAxis, XYDataset dataset, int series, int item, CrosshairState crosshairState, int pass) {
         if (!getItemVisible(series, item)) {
            return;
         }
         super.drawItem(g2, state, dataArea, info, plot, domainAxis, rangeAxis, dataset, series, item, crosshairState, pass);
      }
   }
   
}



Edit: Clean up
Kristian
 
Posts: 7
Joined: Thu Aug 27, 2009 4:34 pm

Re: Potential bug with setSeriesVisible on StackedXYBarRenderer

Postby matinh » Tue Jul 27, 2010 3:29 pm

Hi Kristian!

Thanks for the bug reports. I had another quick look at the issue and produced a simple patch, that also fixes the "floating part" of invisible series. I'm not allowed to attach it to your issue, so I'll post it here:

Code: Select all

--- source/org/jfree/chart/renderer/xy/StackedXYBarRenderer.java        (revision 2273)
+++ source/org/jfree/chart/renderer/xy/StackedXYBarRenderer.java        (working copy)
@@ -246,6 +246,10 @@
                          CrosshairState crosshairState,
                          int pass) {

+        if (!getItemVisible(series, item)) {
+            return;
+        }
+
         if (!(dataset instanceof IntervalXYDataset
                 && dataset instanceof TableXYDataset)) {
             String message = "dataset (type " + dataset.getClass().getName()
@@ -290,7 +294,7 @@

         for (int i = 0; i < series; i++) {
             double v = dataset.getYValue(i, item);
-            if (!Double.isNaN(v)) {
+            if (!Double.isNaN(v) && isSeriesVisible(i)) {
                 if (this.renderAsPercentages) {
                     v = v / total;
                 }


hth,
- martin
matinh
 
Posts: 471
Joined: Fri Aug 11, 2006 10:08 am
Location: Austria

Re: Potential bug with setSeriesVisible on StackedXYBarRenderer

Postby Kristian » Tue Jul 27, 2010 6:31 pm

Great that seems to almost solve the problem. Maybe I just have an older version of the source but I need to add this as well otherwise the bottom most series is always visible.

this should be line 92 in StackedXYBarRenderer.drawItem()
Code: Select all

      IntervalXYDataset intervalDataset = (IntervalXYDataset) dataset;
      double value = intervalDataset.getYValue(series, item);
      if (Double.isNaN(value)) {
         return;
      }
-->
      IntervalXYDataset intervalDataset = (IntervalXYDataset) dataset;
      double value = intervalDataset.getYValue(series, item);
      if (Double.isNaN(value) || !isSeriesVisible(series)) {
         return;
      }

Kristian
 
Posts: 7
Joined: Thu Aug 27, 2009 4:34 pm

Re: Potential bug with setSeriesVisible on StackedXYBarRenderer

Postby matinh » Wed Jul 28, 2010 7:56 am

Hi Kristian!

I just tested again, and it seems to me that my original patch is working without your modifications. Are you sure, you applied the whole patch? If I left out the first part, I get the behavior described by you.

regards,
- martin
matinh
 
Posts: 471
Joined: Fri Aug 11, 2006 10:08 am
Location: Austria

Re: Potential bug with setSeriesVisible on StackedXYBarRenderer

Postby Kristian » Wed Jul 28, 2010 1:53 pm

Wow sorry to waste your time. You are correct I made the change manually and forgot to put in the first part of your change. The fix you gave works fine.

EDIT: for clarity.
Kristian
 
Posts: 7
Joined: Thu Aug 27, 2009 4:34 pm


Return to JFreeChart - General

Who is online

Users browsing this forum: Bing [Bot], Exabot [Bot], Google [Bot] and 13 guests