BarChart with Interval.

A discussion forum for JFreeChart (a 2D chart library for the Java platform).
pmarsollier
Posts: 49
Joined: Thu Jul 08, 2004 8:54 am
Location: France

Post by pmarsollier » Mon Jun 26, 2006 1:39 pm

if you edit your graph, just build it with Excel .... it's be far more easy !!

JIron
Posts: 20
Joined: Mon May 15, 2006 10:42 pm

Post by JIron » Tue Jun 27, 2006 5:44 am

pmarsollier,
Not so Easy...
Only the interval was autorized to make with Photoshop(A friend of mine will do).The others features must be implemented.I just wanna get more time to make this...
if you edit your graph, just build it with Excel
This job was made to substitute Excel to 70 eletric companies to have access to performance features and don´t need have a Excel installed to see online.The only bar with i have trouble is the barchart with interval and huge bar(are 210 charts on total).

This project will be cancelled just because one type of chart it´s not possible to substitute the Excel... :cry:

pmarsollier
Posts: 49
Joined: Thu Jul 08, 2004 8:54 am
Location: France

Post by pmarsollier » Tue Jun 27, 2006 7:44 am

well, the first message contains the data you want to draw ??

I'll see what i can do.

give me a week.

I think it's not so hard to do ....

pmarsollier
Posts: 49
Joined: Thu Jul 08, 2004 8:54 am
Location: France

Post by pmarsollier » Tue Jun 27, 2006 2:59 pm

I made a first shot ...

Image

is thats fitting what you need ???

JIron
Posts: 20
Joined: Mon May 15, 2006 10:42 pm

Post by JIron » Wed Jun 28, 2006 5:15 am

pmarsollier,

That´s Incredible, almost there!!!

The real chart is this:
http://img284.imageshack.us/my.php?imag ... bar1ln.jpg
But if you do in the first example, i modify the bars on my real chart!

The vertical category labels works fine?Like:

Code: Select all

final CategoryAxis domainAxis = cp.getDomainAxis();
    domainAxis.setCategoryLabelPositions(CategoryLabelPositions.UP_90);
My doubts:
-How do you make a space in the bar?(Paint?)
-How do you make a space on the Y axis!!!(The blank labels to position 200)
-How do you make to the huge bars don´t make tiny the others?!!
>>If you use a huge value,like 1000 on the last range, you still can show the bar without distorsion???

Please, post the complete code!(use tags [code and /code] )

Thanks for everything!
JIron

Bavo
Posts: 3
Joined: Tue Jul 11, 2006 3:06 pm

Post by Bavo » Wed Jul 12, 2006 10:25 am

Do you have the code for that pmarsollier? I actually dont need the cut, only the part where values on the ValueAxis go non-linear.

That would be great :)

pmarsollier
Posts: 49
Joined: Thu Jul 08, 2004 8:54 am
Location: France

Post by pmarsollier » Wed Jul 12, 2006 10:36 am

the Interval Class

Code: Select all

public class Interval
{
    // low Limit (value unit)
    private double lowLimit = 0; 
    // high Limit (value unit)
    private double highLimit = 0;
    // max value, no computed value above this
    private double maxValue = 0;
    
    // separator size (soemwhat pixel) 
    private int sepSize = 10; 

    public Interval( double low, double high, double max, int size )
    {
        lowLimit = low;
        highLimit = high;
        maxValue = max;
        sepSize = size;
    }

    public double getHighLimit()
    {
        return highLimit;
    }
    public void setHighLimit(double highLimit)
    {
        this.highLimit = highLimit;
    }
    public double getLowLimit()
    {
        return lowLimit;
    }
    public void setLowLimit(double lowLimit)
    {
        this.lowLimit = lowLimit;
    }
    public double getMaxValue()
    {
        return maxValue;
    }
    public void setMaxValue(double maxValue)
    {
        this.maxValue = maxValue;
    }
    public int getSepSize()
    {
        return sepSize;
    }
    public void setSepSize(int sepSize)
    {
        this.sepSize = sepSize;
    }
    
    public double computeValue( double value )
    {
        // to be overidden to compute adjusted values
        if (value > maxValue) return maxValue;
        return value;
    }

    public boolean isAboveLow( double value )
    {
        // return true is computed value > high limit
        return ( lowLimit > 0 && highLimit > 0&& value > lowLimit );
    }
    public boolean isAboveHigh( double value )
    {
        // return true is computed value > high limit
        return ( lowLimit > 0 && highLimit > 0&& value > highLimit );
    }

    public double getMaxComputed()
    {
        return computeValue(maxValue);
    }

}
you need to implement your own Interval. sample :

Code: Select all

public class MyInterval extends Interval
{

    public MyInterval( double low, double high, double max, int size)
    {
        super(low, high, max, size);
    }
    public double computeValue(double value)
    {
        // 3200 4200 7000 28000
        double ret = value;
        if ( value > getLowLimit() )
        {
            if (value < getHighLimit() )
            {
                // truncate
                ret = getLowLimit();
            }
            else // > highLimit
            {
                // convert to good range
                double delta = getHighLimit() - getLowLimit(); 
                // 3200 => 2300
                // 4200 => 2500
                // 7000 => 2700
                // 28000 => 3500
                if (value < 4000)
                {
                    ret = 2300;
                }
                else if (value < 5000)
                {
                    ret = 2500;
                }
                else if (value < 8000)
                {
                    ret = 2700;
                }
                else if (value < 30000)
                {
                    ret = 3500;
                }
                else
                {
                    ret = 4000;
                }
            }
        }
        return Math.min(ret,getMaxValue());
    }
}
the axis, modifications commented

Code: Select all

import java.awt.Graphics2D;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
import java.util.Iterator;
import java.util.List;

import org.jfree.chart.axis.AxisState;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.axis.ValueTick;
import org.jfree.text.TextUtilities;
import org.jfree.ui.RectangleEdge;

public class IntervalAxis extends NumberAxis
{
//  handling interval         
    
    Interval interval = null;
    
    public IntervalAxis(String label, Interval interval )
    {
        super(label);
        this.interval = interval;
    }
//  handling interval         
    
    /**
     * Draws the axis line, tick marks and tick mark labels.
     * 
     * @param g2  the graphics device.
     * @param cursor  the cursor.
     * @param plotArea  the plot area.
     * @param dataArea  the data area.
     * @param edge  the edge that the axis is aligned with.
     * 
     * @return The width or height used to draw the axis.
     */
    protected AxisState drawTickMarksAndLabels(Graphics2D g2, 
                                               double cursor,
                                               Rectangle2D plotArea,
                                               Rectangle2D dataArea, 
                                               RectangleEdge edge) {
                                              
        AxisState state = new AxisState(cursor);

        if (isAxisLineVisible()) {
            drawAxisLine(g2, cursor, dataArea, edge);
        }

        double ol = getTickMarkOutsideLength();
        double il = getTickMarkInsideLength();

        List ticks = refreshTicks(g2, state, dataArea, edge);
        state.setTicks(ticks);
        g2.setFont(getTickLabelFont());
        Iterator iterator = ticks.iterator();
        while (iterator.hasNext()) 
        {
//          handling interval         
            ValueTick tick = (ValueTick) iterator.next();
            if (isTickLabelsVisible()) 
            {
                // to stop drawing labels above low limit
                boolean draw = !( interval != null && interval.isAboveLow( tick.getValue() ) );
                // to draw the max valuer on the last tick
                boolean last = ( interval != null && !iterator.hasNext());
                if (draw)
                {
	                g2.setPaint(getTickLabelPaint());
	                float[] anchorPoint = calculateAnchorPoint(
	                    tick, cursor, dataArea, edge
	                );
	                TextUtilities.drawRotatedString(
	                    tick.getText(), g2, 
	                    anchorPoint[0], anchorPoint[1],
	                    tick.getTextAnchor(), 
	                    tick.getAngle(),
	                    tick.getRotationAnchor()
	                );
                }
                else if (last)
                {
	                g2.setPaint(getTickLabelPaint());
	                float[] anchorPoint = calculateAnchorPoint(
	                    tick, cursor, dataArea, edge
	                );
	                TextUtilities.drawRotatedString(
	                    getTickUnit().valueToString(interval.getMaxValue()), g2, 
	                    anchorPoint[0], anchorPoint[1],
	                    tick.getTextAnchor(), 
	                    tick.getAngle(),
	                    tick.getRotationAnchor()
	                );
                }
            }
//          handling interval         

            if (isTickMarksVisible()) {
                float xx = (float) valueToJava2D(
                    tick.getValue(), dataArea, edge
                );
                Line2D mark = null;
                g2.setStroke(getTickMarkStroke());
                g2.setPaint(getTickMarkPaint());
                if (edge == RectangleEdge.LEFT) {
                    mark = new Line2D.Double(cursor - ol, xx, cursor + il, xx);
                }
                else if (edge == RectangleEdge.RIGHT) {
                    mark = new Line2D.Double(cursor + ol, xx, cursor - il, xx);
                }
                else if (edge == RectangleEdge.TOP) {
                    mark = new Line2D.Double(xx, cursor - ol, xx, cursor + il);
                }
                else if (edge == RectangleEdge.BOTTOM) {
                    mark = new Line2D.Double(xx, cursor + ol, xx, cursor - il);
                }
                g2.draw(mark);
            }
        }
        
        // need to work out the space used by the tick labels...
        // so we can update the cursor...
        double used = 0.0;
        if (isTickLabelsVisible()) {
            if (edge == RectangleEdge.LEFT) {
                used += findMaximumTickLabelWidth(
                    ticks, g2, plotArea, isVerticalTickLabels()
                );  
                state.cursorLeft(used);      
            }
            else if (edge == RectangleEdge.RIGHT) {
                used = findMaximumTickLabelWidth(
                    ticks, g2, plotArea, isVerticalTickLabels()
                );
                state.cursorRight(used);      
            }
            else if (edge == RectangleEdge.TOP) {
                used = findMaximumTickLabelHeight(
                    ticks, g2, plotArea, isVerticalTickLabels()
                );
                state.cursorUp(used);
            }
            else if (edge == RectangleEdge.BOTTOM) {
                used = findMaximumTickLabelHeight(
                    ticks, g2, plotArea, isVerticalTickLabels()
                );
                state.cursorDown(used);
            }
        }
       
        return state;
    }

}

the renderer, modification commented

Code: Select all

import java.awt.Color;
import java.awt.GradientPaint;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.Stroke;
import java.awt.geom.Rectangle2D;

import org.jfree.chart.axis.CategoryAxis;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.entity.EntityCollection;
import org.jfree.chart.labels.CategoryItemLabelGenerator;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.renderer.category.CategoryItemRendererState;
import org.jfree.data.category.CategoryDataset;
import org.jfree.ui.GradientPaintTransformer;
import org.jfree.ui.RectangleEdge;

public class IntervalBarRenderer extends org.jfree.chart.renderer.category.BarRenderer
{
//  handling interval         
    Interval interval = null;
    
    public IntervalBarRenderer( Interval interval )
    {
        super();
        this.interval = interval;
    }
//  handling interval         
    
    /**
     * Draws the bar for a single (series, category) data item.
     *
     * @param g2  the graphics device.
     * @param state  the renderer state.
     * @param dataArea  the data area.
     * @param plot  the plot.
     * @param domainAxis  the domain axis.
     * @param rangeAxis  the range axis.
     * @param dataset  the dataset.
     * @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) {

        // nothing is drawn for null values...
        Number dataValue = dataset.getValue(row, column);
        if (dataValue == null) {
            return;
        }
        double value = dataValue.doubleValue();

//      handling interval         
        boolean drawSeparator = false;
        if (interval != null)
        {
            drawSeparator = interval.isAboveHigh(value);
            value = interval.computeValue(value);
        }
//      handling interval
        
        PlotOrientation orientation = plot.getOrientation();
        double barW0 = calculateBarW0(plot, orientation, dataArea, domainAxis, 
                state, row, column);
        double[] barL0L1 = calculateBarL0L1(value);
        if (barL0L1 == null) {
            return;  // the bar is not visible
        }
        
        RectangleEdge edge = plot.getRangeAxisEdge();
        double transL0 = rangeAxis.valueToJava2D(barL0L1[0], dataArea, edge);
        double transL1 = rangeAxis.valueToJava2D(barL0L1[1], dataArea, edge);
        double barL0 = Math.min(transL0, transL1);
        double barLength = Math.max(Math.abs(transL1 - transL0), 
                getMinimumBarLength());

        // draw the bar...
        Rectangle2D bar = null;
        if (orientation == PlotOrientation.HORIZONTAL) 
        {
            bar = new Rectangle2D.Double(barL0, barW0, barLength,state.getBarWidth());
        }
        else 
        {
            bar = new Rectangle2D.Double(barW0, barL0, state.getBarWidth(),barLength);
        }
        
        Paint itemPaint = getItemPaint(row, column);
        GradientPaintTransformer t = getGradientPaintTransformer();
        if (t != null && itemPaint instanceof GradientPaint) {
            itemPaint = t.transform((GradientPaint) itemPaint, bar);
        }
        g2.setPaint(itemPaint);
        g2.fill(bar);

//      handling interval         
        if (drawSeparator)
        {
            // interval cannot be not null here !!
            barL0 = rangeAxis.valueToJava2D(interval.getLowLimit(), dataArea, edge) - interval.getSepSize();
            barLength = interval.getSepSize();
            Rectangle2D sepBar = null;
            // draw a blank bar meaning separator
            if (orientation == PlotOrientation.HORIZONTAL) 
            {
                sepBar = new Rectangle2D.Double(barL0, barW0, barLength, state.getBarWidth());
            }
            else 
            {
                sepBar = new Rectangle2D.Double(barW0, barL0, state.getBarWidth(), barLength);
            }
            g2.setPaint(plot.getBackgroundPaint());
            g2.fill(sepBar);
        }
//      handling interval         
        
        // draw the outline...
        if (isDrawBarOutline() 
                && state.getBarWidth() > BAR_OUTLINE_WIDTH_THRESHOLD) {
            Stroke stroke = getItemOutlineStroke(row, column);
            Paint paint = getItemOutlinePaint(row, column);
            if (stroke != null && paint != null) {
                g2.setStroke(stroke);
                g2.setPaint(paint);
                g2.draw(bar);
            }
        }

        CategoryItemLabelGenerator generator 
            = getItemLabelGenerator(row, column);
        if (generator != null && isItemLabelVisible(row, column)) {
            drawItemLabel(g2, dataset, row, column, plot, generator, bar, 
                    (value < 0.0));
        }        

        // add an item entity, if this information is being collected
        EntityCollection entities = state.getEntityCollection();
        if (entities != null) {
            addItemEntity(entities, dataset, row, column, bar);
        }

    }
    
}
the use of it :

Code: Select all

Interval interval = new MyInterval(2000, 3000, 30000, 10);
IntervalBarRenderer renderer = new IntervalBarRenderer( interval );
IntervalAxis valueAxis = new IntervalAxis("Valor", interval);
valueAxis.setRange(0,interval.getMaxComputed());
valueAxis.setTickUnit(new NumberTickUnit(500,new DecimalFormat("0")));
if you need, I can post the archive via private message.

Bavo
Posts: 3
Joined: Tue Jul 11, 2006 3:06 pm

Post by Bavo » Wed Jul 12, 2006 1:03 pm

Ok, thanks, the code compiles and runs right without problems. Now it's a question to change t to my case, but I think that won't be a problem either. You should really implement this!

Nice work, thx alot.

Locked