TickMarks in CategoryAxis?

A discussion forum for JFreeChart (a 2D chart library for the Java platform).
Locked
Tobi

TickMarks in CategoryAxis?

Post by Tobi » Thu Jul 29, 2004 8:52 am

Hi,

why can i not draw TickMarks in a Category Axis? A Value or Number Axis can do and a Category Axis not?

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 Jul 29, 2004 2:30 pm

The code to draw the tick marks hasn't been added to the CategoryAxis class yet. The implementation will need an extra flag to determine whether the tick marks are placed in the center of each category, or used to mark the boundary between two categories. It is on the to-do list (but has been for a long time, it isn't near the top of my list).
David Gilbert
JFreeChart Project Leader

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

Tobi

Post by Tobi » Thu Jul 29, 2004 2:37 pm

I've today developed a solution by myself. I added a method to draw TickMarks in CategoryAxis Class. The Marks are drawn at the position of the GridLines.

But now i've seen another problem. For example in a CategoryDataset with one series an a Bar3D Renderer. The first category is centered with the gridline, the second category is more to left 1Pixel (not centered) and many many categories again, the gridline and the Bar are completely wrong (xxx Pixels)

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 Jul 29, 2004 2:45 pm

With the 3D renderer, you must also use the 3D axis...it is all an ugly hack. The 3D "effect" adds nothing to the information that your chart conveys - I recommend just using a 2D bar chart.
David Gilbert
JFreeChart Project Leader

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

Tobi

Post by Tobi » Thu Jul 29, 2004 5:04 pm

OK now i've tried with 3D Axis and it works fine. But the GridLines are still drawn wrong. Now I've used the same method to recalculate coordinates as in 3D Axis and overwrite the drawDomainGridlines etc. methods, this works well. But is there not a standard solution?

I'm using CategoryAxis3D, BarRenderer3D and CategoryPlot, why are the Gridlines in standard not painted correct? Or is the fault on my side?

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 » Fri Jul 30, 2004 10:16 am

You've found a bug. I've updated the CategoryAxis3D class and committed the change to CVS for the next release (0.9.21).

The change is to add this method:

Code: Select all

    /**
     * Returns the Java 2D coordinate for a category.
     * 
     * @param anchor  the anchor point.
     * @param category  the category index.
     * @param categoryCount  the category count.
     * @param area  the data area.
     * @param edge  the location of the axis.
     * 
     * @return the coordinate.
     */
    public double getCategoryJava2DCoordinate(CategoryAnchor anchor, 
                                              int category, 
                                              int categoryCount, 
                                              Rectangle2D area,
                                              RectangleEdge edge) {
    
        double result = 0.0;
        Rectangle2D adjustedArea = area;
        CategoryPlot plot = (CategoryPlot) getPlot();
        CategoryItemRenderer renderer = plot.getRenderer();
        if (renderer instanceof Effect3D) {
            Effect3D e3D = (Effect3D) renderer;
            double adjustedX = area.getMinX();
            double adjustedY = area.getMinY();
            double adjustedW = area.getWidth() - e3D.getXOffset();
            double adjustedH = area.getHeight() - e3D.getYOffset();

            if (edge == RectangleEdge.LEFT || edge == RectangleEdge.BOTTOM) {
                adjustedY += e3D.getYOffset();
            }
            else if (edge == RectangleEdge.RIGHT || edge == RectangleEdge.TOP) {
                adjustedX += e3D.getXOffset();
            }
            adjustedArea = new Rectangle2D.Double(
                adjustedX, adjustedY, adjustedW, adjustedH
            );
        }

        if (anchor == CategoryAnchor.START) {
            result = getCategoryStart(category, categoryCount, adjustedArea, edge);
        }
        else if (anchor == CategoryAnchor.MIDDLE) {
            result = getCategoryMiddle(category, categoryCount, adjustedArea, edge);
        }
        else if (anchor == CategoryAnchor.END) {
            result = getCategoryEnd(category, categoryCount, adjustedArea, edge);
        }
        return result;
                                                      
    }
                                              
David Gilbert
JFreeChart Project Leader

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

Tobi

Post by Tobi » Fri Jul 30, 2004 4:02 pm

I have done this in my custom Axis class, too.
I needed a CategoryAxis which automatically find out if its 3D or 2D mode, and i need multiline Tick Labels. So i've decided to make a new class extended from CategoryAxis.

rs20021

need to add tick marks for the category axis

Post by rs20021 » Mon Aug 02, 2004 4:29 pm

Tobi,

I am using a regular bar chart and want to display the tick marks on the category axis...aligned to the center... Can I see the workaround code you did for this... till the cvs release comes through


thanks

Tobi
Posts: 12
Joined: Fri Jul 30, 2004 4:12 pm
Location: Black Forrest, Germany
Contact:

Post by Tobi » Mon Aug 02, 2004 4:52 pm

Hi,

i have created a new Class extended from CategoryAxis and added these modified methods, works in 2D or 3D mode:

Code: Select all

    /**
     * Draws the axis on a Java 2D graphics device (such as the screen or a printer).
     *
     * @param g2  the graphics device (<code>null</code> not permitted).
     * @param cursor  the cursor location.
     * @param plotArea  the area within which the axis should be drawn (<code>null</code> not
     *                  permitted).
     * @param dataArea  the area within which the plot is being drawn (<code>null</code> not
     *                  permitted).
     * @param edge  the location of the axis (<code>null</code> not permitted).
     * @param plotState  collects information about the plot (<code>null</code> permitted).
     *
     * @return the axis state (never <code>null</code>).
     */
    public AxisState draw(Graphics2D g2,
                          double cursor,
                          Rectangle2D plotArea,
                          Rectangle2D dataArea,
                          RectangleEdge edge,
                          PlotRenderingInfo plotState) {

    	AxisState state = new AxisState(cursor);
    	
        // if the axis is not visible, don't draw it...
        if (!isVisible()) {
            return new AxisState(cursor);
        }
        
        CategoryPlot plot = (CategoryPlot) getPlot();
        
        Rectangle2D adjustedDataArea = new Rectangle2D.Double();
        if (plot.getRenderer() instanceof Effect3D) {
            Effect3D e3D = (Effect3D) plot.getRenderer();
            double adjustedX = dataArea.getMinX();
            double adjustedY = dataArea.getMinY();
            double adjustedW = dataArea.getWidth() - e3D.getXOffset();
            double adjustedH = dataArea.getHeight() - e3D.getYOffset();

            if (edge == RectangleEdge.LEFT || edge == RectangleEdge.BOTTOM) {
                adjustedY += e3D.getYOffset();
            }
            else if (edge == RectangleEdge.RIGHT || edge == RectangleEdge.TOP) {
                adjustedX += e3D.getXOffset();
            }
            adjustedDataArea.setRect(adjustedX, adjustedY, adjustedW, adjustedH);
        }
        else {
            adjustedDataArea.setRect(dataArea);
        }
        
        if (isAxisLineVisible()) {
            drawAxisLine(g2, cursor, adjustedDataArea, edge);
        }
                
        // draw the category labels and axis label
        state = drawTickMarks(g2, cursor, plotArea, adjustedDataArea, edge);
        state = drawCategoryLabels(g2, plotArea, adjustedDataArea, edge, state, plotState);
        state = drawLabel(getLabel(), g2, plotArea, dataArea, edge, state);

        return state;

    }
    
    /**
     * 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 drawTickMarks(Graphics2D g2,
                                      double cursor,
                                      Rectangle2D plotArea,
                                      Rectangle2D dataArea,
                                      RectangleEdge edge) {

        AxisState state = new AxisState(cursor);
        
        double ol = getTickMarkOutsideLength();
        double il = getTickMarkInsideLength();

        List ticks = refreshTicks(g2, state, plotArea, dataArea, edge);
        state.setTicks(ticks);
        Iterator iterator = ticks.iterator();
        int cnt = 0;
        
        while (iterator.hasNext()) {
            CategoryTick tick = (CategoryTick) iterator.next();
            
            if (isTickMarksVisible()) {
                float xx = (float) translateValueToJava2D(cnt, 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);
            }

            cnt++;
        }

        return state;
    }
    
    public double translateValueToJava2D(int count,
            Rectangle2D area,
            RectangleEdge edge) {
    
    	CategoryPlot plot = (CategoryPlot)getPlot();
    	CategoryAnchor anchor = plot.getDomainGridlinePosition();
        RectangleEdge domainAxisEdge = edge;//plot.getDomainAxisEdge();
        CategoryDataset data = plot.getDataset();
            if (data != null) {
                CategoryAxis axis = plot.getDomainAxis();
                if (axis != null) {
                    int columnCount = data.getColumnCount();
                    return axis.getCategoryJava2DCoordinate(
                            anchor, count, columnCount, area, domainAxisEdge
                        );
                }
            }
    
            return 0.0d;
    }
Now you have to set TickMarks visible like this:

YourAxis.setTickMarksVisible(true);

Hope this helps you?

Greetings,
Tobi

rs20021

TickMarks in CategoryAxis?

Post by rs20021 » Mon Aug 02, 2004 5:41 pm

tobi,

thank you for the code.... however I did wat u suggested and I still do not see the tick marks

public class extendedCategoryAxis extends CategoryAxis{

................added all the 3 methods you suggested

}


Compiled the class and then used the code in my calling servlet

In my main code:
NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
rangeAxis.setRange(rangeAxis.getLowerBound(), rangeAxis.getUpperBound() );
extendedCategoryAxis cAxis = (extendedCategoryAxis)plot.getDomainAxis();
cAxis.setTickMarksVisible(true);


But it still does not work?? This is a regular bar chart not 3D.....Any suggestions...

Tobi
Posts: 12
Joined: Fri Jul 30, 2004 4:12 pm
Location: Black Forrest, Germany
Contact:

Post by Tobi » Mon Aug 02, 2004 6:02 pm

Maybe try plot.setDomainAxis(cAxis) after doing all this.
And/or:

cAxis.setTickMarkOutsideLength(float length);
cAxis.setTickMarkPaint(axisPaint);

to set a real paint!

If it doesn't work, try to find out if your application goes into the modified method "draw" of the new class extendedCategoryAxis. If not you have to find the fault, why not.

If there are no compiling errors, the new class should work fine, in 2D AND 3D!

rs20021

CategoryAxis Ticks display

Post by rs20021 » Mon Aug 02, 2004 6:29 pm

Tobi,

I had to do the following and it worked

tx so much for your help

MyCategoryAxis ca = new MyCategoryAxis();
ca.setTickMarksVisible(true);
ca.setTickMarkOutsideLength(2.0f);
ca.setTickMarkPaint(Color.black);
plot.setDomainAxis(ca);

Guest

Post by Guest » Tue Nov 02, 2004 3:50 am

How do i modify the above code to customize the domain margin for each ticks. I am using category dataset. Urgently need help. Thx.

Tobi
Posts: 12
Joined: Fri Jul 30, 2004 4:12 pm
Location: Black Forrest, Germany
Contact:

Post by Tobi » Mon Nov 22, 2004 5:29 pm

What margin do you mean?

Locked