#682 StackedXYAreaRenderer2 bad rendering

1.0.x
open
nobody
General (896)
5
2012-11-27
2006-10-17
Anonymous
No

I noticed a problem rendering a chart with a
TimeTableXYDataset (see picture). Vertical lines are
visible.
The rendering problem appear when i have "holes" in
the series, like weekends in a time series. There are
no data for weekends. If I try with only 5 days the
rendering is correct.

Cheers,
Alessandro

Discussion

  • Nobody/Anonymous

    Stacked Time Series

     
    Attachments
  • Nobody/Anonymous

    Logged In: NO

    Had similar problem : seems like lines are drawn for points where data exists. If you soom in on the chart, you'll see that the line is right at the currrent X. StackedXYAreaRenderer (without 2 at the end) doesn't do it, but that one doesn't display hints for items.

     
  • Nobody/Anonymous

    Logged In: NO

    Also StackedXYAreaRenderer2 does not show outline of the area. StackedXYAreaRenderer does.

     
  • bogakvm

    bogakvm - 2007-03-29

    Logged In: YES
    user_id=1756381
    Originator: NO

    this seem to fix "hole" lines in between. I didn't test negative values though, but it can give an idea what's wrong

    (StackedXYAreaRenderer2.java,v 1.6.2.6), public void drawItem(Graphics2D g2,....) :

    ..... if block for positive values :

    // LEFT POLYGON
    if (y0 >= 0.0)
    {
    double yleft = (y0 + y1) / 2.0 + stackLeft[1];
    float transYLeft
    = (float) rangeAxis.valueToJava2D(yleft, dataArea, edge1);
    left.moveTo(transX1, transY1);
    left.lineTo(transX1, transStack1);
    left.lineTo(transXLeft - 1, transStackLeft); // offset to the left by 1 pix
    left.lineTo(transXLeft - 1, transYLeft); // offset to the left by 1 pix
    left.closePath();
    }
    else
    {
    left.moveTo(transX1, transStack1);
    left.lineTo(transX1, transY1);
    left.lineTo(transXLeft, 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(transX1 - 1, transStack1); // offset to the left by one
    right.lineTo(transX1 - 1, transY1);
    right.lineTo(transXRight, transYRight);
    right.lineTo(transXRight, transStackRight);
    right.closePath();
    }
    else
    {
    right.moveTo(transX1, transStack1);
    right.lineTo(transX1, transY1);
    right.lineTo(transXRight, transStackRight);
    right.closePath();
    }

     
  • bogakvm

    bogakvm - 2007-07-03

    Logged In: YES
    user_id=1756381
    Originator: NO

    I was able to fix this one. It renders whole are correctly now : no lines between, draws an outline and generates tooltips. I am new to open source community, so just pasting the fixed code here. Please add that to the file. This is for StackedXYAreaRenderer2 not StackedXYAreaRenderer. I used StackedXYAreaRenderer2 as the starting point as it does generate tooltips.

    here is the method I fixed (drawItem(...)) :

    /**
    * Draws the visual representation of a single data item.
    *
    * bogakvm 7/3/2007 :
    *
    * - modified logic not to draw every single data item. Draws the whole series area instead.
    * - still individual shapes are crearted for proper tooltip generation (mergind left and right polygon)
    * - added some comments for things I could figure out
    * - added logic to draw an outline around the series as it was not in place.
    * - kept left and right points (pLeftXXX and pRightXXX see comments), but for the series shape only
    * data points are used (lines only connect exisint data points from the data set.
    * - left debug statements in (commented out)
    *
    *
    * @param g2 the graphics device.
    * @param state the renderer state.
    * @param dataArea the area within which the data is being drawn.
    * @param info collects information about the drawing.
    * @param plot the plot (can be used to obtain standard color information
    * etc).
    * @param domainAxis the domain axis.
    * @param rangeAxis the range axis.
    * @param dataset the dataset.
    * @param series the series index (zero-based).
    * @param item the item index (zero-based).
    * @param crosshairState information about crosshairs on a plot.
    * @param pass the pass index.
    */
    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) {

    // setup for collecting optional entity info...
    Shape entityArea = null;
    TableXYDataset tdataset = (TableXYDataset) dataset;

        // TEMP :       if \(series>0\) return;
    

    EntityCollection entities = null;

    if (info != null)
    {
    entities = info.getOwner().getEntityCollection();
    }

    // get the data point...
    double x1 = dataset.getXValue(series, item);
    double y1 = dataset.getYValue(series, item);

    if (Double.isNaN(y1))
    {
    y1 = 0.0;
    }
    double[] stack1 = getStackValues(tdataset, series, item);

    // get the previous point and the next point so we can calculate a
    // "hot spot" for the area (used by the chart entity)...
    int item0 = Math.max(item - 1, 0);
    double x0 = dataset.getXValue(series, item0);
    double y0 = dataset.getYValue(series, item0);

    if (Double.isNaN(y0))
    {
    y0 = 0.0;
    }

    double[] stack0 = getStackValues(tdataset, series, item0);

    int itemCount = dataset.getItemCount(series);

        int item2 = Math.min\(item + 1, itemCount - 1\);
    

    double x2 = dataset.getXValue(series, item2);
    double y2 = dataset.getYValue(series, item2);

    if (Double.isNaN(y2))
    {
    y2 = 0.0;
    }

    double[] stack2 = getStackValues(tdataset, series, item2);

    double xleft = (x0 + x1) / 2.0;
    double xright = (x1 + x2) / 2.0;
    double[] stackLeft = averageStackValues(stack0, stack1);
    double[] stackRight = averageStackValues(stack1, stack2);
    double[] adjStackLeft = adjustedStackValues(stack0, stack1);
    double[] adjStackRight = adjustedStackValues(stack1, stack2);

    RectangleEdge edge0 = plot.getDomainAxisEdge();

    float transX1 = (float) domainAxis.valueToJava2D(x1, dataArea, edge0);
    float transXLeft = (float) domainAxis.valueToJava2D(xleft, dataArea, edge0);
    float transXRight = (float) domainAxis.valueToJava2D(xright, dataArea, edge0);

    if (this.roundXCoordinates)
    {
    transX1 = Math.round(transX1);
    transXLeft = Math.round(transXLeft);
    transXRight = Math.round(transXRight);
    }

    float transY1 = 0;

    RectangleEdge edge1 = plot.getRangeAxisEdge();
    GeneralPath left = new GeneralPath();
    GeneralPath right = new GeneralPath();

        float transStack1 = 0;
        float transStackLeft = 0;
        float transYLeft = 0;
        float transYRight = 0;
        float transStackRight = 0;
    
        Point pTopLeft = null;
        Point pTopCenter = null;
        Point pTopRight = null;
        Point pBottomLeft = null;
        Point pBottomCenter = null;
        Point pBottomRight = null;
    
        /\*         Connecting center lines \(data points\) only, otherwise there is an issue with shape form when multiple series 
            are plotted.
    
                Shape is needed for each data point to add entity \(for tooltip generation\). Individual shapes are not drawn as 
            originally. The whole series area is filled and then outlined \(if outline is true\) 
         \*/
    

    if (y1 >= 0.0) // handle positive value (y1 = middle point, i.e. data value
    {
    transY1 = (float) rangeAxis.valueToJava2D(y1 + stack1[1], dataArea, edge1);
    transStack1 = (float) rangeAxis.valueToJava2D(stack1[1], dataArea, edge1);
    transStackLeft = (float) rangeAxis.valueToJava2D(adjStackLeft[1], dataArea, edge1);

    // LEFT POLYGON - the one that draws to the left of transX1 line

    if (y0 >= 0.0)
    {
    double yleft = (y0 + y1) / 2.0 + stackLeft[1];
    transYLeft = (float) rangeAxis.valueToJava2D(yleft, dataArea, edge1);
    /*
    g2.drawString(transX1+" TC", transX1, transY1 + 5);
    g2.drawString(transX1+" BC", transX1, transStack1 + 5);
    g2.drawString(transX1+" BL", transXLeft, transStackLeft + 5);
    g2.drawString(transX1+" TL", transXLeft, transYLeft + 5);
    */
    left.moveTo(transX1, transY1); // visually : right top. Keep in mind coordinate system for Java 2D
    left.lineTo(transX1, transStack1); // right bottom
    left.lineTo(transXLeft, transStackLeft); // left bottom
    left.lineTo(transXLeft, transYLeft); // left top
    left.closePath();

    // pTopLeft = new Point((int)transXLeft, (int)transYLeft); // left top
    pTopCenter = new Point((int)transX1, (int)transY1); // right top

    // pBottomLeft = new Point((int)transXLeft, (int)transStackLeft); // left bottom
    pBottomCenter = new Point((int)transX1, (int)transStack1); // right bottom (becomes center bottom for the curve)
    }
    else
    {
    /*
    g2.drawString(transX1+" LL_1", transX1, transStack1 + 5);
    g2.drawString(transX1+" LL_2", transX1, transY1 + 5);
    g2.drawString(transX1+" LL_3", transXLeft, transStackLeft + 5);
    */
    left.moveTo(transX1, transStack1);
    left.lineTo(transX1, transY1);
    left.lineTo(transXLeft, transStackLeft);
    left.closePath();

    // pTopLeft = new Point((int)transXLeft, (int)transStackLeft);
    pTopCenter = new Point((int)transX1, (int)transY1);

    // pBottomLeft = pTopLeft;
    pBottomCenter = new Point((int)transX1, (int)transStack1);
    }

            // RIGHT POLYGON
    

    transStackRight = (float) rangeAxis.valueToJava2D(adjStackRight[1], dataArea, edge1);

    if (y2 >= 0.0)
    {
    double yright = (y1 + y2) / 2.0 + stackRight[1];

    transYRight = (float) rangeAxis.valueToJava2D(yright, dataArea, edge1);
    /*
    g2.drawString(transX1+" RG_1", transX1, transStack1 - 5);
    g2.drawString(transX1+" RG_2", transX1, transY1 - 5);
    g2.drawString(transX1+" RG_3", transXRight, transYRight - 5);
    g2.drawString(transX1+" RG_4", transXRight, transStackRight - 5);
    */
    right.moveTo(transX1, transStack1); // bottom left
    right.lineTo(transX1, transY1); // top left
    right.lineTo(transXRight, transYRight); // top right
    right.lineTo(transXRight, transStackRight); // bottom right
    right.closePath();

    // pTopRight = new Point((int)transXRight, (int)transYRight);
    // pBottomRight = new Point((int)transXRight, (int)transStackRight);
    }
    else
    {
    /*
    g2.drawString(transX1+" RL_1", transX1, transStack1 - 5);
    g2.drawString(transX1+" RL_2", transX1, transY1 - 5);
    g2.drawString(transX1+" RL_3", transXRight, transStackRight - 5);
    */
    right.moveTo(transX1, transStack1);
    right.lineTo(transX1, transY1);
    right.lineTo(transXRight, transStackRight);
    right.closePath();

    // pTopRight = new Point((int)transXRight, (int)transStackRight);
    // pBottomRight = pTopRight;
    }
    // g2.drawLine((int)pTopCenter.getX(), (int)pTopCenter.getY(), (int)pTopCenter.getX(), 0);
    }
    else
    { // handle negative value
    transY1 = (float) rangeAxis.valueToJava2D(y1 + stack1[0], dataArea,edge1);
    transStack1 = (float) rangeAxis.valueToJava2D(stack1[0], dataArea, edge1);
    transStackLeft = (float) rangeAxis.valueToJava2D(adjStackLeft[0], dataArea, edge1);

    // LEFT POLYGON
    if (y0 >= 0.0) // three points polygon : only half of the area is under X axis
    {
    /*
    g2.drawString(transX1+" -LG_1", transX1, transStack1 + 5);
    g2.drawString(transX1+" -LG_2", transX1, transY1 + 5);
    g2.drawString(transX1+" -LG_3", transXLeft, transStackLeft + 5);
    */
    left.moveTo(transX1, transStack1);
    left.lineTo(transX1, transY1);
    left.lineTo(transXLeft, transStackLeft);
    left.closePath();

    // pTopLeft = new Point((int)transXLeft, (int)transStackLeft);
    pTopCenter = new Point((int)transX1, (int)transY1);

    // pBottomLeft = pTopLeft;
    pBottomCenter = new Point((int)transX1, (int)transStack1);
    }
    else // four points polygon : all the are below X axis
    {
    double yleft = (y0 + y1) / 2.0 + stackLeft[0];

                transYLeft = \(float\) rangeAxis.valueToJava2D\(yleft, dataArea, edge1\);
    

    /*
    g2.drawString(transX1+" -LL_1", transX1, transY1 + 5);
    g2.drawString(transX1+" -LL_2", transX1, transStack1 + 5);
    g2.drawString(transX1+" -LL_3", transXLeft, transStackLeft + 5);
    g2.drawString(transX1+" -LL_4", transXLeft, transYLeft + 5);
    */
    left.moveTo(transX1, transY1);
    left.lineTo(transX1, transStack1);
    left.lineTo(transXLeft, transStackLeft);
    left.lineTo(transXLeft, transYLeft);
    left.closePath();

    // pTopLeft = new Point((int)transXLeft, (int)transYLeft);
    pTopCenter = new Point((int)transX1, (int)transY1);

    // pBottomLeft = new Point((int)transXLeft, (int)transStackLeft);
    pBottomCenter = new Point((int)transX1, (int)transStack1);
    }

    transStackRight = (float) rangeAxis.valueToJava2D( adjStackRight[0], dataArea, edge1);

    // RIGHT POLYGON
    if (y2 >= 0.0) // three points polygon : negative comes to positive on the edge...
    {
    /*
    g2.drawString(transX1+" -RG_1", transX1, transStack1 - 5);
    g2.drawString(transX1+" -RG_2", transX1, transY1 - 5);
    g2.drawString(transX1+" -RG_3", transXRight, transStackRight - 5);
    */
    right.moveTo(transX1, transStack1);
    right.lineTo(transX1, transY1);
    right.lineTo(transXRight, transStackRight);
    right.closePath();

    // pTopRight = new Point((int)transXRight, (int)transStackRight);
    // pBottomRight = new Point((int)transXRight, (int)transStack1);
    }
    else // four points polygon : all the area is under X axis
    {
    double yright = (y1 + y2) / 2.0 + stackRight[0];
    transYRight = (float) rangeAxis.valueToJava2D(yright, dataArea, edge1);
    /*
    g2.drawString(transX1+" -RL_1", transX1, transStack1 - 5);
    g2.drawString(transX1+" -RL_2", transX1, transY1 - 5);
    g2.drawString(transX1+" -RL_3", transXRight, transYRight - 5);
    g2.drawString(transX1+" -RL_4", transXRight, transStackRight - 5);
    */
    right.moveTo(transX1, transStack1);
    right.lineTo(transX1, transY1);
    right.lineTo(transXRight, transYRight);
    right.lineTo(transXRight, transStackRight);
    right.closePath();

    // pTopRight = new Point((int)transXRight, (int)transYRight);
    // pBottomRight = new Point((int)transXRight, (int)transStackRight);;
    }
    // g2.drawLine((int)pTopCenter.getX(), (int)pTopCenter.getY(), (int)pTopCenter.getX(), 0);
    }

    if (pass == 0)
    {
    if (pTopLeft!=null)
    seriesShape.addPoint( (int)pTopLeft.getX(), (int)pTopLeft.getY());

            if \(pTopCenter\!=null\)
                seriesShape.addPoint\( \(int\)pTopCenter.getX\(\), \(int\)pTopCenter.getY\(\)\);
    
            if \(pTopRight\!=null\)
                seriesShape.addPoint\( \(int\)pTopRight.getX\(\), \(int\)pTopRight.getY\(\)\);
    
            // put points into a previous values stack :            
            if \(pBottomLeft\!=null\)
                bottomPoints.push\(pBottomLeft\);
    
            if \(pBottomCenter\!=null\)
                bottomPoints.push\(pBottomCenter\);
    
            if \(pBottomRight\!=null\)
                bottomPoints.push\(pBottomRight\);
    
            if \(item==itemCount - 1\)
            \{
                while \(\!bottomPoints.isEmpty\(\)\)
                \{
                    Point p = \(Point\)bottomPoints.pop\(\);
                    seriesShape.addPoint\( \(int\)p.getX\(\), \(int\)p.getY\(\) \);
                \}
    
                Paint itemPaint = getItemPaint\(series, item\);
                g2.setPaint\(itemPaint\);
                g2.fill\(seriesShape\);
    
                if \(isOutline\(\)\) 
                \{
                    g2.setStroke\(getSeriesOutlineStroke\(series\)\);
                    g2.setPaint\(getSeriesOutlinePaint\(series\)\);
                    g2.draw\(seriesShape\);
                \}
    
                // create new polygon for next area 
                seriesShape = new Polygon\(\);
            \}
    

    }

    // add an entity for the item : shape created by left and right paths is used to generate a mouse hint...
    if (entities != null)
    {
    GeneralPath gp = new GeneralPath(left);
    gp.append(right, false);
    entityArea = gp;

            addEntity\(entities, entityArea, dataset, series, item, transX1, transY1\);
        \}
    

    }

    --
    V.

     

Get latest updates about Open Source Projects, Conferences and News.

Sign up for the SourceForge newsletter:





No, thanks