"Tooltip" behavior in StackAareaChart..is there a

A discussion forum for JFreeChart (a 2D chart library for the Java platform).
Locked
deepika
Posts: 13
Joined: Fri May 13, 2005 2:00 pm

"Tooltip" behavior in StackAareaChart..is there a

Post by deepika » Thu Nov 30, 2006 2:51 pm

Hi Everyone,

I am trying to create a stacked area chart using ChartFactory.createStackedAreaChart() with CategoryDataset. But to my surprise, tooltip behaves very different compared to using ChartFactory.createAreaChart() with CategoryDataset. When I say it behaves different, I mean that for formar case, I have to move the mouse to the (X,Y) intersection to display the tooltip while later displays the tooltip no matter where the mouse is on the chart. Is it possible that there is some kind of bug in ChartFactory.createAreaChart()?

I am using Jfreechart version 1.0.3. I am also attaching the sample example I am working with.

Can anyone please help me here. This is really urgent. I have to use CategoryDataset because the values on the X-axis are strings( NOT numbers). Any suggestion on as to how could I get tooltips working in the same way as it does for ChartFactory.createAreaChart().

Thanks,
Deepika


/* ------------------
* AreaChartDemo.java
* ------------------
* (C) Copyright 2002-2005, by Object Refinery Limited.
*
*/

package demo;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;

import javax.swing.JPanel;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.CategoryAxis;
import org.jfree.chart.axis.CategoryLabelPositions;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.title.TextTitle;
import org.jfree.data.category.CategoryDataset;
import org.jfree.data.category.DefaultCategoryDataset;
import org.jfree.ui.ApplicationFrame;
import org.jfree.ui.RectangleEdge;
import org.jfree.ui.RectangleInsets;
import org.jfree.ui.RefineryUtilities;
import org.jfree.ui.VerticalAlignment;
import org.jfree.util.UnitType;

/**
* A simple demonstration application showing how to create an area chart
* using data from a {@link CategoryDataset}.
*/
public class DeepikaStackedAreaChartDemo1 extends ApplicationFrame {

/**
* Creates a new demo application.
*
* @param title the frame title.
*/
public DeepikaStackedAreaChartDemo1(String title) {

super(title);
CategoryDataset dataset = createDataset();
JFreeChart chart = createChart(dataset);
ChartPanel chartPanel = new ChartPanel(chart);
chartPanel.setPreferredSize(new Dimension(500, 270));
chartPanel.setEnforceFileExtensions(false);
setContentPane(chartPanel);

}

/**
* Creates a sample dataset.
*
* @return A sample dataset.
*/
private static CategoryDataset createDataset() {
DefaultCategoryDataset dataset = new DefaultCategoryDataset();
dataset.addValue(1.0, "Series 1", "Type 1");
dataset.addValue(4.0, "Series 1", "Type 2");
dataset.addValue(3.0, "Series 1", "Type 3");
dataset.addValue(5.0, "Series 1", "Type 4");
dataset.addValue(5.0, "Series 1", "Type 5");
dataset.addValue(7.0, "Series 1", "Type 6");
dataset.addValue(7.0, "Series 1", "Type 7");
dataset.addValue(8.0, "Series 1", "Type 8");
dataset.addValue(5.0, "Series 2", "Type 1");
dataset.addValue(7.0, "Series 2", "Type 2");
dataset.addValue(6.0, "Series 2", "Type 3");
dataset.addValue(8.0, "Series 2", "Type 4");
dataset.addValue(4.0, "Series 2", "Type 5");
dataset.addValue(4.0, "Series 2", "Type 6");
dataset.addValue(2.0, "Series 2", "Type 7");
dataset.addValue(1.0, "Series 2", "Type 8");
dataset.addValue(4.0, "Series 3", "Type 1");
dataset.addValue(3.0, "Series 3", "Type 2");
dataset.addValue(2.0, "Series 3", "Type 3");
dataset.addValue(3.0, "Series 3", "Type 4");
dataset.addValue(6.0, "Series 3", "Type 5");
dataset.addValue(3.0, "Series 3", "Type 6");
dataset.addValue(4.0, "Series 3", "Type 7");
dataset.addValue(3.0, "Series 3", "Type 8");
return dataset;
}
/**
* Creates a chart.
*
* @param dataset the dataset.
*
* @return The chart.
*/
private static JFreeChart createChart(CategoryDataset dataset) {

JFreeChart chart = ChartFactory.createStackedAreaChart(
"Area Chart", // chart title
"Category", // domain axis label
"Value", // range axis label
dataset, // data
PlotOrientation.VERTICAL, // orientation
true, // include legend
true, // tooltips
false // urls
);

// NOW DO SOME OPTIONAL CUSTOMISATION OF THE CHART...
chart.setBackgroundPaint(Color.white);
TextTitle subtitle = new TextTitle(
"An area chart demonstration. We use this subtitle as an "
+ "example of what happens when you get a really long title or "
+ "subtitle."
);
subtitle.setFont(new Font("SansSerif", Font.PLAIN, 12));
subtitle.setPosition(RectangleEdge.TOP);
subtitle.setPadding(
new RectangleInsets(UnitType.RELATIVE, 0.05, 0.05, 0.05, 0.05)
);
subtitle.setVerticalAlignment(VerticalAlignment.BOTTOM);
chart.addSubtitle(subtitle);

CategoryPlot plot = chart.getCategoryPlot();
plot.setForegroundAlpha(0.5f);

plot.setAxisOffset(new RectangleInsets(5.0, 5.0, 5.0, 5.0));
plot.setBackgroundPaint(Color.lightGray);
plot.setDomainGridlinesVisible(true);
plot.setDomainGridlinePaint(Color.white);
plot.setRangeGridlinesVisible(true);
plot.setRangeGridlinePaint(Color.white);

CategoryAxis domainAxis = plot.getDomainAxis();
domainAxis.setCategoryLabelPositions(CategoryLabelPositions.UP_45);
domainAxis.setLowerMargin(0.0);
domainAxis.setUpperMargin(0.0);
domainAxis.addCategoryLabelToolTip("Type 1", "The first type.");
domainAxis.addCategoryLabelToolTip("Type 2", "The second type.");
domainAxis.addCategoryLabelToolTip("Type 3", "The third type.");

NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
rangeAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
rangeAxis.setLabelAngle(0 * Math.PI / 2.0);
// OPTIONAL CUSTOMISATION COMPLETED.

return chart;

}

/**
* Creates a panel for the demo (used by SuperDemo.java).
*
* @return A panel.
*/
public static JPanel createDemoPanel() {
JFreeChart chart = createChart(createDataset());
return new ChartPanel(chart);
}

/**
* Starting point for the demonstration application when it is run as
* a stand-alone application.
*
* @param args ignored.
*/
public static void main(String[] args) {

DeepikaStackedAreaChartDemo1 demo = new DeepikaStackedAreaChartDemo1("Area Chart Demo");
demo.pack();
RefineryUtilities.centerFrameOnScreen(demo);
demo.setVisible(true);

}

}
Thanks & Regards,
Deepika

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

Post by david.gilbert » Thu Nov 30, 2006 3:17 pm

This is a limitation of the renderer. Fixing it will require quite a big change in the way that the area shapes are being generated. That will be a good thing, because at the same time I can fix the handling of negative values (which is currently broken). I can't promise when I'll find the time to do this though...but hopefully before 1.0.4.
David Gilbert
JFreeChart Project Leader

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

deepika
Posts: 13
Joined: Fri May 13, 2005 2:00 pm

Post by deepika » Thu Nov 30, 2006 4:18 pm

Thanks Dave. I appreciate your response.

I would like to offer my help and try to get it fixed. Could you provide me some pointers/directions. Would it be along the implementation of StackedXYAreaRenderer2.java?

Also, I have another question. I am also using a Time series chart as follows. I am passing TimeTableXYDataset to it.

JFreeChart chart = ChartFactory.createTimeSeriesChart(
title, // chart title
xAxisLabel, // domain axis label
yAxisLabel, // range axis label
dataset, // data
// PlotOrientation.VERTICAL, // the plot orientation
true, // legend
true, // tooltips
false // urls
);


XYPlot plot = (XYPlot) chart.getPlot();
plot.setRenderer(renderer);

DateAxis axis = (DateAxis) plot.getDomainAxis();
axis.setDateFormatOverride(new SimpleDateFormat("MMM-yyyy"));
plot.setOrientation(orientation);

//Controls the alpha-transparency of the plot (Doesn't use solid colors)
plot.setForegroundAlpha(0.5f);
plot.setBackgroundPaint(Color.white);
// plot.setDomainGridlinePaint(Color.lightGray);
// plot.setRangeGridlinePaint(Color.lightGray);

plot.setRangeAxis(yAxis); // forces recalculation of the axis range

chart.setBackgroundPaint(new Color(236, 248, 255));
chart.addSubtitle(new TextTitle(subTitle));

The tooltip seems to work fine when I run this code in an applet (The tooltip is displayed at every point within the chart). But when I save this as .png image, get its ImageMap and display in browser, the tooltip don't seem to work that nice. They are displayed only at certain points which makes it hard and less useful when dataset is not very small.

Below is the ImageMap that is used by browser.

<map id="jfreechart-6512.png" name="jfreechart-6512.png">
<area shape="poly" coords="974,554,974,620,917,620,917,580,917,580,974,620,974,554,974,554,974,620,974,620" title="series 1, Sep-2006 = 794" alt=""/>
<area shape="poly" coords="860,605,860,620,803,620,803,605,803,605,860,620,860,605,917,580,917,620,917,620" title="series 1, Aug-2006 = 180" alt=""/>
<area shape="poly" coords="746,605,746,620,691,620,691,605,691,605,746,620,746,605,803,605,803,620,803,620" title="series 1, Jul-2006 = 179" alt=""/>
<area shape="poly" coords="636,605,636,620,579,620,579,606,579,606,636,620,636,605,691,605,691,620,691,620" title="series 1, Jun-2006 = 174" alt=""/>
<area shape="poly" coords="522,606,522,620,467,620,467,606,467,606,522,620,522,606,579,606,579,620,579,620" title="series 1, May-2006 = 169" alt=""/>
<area shape="poly" coords="411,606,411,620,355,620,355,606,355,606,411,620,411,606,467,606,467,620,467,620" title="series 1, Apr-2006 = 166" alt=""/>
<area shape="poly" coords="298,606,298,620,246,620,246,606,246,606,298,620,298,606,355,606,355,620,355,620" title="series 1, Mar-2006 = 164" alt=""/>
<area shape="poly" coords="195,606,195,620,138,620,138,607,138,607,195,620,195,606,246,606,246,620,246,620" title="series 1, Feb-2006 = 163" alt=""/>
<area shape="poly" coords="81,607,81,620,81,620,81,607,81,607,81,620,81,607,138,607,138,620,138,620" title="series 1, Jan-2006 = 159" alt=""/>
<area shape="poly" coords="974,553,974,554,917,580,917,578,917,578,974,554,974,553,974,553,974,554,974,554" title="series 2, Sep-2006 = 19" alt=""/>
<area shape="poly" coords="860,603,860,605,803,605,803,603,803,603,860,605,860,603,917,578,917,580,917,580" title="series 2, Aug-2006 = 19" alt=""/>
<area shape="poly" coords="746,603,746,605,691,605,691,604,691,604,746,605,746,603,803,603,803,605,803,605" title="series 2, Jul-2006 = 19" alt=""/>

<area shape="poly" coords="636,604,636,605,579,606,579,604,579,604,636,605,636,604,691,604,691,605,691,605" title="series 2, Jun-2006 = 18" alt=""/>
<area shape="poly" coords="522,604,522,606,467,606,467,605,467,605,522,606,522,604,579,604,579,606,579,606" title="series 2, May-2006 = 17" alt=""/>
<area shape="poly" coords="411,605,411,606,355,606,355,605,355,605,411,606,411,605,467,605,467,606,467,606" title="series 2, Apr-2006 = 17" alt=""/>
<area shape="poly" coords="298,605,298,606,246,606,246,605,246,605,298,606,298,605,355,605,355,606,355,606" title="series 2, Mar-2006 = 18" alt=""/>
<area shape="poly" coords="195,605,195,606,138,607,138,605,138,605,195,606,195,605,246,605,246,606,246,606" title="series 2, Feb-2006 = 22" alt=""/>
<area shape="poly" coords="81,605,81,607,81,607,81,605,81,605,81,607,81,605,138,605,138,607,138,607" title="series 2, Jan-2006 = 22" alt=""/>
<area shape="poly" coords="974,71,974,553,917,578,917,103,917,103,974,553,974,71,974,71,974,553,974,553" title="series 3, Sep-2006 = 5826" alt=""/>
<area shape="poly" coords="860,135,860,603,803,603,803,135,803,135,860,603,860,135,917,103,917,578,917,578" title="series 3, Aug-2006 = 5665" alt=""/>
<area shape="poly" coords="746,135,746,603,691,604,691,137,691,137,746,603,746,135,803,135,803,603,803,603" title="series 3, Jul-2006 = 5665" alt=""/>
<area shape="poly" coords="636,138,636,604,579,604,579,142,579,142,636,604,636,138,691,137,691,604,691,604" title="series 3, Jun-2006 = 5631" alt=""/>
<area shape="poly" coords="522,147,522,604,467,605,467,150,467,150,522,604,522,147,579,142,579,604,579,604" title="series 3, May-2006 = 5538" alt=""/>
<area shape="poly" coords="411,153,411,605,355,605,355,154,355,154,411,605,411,153,467,150,467,605,467,605" title="series 3, Apr-2006 = 5462" alt=""/>
<area shape="poly" coords="298,154,298,605,246,605,246,149,246,149,298,605,298,154,355,154,355,605,355,605" title="series 3, Mar-2006 = 5451" alt=""/>
<area shape="poly" coords="195,145,195,605,138,605,138,146,138,146,195,605,195,145,246,149,246,605,246,605" title="series 3, Feb-2006 = 5563" alt=""/>
<area shape="poly" coords="81,148,81,605,81,605,81,148,81,148,81,605,81,148,138,146,138,605,138,605" title="series 3, Jan-2006 = 5524" alt=""/>
</map>

If you carefully see the coords, you'll notice that some of the X,Y coords are repeated. Is this a problem? Is there any way to get the tooltips working in the same way as they do inside applet?

Thanks & Regards,
Deepika
Thanks & Regards,
Deepika

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

Post by david.gilbert » Thu Nov 30, 2006 4:36 pm

deepika wrote:I would like to offer my help and try to get it fixed. Could you provide me some pointers/directions. Would it be along the implementation of StackedXYAreaRenderer2.java?
Yes, exactly the same approach should work. I'm having a quick look at it now, maybe it won't take so long to do it...
David Gilbert
JFreeChart Project Leader

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

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

Post by david.gilbert » Thu Nov 30, 2006 6:40 pm

I've translated the code from StackedXYAreaRenderer2, and it mostly works, but during testing I found a bug that affects both renderers and will take a bit more time to fix.
David Gilbert
JFreeChart Project Leader

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

deepika
Posts: 13
Joined: Fri May 13, 2005 2:00 pm

Post by deepika » Wed Jan 10, 2007 7:25 pm

Hi David,

Which files have you updated for this fix. I looked at the StackedAreaRenderer.java but that seems to be the old version.

Thanks,
Deepika
Thanks & Regards,
Deepika

deepika
Posts: 13
Joined: Fri May 13, 2005 2:00 pm

Post by deepika » Thu Mar 01, 2007 5:00 pm

Hi David,

I downloaded the latest version of Jfreechart 1.0.4 but I still don't find the changes you mentioned in your below note. The last time StackedAreaRenderer.java was updated is 2006-10-11 but according to your note, it should have been updated on 2006-11-30 again.

Could you please help me and send me the changes you made in order for tooltip to behave in the same manner as they do when someone uses StackedXYAreaRenderer2.

I greatly appreciate your help.

Thanks,
Deepika
Thanks & Regards,
Deepika

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

Post by david.gilbert » Thu Mar 01, 2007 5:05 pm

This is what I have at present - I haven't committed it to CVS because it doesn't work properly yet. Feel free to mess about with it - I'll hopefully get back to fixing it soon:

Code: Select all

/* ===========================================================
 * JFreeChart : a free chart library for the Java(tm) platform
 * ===========================================================
 *
 * (C) Copyright 2000-2006, by Object Refinery Limited and Contributors.
 *
 * Project Info:  http://www.jfree.org/jfreechart/index.html
 *
 * This library is free software; you can redistribute it and/or modify it 
 * under the terms of the GNU Lesser General Public License as published by 
 * the Free Software Foundation; either version 2.1 of the License, or 
 * (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but 
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 
 * License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
 * USA.  
 *
 * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 
 * in the United States and other countries.]
 *
 * ------------------------
 * StackedAreaRenderer.java
 * ------------------------
 * (C) Copyright 2002-2006, by Dan Rivett (d.rivett@ukonline.co.uk) and 
 *                          Contributors.
 *
 * Original Author:  Dan Rivett (adapted from AreaCategoryItemRenderer);
 * Contributor(s):   Jon Iles;
 *                   David Gilbert (for Object Refinery Limited);
 *                   Christian W. Zuckschwerdt;
 *
 * $Id: StackedAreaRenderer.java,v 1.6.2.3 2006/10/11 16:25:50 mungady Exp $
 *
 * Changes:
 * --------
 * 20-Sep-2002 : Version 1, contributed by Dan Rivett;
 * 24-Oct-2002 : Amendments for changes in CategoryDataset interface and 
 *               CategoryToolTipGenerator interface (DG);
 * 01-Nov-2002 : Added tooltips (DG);
 * 06-Nov-2002 : Renamed drawCategoryItem() --> drawItem() and now using axis 
 *               for category spacing. Renamed StackedAreaCategoryItemRenderer 
 *               --> StackedAreaRenderer (DG);
 * 26-Nov-2002 : Switched CategoryDataset --> TableDataset (DG);
 * 26-Nov-2002 : Replaced isStacked() method with getRangeType() method (DG);
 * 17-Jan-2003 : Moved plot classes to a separate package (DG);
 * 25-Mar-2003 : Implemented Serializable (DG);
 * 13-May-2003 : Modified to take into account the plot orientation (DG);
 * 30-Jul-2003 : Modified entity constructor (CZ);
 * 07-Oct-2003 : Added renderer state (DG);
 * 29-Apr-2004 : Added getRangeExtent() override (DG);
 * 05-Nov-2004 : Modified drawItem() signature (DG);
 * 07-Jan-2005 : Renamed getRangeExtent() --> findRangeBounds() (DG);
 * ------------- JFREECHART 1.0.x ---------------------------------------------
 * 11-Oct-2006 : Added support for rendering data values as percentages,
 *               and added a second pass for drawing item labels (DG);
 * 
 */

package org.jfree.chart.renderer.category;

import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.Shape;
import java.awt.geom.GeneralPath;
import java.awt.geom.Rectangle2D;
import java.io.Serializable;

import org.jfree.chart.axis.CategoryAxis;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.entity.EntityCollection;
import org.jfree.chart.event.RendererChangeEvent;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.data.DataUtilities;
import org.jfree.data.Range;
import org.jfree.data.category.CategoryDataset;
import org.jfree.data.general.DatasetUtilities;
import org.jfree.ui.RectangleEdge;
import org.jfree.util.PublicCloneable;

/**
 * A renderer that draws stacked area charts for a 
 * {@link org.jfree.chart.plot.CategoryPlot}.
 */
public class StackedAreaRenderer extends AreaRenderer 
                                 implements Cloneable, PublicCloneable, 
                                            Serializable {

    /** For serialization. */
    private static final long serialVersionUID = -3595635038460823663L;
     
    /** A flag that controls whether the areas display values or percentages. */
    private boolean renderAsPercentages;
    
    /**
     * Creates a new renderer.
     */
    public StackedAreaRenderer() {
        this(false);
    }
    
    /**
     * Creates a new renderer.
     * 
     * @param renderAsPercentages  a flag that controls whether the data values
     *                             are rendered as percentages.
     */
    public StackedAreaRenderer(boolean renderAsPercentages) {
        super();
        this.renderAsPercentages = renderAsPercentages;
    }

    /**
     * Returns <code>true</code> if the renderer displays each item value as
     * a percentage (so that the stacked areas add to 100%), and 
     * <code>false</code> otherwise.
     * 
     * @return A boolean.
     *
     * @since 1.0.3
     */
    public boolean getRenderAsPercentages() {
        return this.renderAsPercentages;   
    }
    
    /**
     * Sets the flag that controls whether the renderer displays each item
     * value as a percentage (so that the stacked areas add to 100%), and sends
     * a {@link RendererChangeEvent} to all registered listeners.
     * 
     * @param asPercentages  the flag.
     *
     * @since 1.0.3
     */
    public void setRenderAsPercentages(boolean asPercentages) {
        this.renderAsPercentages = asPercentages; 
        notifyListeners(new RendererChangeEvent(this));
    }
    
    /**
     * Returns the number of passes (<code>2</code>) required by this renderer. 
     * The first pass is used to draw the bars, the second pass is used to
     * draw the item labels (if visible).
     * 
     * @return The number of passes required by the renderer.
     */
    public int getPassCount() {
        return 2;
    }

    /**
     * Returns the range of values the renderer requires to display all the 
     * items from the specified dataset.
     * 
     * @param dataset  the dataset (<code>null</code> not permitted).
     * 
     * @return The range (or <code>null</code> if the dataset is empty).
     */
    public Range findRangeBounds(CategoryDataset dataset) {
        if (this.renderAsPercentages) {
            return new Range(0.0, 1.0);   
        }
        else {
            return DatasetUtilities.findStackedRangeBounds(dataset);
        }
    }

    /**
     * Draw a single data item.
     *
     * @param g2  the graphics device.
     * @param state  the renderer state.
     * @param dataArea  the data plot area.
     * @param plot  the plot.
     * @param domainAxis  the domain axis.
     * @param rangeAxis  the range axis.
     * @param dataset  the data.
     * @param row  the row index (zero-based).
     * @param column  the column index (zero-based).
     * @param pass  the pass index.
     */
    public void drawItem(Graphics2D g2,
                         CategoryItemRendererState state,
                         Rectangle2D dataArea,
                         CategoryPlot plot,
                         CategoryAxis domainAxis,
                         ValueAxis rangeAxis,
                         CategoryDataset dataset,
                         int row,
                         int column,
                         int pass) {

        // setup for collecting optional entity info...
        Shape entityArea = null;
        EntityCollection entities = state.getEntityCollection();
        
        double y1 = 0.0;
        Number n = dataset.getValue(row, column);
        if (n != null) {
            y1 = n.doubleValue();
        }        
        double[] stack1 = getStackValues(dataset, row, column);


        // leave the y values (y1, y0) untranslated as it is going to be be 
        // stacked up later by previous series values, after this it will be 
        // translated.
        double xx1 = domainAxis.getCategoryMiddle(column, getColumnCount(), 
                dataArea, plot.getDomainAxisEdge());
        
        
        // get the previous point and the next point so we can calculate a 
        // "hot spot" for the area (used by the chart entity)...
        double y0 = 0.0;
        n = dataset.getValue(row, Math.max(column - 1, 0));
        if (n != null) {
            y0 = n.doubleValue();
        }
        double[] stack0 = getStackValues(dataset, row, Math.max(column - 1, 0));

        // FIXME: calculate xx0
        double xx0 = domainAxis.getCategoryStart(column, getColumnCount(), 
                dataArea, plot.getDomainAxisEdge());
        
        int itemCount = dataset.getColumnCount();
        double y2 = 0.0;
        n = dataset.getValue(row, Math.min(column + 1, itemCount - 1));
        if (n != null) {
            y2 = n.doubleValue();
        }
        double[] stack2 = getStackValues(dataset, row, Math.min(column + 1, 
                itemCount - 1));

        double xx2 = domainAxis.getCategoryEnd(column, getColumnCount(), 
                dataArea, plot.getDomainAxisEdge());
        
        // FIXME: calculate xxLeft and xxRight
        double xxLeft = xx0;
        double xxRight = xx2;
        
        double[] stackLeft = averageStackValues(stack0, stack1);
        double[] stackRight = averageStackValues(stack1, stack2);
        double[] adjStackLeft = adjustedStackValues(stack0, stack1);
        double[] adjStackRight = adjustedStackValues(stack1, stack2);

        float transY1;
        
        RectangleEdge edge1 = plot.getRangeAxisEdge();
        
        GeneralPath left = new GeneralPath();
        GeneralPath right = new GeneralPath();
        if (y1 >= 0.0) {  // handle positive value
            transY1 = (float) rangeAxis.valueToJava2D(y1 + stack1[1], dataArea, 
                    edge1);
            float transStack1 = (float) rangeAxis.valueToJava2D(stack1[1], 
                    dataArea, edge1);
            float transStackLeft = (float) rangeAxis.valueToJava2D(
                    adjStackLeft[1], dataArea, edge1);
            
            // LEFT POLYGON
            if (y0 >= 0.0) {
                double yleft = (y0 + y1) / 2.0 + stackLeft[1];
                float transYLeft 
                    = (float) rangeAxis.valueToJava2D(yleft, dataArea, edge1);
                left.moveTo((float) xx1, transY1);
                left.lineTo((float) xx1, transStack1);
                left.lineTo((float) xxLeft, transStackLeft);
                left.lineTo((float) xxLeft, transYLeft);
                left.closePath();
            }
            else {
                left.moveTo((float) xx1, transStack1);
                left.lineTo((float) xx1, transY1);
                left.lineTo((float) xxLeft, transStackLeft);
                left.closePath();
            }

            float transStackRight = (float) rangeAxis.valueToJava2D(
                    adjStackRight[1], dataArea, edge1);
            // RIGHT POLYGON
            if (y2 >= 0.0) {
                double yright = (y1 + y2) / 2.0 + stackRight[1];
                float transYRight 
                    = (float) rangeAxis.valueToJava2D(yright, dataArea, edge1);
                right.moveTo((float) xx1, transStack1);
                right.lineTo((float) xx1, transY1);
                right.lineTo((float) xxRight, transYRight);
                right.lineTo((float) xxRight, transStackRight);
                right.closePath();
            }
            else {
                right.moveTo((float) xx1, transStack1);
                right.lineTo((float) xx1, transY1);
                right.lineTo((float) xxRight, transStackRight);
                right.closePath();
            }
        }
        else {  // handle negative value 
            transY1 = (float) rangeAxis.valueToJava2D(y1 + stack1[0], dataArea,
                    edge1);
            float transStack1 = (float) rangeAxis.valueToJava2D(stack1[0], 
                    dataArea, edge1);
            float transStackLeft = (float) rangeAxis.valueToJava2D(
                    adjStackLeft[0], dataArea, edge1);

            // LEFT POLYGON
            if (y0 >= 0.0) {
                left.moveTo((float) xx1, transStack1);
                left.lineTo((float) xx1, transY1);
                left.lineTo((float) xxLeft, transStackLeft);
                left.clone();
            }
            else {
                double yleft = (y0 + y1) / 2.0 + stackLeft[0];
                float transYLeft = (float) rangeAxis.valueToJava2D(yleft, 
                        dataArea, edge1);
                left.moveTo((float) xx1, transY1);
                left.lineTo((float) xx1, transStack1);
                left.lineTo((float) xxLeft, transStackLeft);
                left.lineTo((float) xxLeft, transYLeft);
                left.closePath();
            }
            float transStackRight = (float) rangeAxis.valueToJava2D(
                    adjStackRight[0], dataArea, edge1);
            
            // RIGHT POLYGON
            if (y2 >= 0.0) {
                right.moveTo((float) xx1, transStack1);
                right.lineTo((float) xx1, transY1);
                right.lineTo((float) xxRight, transStackRight);
                right.closePath();
            }
            else {
                double yright = (y1 + y2) / 2.0 + stackRight[0];
                float transYRight = (float) rangeAxis.valueToJava2D(yright, 
                        dataArea, edge1);
                right.moveTo((float) xx1, transStack1);
                right.lineTo((float) xx1, transY1);
                right.lineTo((float) xxRight, transYRight);
                right.lineTo((float) xxRight, transStackRight);
                right.closePath();
            }
        }

        g2.setPaint(getItemPaint(row, column));
        g2.setStroke(getItemStroke(row, column));

        //  Get series Paint and Stroke
        Paint itemPaint = getItemPaint(row, column);
        if (pass == 0) {
            g2.setPaint(itemPaint);
            g2.fill(left);
            g2.fill(right);
        } 
        
        // add an entity for the item...
        if (entities != null) {
            GeneralPath gp = new GeneralPath(left);
            gp.append(right, false);
            entityArea = gp;
            addItemEntity(entities, dataset, row, column, entityArea);
        }
        
    }

//    /**
//     * Draw a single data item.
//     *
//     * @param g2  the graphics device.
//     * @param state  the renderer state.
//     * @param dataArea  the data plot area.
//     * @param plot  the plot.
//     * @param domainAxis  the domain axis.
//     * @param rangeAxis  the range axis.
//     * @param dataset  the data.
//     * @param row  the row index (zero-based).
//     * @param column  the column index (zero-based).
//     * @param pass  the pass index.
//     */
//    public void drawItem(Graphics2D g2,
//                         CategoryItemRendererState state,
//                         Rectangle2D dataArea,
//                         CategoryPlot plot,
//                         CategoryAxis domainAxis,
//                         ValueAxis rangeAxis,
//                         CategoryDataset dataset,
//                         int row,
//                         int column,
//                         int pass) {
//
//        // plot non-null values...
//        Number dataValue = dataset.getValue(row, column);
//        if (dataValue == null) {
//            return;
//        }
//        
//        double value = dataValue.doubleValue();
//        double total = 0.0;  // only needed if calculating percentages
//        if (this.renderAsPercentages) {
//            total = DataUtilities.calculateColumnTotal(dataset, column);
//            value = value / total;
//        }
//
//        // leave the y values (y1, y0) untranslated as it is going to be be 
//        // stacked up later by previous series values, after this it will be 
//        // translated.
//        double xx1 = domainAxis.getCategoryMiddle(column, getColumnCount(), 
//                dataArea, plot.getDomainAxisEdge());
//        
//        double previousHeightx1 = getPreviousHeight(dataset, row, column);
//        double y1 = value + previousHeightx1;
//        RectangleEdge location = plot.getRangeAxisEdge();
//        double yy1 = rangeAxis.valueToJava2D(y1, dataArea, location);
//
//        g2.setPaint(getItemPaint(row, column));
//        g2.setStroke(getItemStroke(row, column));
//
//        // in column zero, the only job to do is draw any visible item labels
//        // and this is done in the second pass...
//        if (column == 0) {
//            if (pass == 1) {
//                // draw item labels, if visible
//                if (isItemLabelVisible(row, column)) {
//                    drawItemLabel(g2, plot.getOrientation(), dataset, row, column, 
//                            xx1, yy1, (y1 < 0.0));
//                }    
//            }
//        }
//        else {
//            Number previousValue = dataset.getValue(row, column - 1);
//            if (previousValue != null) {
//
//                double xx0 = domainAxis.getCategoryMiddle(column - 1, 
//                        getColumnCount(), dataArea, plot.getDomainAxisEdge());
//                double y0 = previousValue.doubleValue();
//                if (this.renderAsPercentages) {
//                    total = DataUtilities.calculateColumnTotal(dataset, 
//                            column - 1);
//                    y0 = y0 / total;
//                }
//               
//
//                // Get the previous height, but this will be different for both
//                // y0 and y1 as the previous series values could differ.
//                double previousHeightx0 = getPreviousHeight(dataset, row, 
//                        column - 1);
//
//                // Now stack the current y values on top of the previous values.
//                y0 += previousHeightx0;
//
//                // Now translate the previous heights
//                double previousHeightxx0 = rangeAxis.valueToJava2D(
//                        previousHeightx0, dataArea, location);
//                double previousHeightxx1 = rangeAxis.valueToJava2D(
//                        previousHeightx1, dataArea, location);
//
//                // Now translate the current y values.
//                double yy0 = rangeAxis.valueToJava2D(y0, dataArea, location);
//
//                if (pass == 0) {
//                    // FIXME: this doesn't handle negative values properly
//                    Polygon p = null;
//                    PlotOrientation orientation = plot.getOrientation();
//                    if (orientation == PlotOrientation.HORIZONTAL) {
//                        p = new Polygon();
//                        p.addPoint((int) yy0, (int) xx0);
//                        p.addPoint((int) yy1, (int) xx1);
//                        p.addPoint((int) previousHeightxx1, (int) xx1);
//                        p.addPoint((int) previousHeightxx0, (int) xx0);
//                    }
//                    else if (orientation == PlotOrientation.VERTICAL) {
//                        p = new Polygon();
//                        p.addPoint((int) xx0, (int) yy0);
//                        p.addPoint((int) xx1, (int) yy1);
//                        p.addPoint((int) xx1, (int) previousHeightxx1);
//                        p.addPoint((int) xx0, (int) previousHeightxx0);
//                    }
//                    g2.setPaint(getItemPaint(row, column));
//                    g2.setStroke(getItemStroke(row, column));
//                    g2.fill(p);
//
//                    // add an item entity, if this information is being 
//                    // collected...
//                    EntityCollection entities = state.getEntityCollection();
//                    if (entities != null) {
//                        addItemEntity(entities, dataset, row, column, p);
//                    }
//                    
//                }
//                else {
//                    if (isItemLabelVisible(row, column)) {
//                        drawItemLabel(g2, plot.getOrientation(), dataset, row, 
//                                column, xx1, yy1, (y1 < 0.0));
//                    }  
//                }
//            }
//            
//
//        }
//        
//    }

    /**
     * Calculates the stacked value of the all series up to, but not including 
     * <code>series</code> for the specified category, <code>category</code>.  
     * It returns 0.0 if <code>series</code> is the first series, i.e. 0.
     *
     * @param dataset  the dataset (<code>null</code> not permitted).
     * @param series  the series.
     * @param category  the category.
     *
     * @return double returns a cumulative value for all series' values up to 
     *         but excluding <code>series</code> for Object 
     *         <code>category</code>.
     */
    protected double getPreviousHeight(CategoryDataset dataset, 
                                       int series, int category) {

        double result = 0.0;
        Number n;
        double total = 0.0;
        if (this.renderAsPercentages) {
            total = DataUtilities.calculateColumnTotal(dataset, category);
        }
        for (int i = 0; i < series; i++) {
            n = dataset.getValue(i, category);
            if (n != null) {
                double v = n.doubleValue();
                if (this.renderAsPercentages) {
                    v = v / total;
                }
                result += v;
            }
        }
        return result;

    }

    /**
     * Calculates the stacked values (one positive and one negative) of all 
     * series up to, but not including, <code>series</code> for the specified 
     * item. It returns [0.0, 0.0] if <code>series</code> is the first series.
     *
     * @param dataset  the dataset (<code>null</code> not permitted).
     * @param series  the series index.
     * @param index  the item index.
     *
     * @return An array containing the cumulative negative and positive values
     *     for all series values up to but excluding <code>series</code> 
     *     for <code>index</code>.
     */
    protected double[] getStackValues(CategoryDataset dataset, 
            int series, int index) {
        double[] result = new double[2];
        for (int i = 0; i < series; i++) {
            if (isSeriesVisible(i)) {
                double v = 0.0;
                Number n = dataset.getValue(i, index);
                if (n != null) {
                    v = n.doubleValue();
                }
                if (!Double.isNaN(v)) {
                    if (v >= 0.0) {
                        result[1] += v;   
                    }
                    else {
                        result[0] += v;   
                    }
                }
            }
        }
        return result;
    }

    /**
     * Returns a pair of "stack" values calculated as the mean of the two 
     * specified stack value pairs.
     * 
     * @param stack1  the first stack pair.
     * @param stack2  the second stack pair.
     * 
     * @return A pair of average stack values.
     */
    private double[] averageStackValues(double[] stack1, double[] stack2) {
        double[] result = new double[2];
        result[0] = (stack1[0] + stack2[0]) / 2.0;
        result[1] = (stack1[1] + stack2[1]) / 2.0;
        return result;
    }

    /**
     * Calculates adjusted stack values from the supplied values.  The value is
     * the mean of the supplied values, unless either of the supplied values
     * is zero, in which case the adjusted value is zero also.
     * 
     * @param stack1  the first stack pair.
     * @param stack2  the second stack pair.
     * 
     * @return A pair of average stack values.
     */
    private double[] adjustedStackValues(double[] stack1, double[] stack2) {
        double[] result = new double[2];
        if (stack1[0] == 0.0 || stack2[0] == 0.0) {
            result[0] = 0.0;   
        }
        else {
            result[0] = (stack1[0] + stack2[0]) / 2.0;
        }
        if (stack1[1] == 0.0 || stack2[1] == 0.0) {
            result[1] = 0.0;   
        }
        else {
            result[1] = (stack1[1] + stack2[1]) / 2.0;
        }
        return result;
    }

    /**
     * Checks this instance for equality with an arbitrary object.
     *
     * @param obj  the object (<code>null</code> not permitted).
     *
     * @return A boolean.
     */
    public boolean equals(Object obj) {
        if (obj == this) {
            return true;
        }
        if (! (obj instanceof StackedAreaRenderer)) {
            return false;
        }
        StackedAreaRenderer that = (StackedAreaRenderer) obj;
        if (this.renderAsPercentages != that.renderAsPercentages) {
            return false;
        }
        return super.equals(obj);
    }
}
David Gilbert
JFreeChart Project Leader

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

pradheep
Posts: 15
Joined: Thu Apr 12, 2007 4:47 am
Location: Chennai [INDIA]
Contact:

Post by pradheep » Tue May 08, 2007 12:14 pm

i am using Image map of the generated Horizontal Stacked Bar chart.
its getting generated with onmouseover and onmouseout attributes which have method overlib(string) and nd()

where do i find those function. another think is i need a URL which should be a javascript:newwindow////


guide me in this
--------------------------------
Cheers
PraDz

chechaquo
Posts: 10
Joined: Tue Oct 28, 2008 12:42 pm

Post by chechaquo » Tue Oct 28, 2008 1:08 pm

Hello,

I'm using jfreechart-1.0.11.
I was playing with deepika's class:
I replaced createDataset method with code below:

Code: Select all

private static CategoryDataset createDataset() {
DefaultCategoryDataset dataset = new DefaultCategoryDataset();
 
    dataset.addValue(0.0, "A", "2006");
    dataset.addValue(0.0, "A", "2007");
    dataset.addValue(0.0, "A", "2008");

  
    dataset.addValue(0.0, "B", "2006");
    dataset.addValue(0.0, "B", "2007");
    dataset.addValue(0.0, "B", "2008");

  
    dataset.addValue(0.1, "C", "2006");
    dataset.addValue(0.0, "C", "2007");
    dataset.addValue(0.63, "C", "2008");

   
    dataset.addValue(0.0, "D", "2006");
    dataset.addValue(0.0, "D", "2007");
    dataset.addValue(0.0, "D", "2008");
    
   
    dataset.addValue(0.0, "E", "2006");
    dataset.addValue(0.0, "E", "2007");
    dataset.addValue(0.0, "E", "2008");



return dataset;
}
and got strange diagram, shouldn’t it only contain C values?

Thanks for your help in advance.

chechaquo
Posts: 10
Joined: Tue Oct 28, 2008 12:42 pm

Post by chechaquo » Thu Oct 30, 2008 9:11 am

I tested same code with jfreechart-1.0.5. This time diagram was rendered correctly, but it had problems with tooltip (displaying values for E not for C)

Locked