DateAxis Questions/Problems

A discussion forum for JFreeChart (a 2D chart library for the Java platform).
Mottfried
Posts: 14
Joined: Mon Jul 24, 2006 10:51 am

DateAxis Questions/Problems

Post by Mottfried » Wed Jul 26, 2006 9:34 am

First, i read the whole Forum - but didnt found an answer...and iam not a java2d-pro. At this time my company looks forward to replace our old bfo-components with jfreechart.

My Questions are :
* Is it possible to print the TickLabels for the DateAxis vertical and/or can i rotate those TickLabels ? Please a simple example.
* At the right end of the x-Axis (DateAxis) the last TickLabel is cut off. How can i fix that ?
* I use a custom shape. How can i print this rectangle with a black border an a white filling ? At present i use this codefragment:

Code: Select all

markerRenderer.setSeriesPaint(0, Color.black);
markerRenderer.setSeriesLinesVisible(0, false);
markerRenderer.setSeriesShapesVisible(0, true);
markerRenderer.setSeriesShape(0, new java.awt.Rectangle(-5,-5,10,10));
markerRenderer.setSeriesOutlinePaint(0, Color.black);
markerRenderer.setDrawOutlines(true);
Thanks for your help.

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

Re: DateAxis Questions/Problems

Post by david.gilbert » Wed Jul 26, 2006 2:27 pm

Mottfried wrote:* Is it possible to print the TickLabels for the DateAxis vertical and/or can i rotate those TickLabels ? Please a simple example.
Yes. The DateAxis inherits the setVerticalTickLabels(boolean) method.
Mottfried wrote:* At the right end of the x-Axis (DateAxis) the last TickLabel is cut off. How can i fix that ?
This is a known bug that I haven't gotten around to fixing. A workaround would be to modify the plot or chart insets to leave more white space at the right of the chart.
Mottfried wrote:* I use a custom shape. How can i print this rectangle with a black border an a white filling ? At present i use this codefragment:

Code: Select all

markerRenderer.setSeriesPaint(0, Color.black);
markerRenderer.setSeriesLinesVisible(0, false);
markerRenderer.setSeriesShapesVisible(0, true);
markerRenderer.setSeriesShape(0, new java.awt.Rectangle(-5,-5,10,10));
markerRenderer.setSeriesOutlinePaint(0, Color.black);
markerRenderer.setDrawOutlines(true);
Is markerRenderer an XYLineAndShapeRenderer? If so, check out setUseFillPaint() and setUseOutlinePaint().
David Gilbert
JFreeChart Project Leader

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

Mottfried
Posts: 14
Joined: Mon Jul 24, 2006 10:51 am

Post by Mottfried » Wed Jul 26, 2006 2:56 pm

Wonderful, thanks a lot for the quick help.

Just a little question, if i use setVerticalTickLabels(boolean) the labels are rotated by 270 degree (if it is counterclockwise), but a rotation by 90 degrees clockwise, would be correct for left-to-right-readers. Is it possible to print it in the other vertical-style ? Or should i modifiy the drawing-routine ?

jwenting
Posts: 157
Joined: Sat Jul 15, 2006 7:46 am

Post by jwenting » Thu Jul 27, 2006 3:11 pm

To remove the extra ticklabel from the axis, add the following to refreshTicksHorizontal:

Code: Select all

        Tick tick = (Tick) result.get(result.size()-1);
        if (tick instanceof DateTick && isRunsOffScale(g2, (DateTick) tick,
                                                       dataArea, edge)) {
            result.remove(tick);
        }
right before the return statement.

Code: Select all

    public boolean isRunsOffScale(Graphics2D g, DateTick tick,Rectangle2D dataArea,
            RectangleEdge edge) {
        double imageWidth = g.getClipBounds().getMaxX();
        FontMetrics fm = g.getFontMetrics(g.getFont());
        double position = valueToJava2D(tick.getDate().getTime(), dataArea, edge);
        // divide stringWidth by 2 becayse valueToJava2D returns the centerpoint
        // for the label, not the left edge
        double right = position + (fm.stringWidth(tick.getText()) / 2);
        boolean result = (right > imageWidth);
        return result;
    }
We had the same problem and decided to fix it in our own code, feel free to incorporate it into the next release.

I'm now involved in patching the valueaxis to allow tickmarks to be drawn but the labels skipped (customer requirement, they want ticks for every work day but only 1 label per week (for example)).

velazquezs
Posts: 8
Joined: Tue Apr 11, 2006 11:10 pm

Post by velazquezs » Sat Aug 12, 2006 12:52 am

Hi jwenting,

Is it posible to provide the modified version of DateAxis and ValueAxis?

I'm trying to plot tick mark labels for a DateAxis each 15 days starting from day 01, so no matter the data set, it would print tick marks for 01, 15 or 30

Cheers!

jwenting
Posts: 157
Joined: Sat Jul 15, 2006 7:46 am

Post by jwenting » Wed Aug 16, 2006 2:39 pm

Those 2 snippets are all you need to add to the DateAxis to remove the last tick (and label) if it would get cut off.

I'm working myself on a modified DateAxis (or ValueAxis) that will allow tickmarks to be drawn even if the ticklabels are not (because they'd overlap for example).
Problem of course is that if the axis gets really dense (minute interval on a year long chart that's only a few hundred pixels wide for example) you'd get the tickmarks themselves too close together or overlapping.
Ideally the axis would allow a setting that would indicate how many tickmarks to draw between each printed ticklabel, but I'm far from achieving that.

To also get rid of first labels that run off the left of the axis, you need to do a bit more.

Code: Select all

    private double tickLabelWidth;
    private Double previous;
    public boolean isHiddenValue(Date time, Rectangle2D area, RectangleEdge edge) {
        boolean hidden = !getTimeline().containsDomainValue(time);
        if (!hidden) {
            double current = valueToJava2D(time.getTime(), area, edge);
            if (previous != null) {
                if ((current - previous) < tickLabelWidth)  {
                    return true;
                }
            }
            previous = current;
            if (current < area.getX()) {
                hidden = true;
            } else if(current >= area.getMaxX()) {
                hidden = true;
            }
        }
        return hidden;
    }
    protected List refreshTicksHorizontal(Graphics2D g2, Rectangle2D dataArea,
            RectangleEdge edge) {
        previous = null;
        List<Tick> result = new java.util.ArrayList<Tick>();

        Font tickLabelFont = getTickLabelFont();
        g2.setFont(tickLabelFont);

        if (isAutoTickUnitSelection()) {
            selectAutoTickUnit(g2, dataArea, edge);
        }


        Date lowerDate = getMinimumDate();
        Date upperDate = getMaximumDate();
        lowerDate = forwardToVisibleSectionIfHidden(getTimeline(), lowerDate);
        upperDate = forwardToVisibleSectionIfHidden(getTimeline(), upperDate);
        selectHorizontalAutoTickUnitEnhanced(g2, dataArea, edge,
                lowerDate.getTime(), upperDate.getTime());

        DateTickUnit unit = getTickUnit();
        // Shift start date to the round units for this type
        Date tickDate = alignToUnit(unit, lowerDate);
        upperDate = alignToUnit(unit, upperDate);
        boolean hiddenValue;
        while (!tickDate.after(upperDate)) {
        //while (tickDate.before(upperDate)) {
            hiddenValue = isHiddenValue(tickDate, dataArea, edge);
            if (hiddenValue) {
                tickDate = unit.rollDate(tickDate);
                tickDate = alignToUnit(unit, tickDate);
            } else {
                // work out the value, label and position
                String tickLabel;
                DateFormat formatter = getDateFormatOverride();
                if (formatter != null) {
                    tickLabel = formatter.format(tickDate);
                } else {
                    tickLabel = getTickUnit().dateToString(tickDate);
                }
                TextAnchor anchor = null;
                TextAnchor rotationAnchor = null;
                double angle = 0.0;
                if (isVerticalTickLabels()) {
                    anchor = TextAnchor.CENTER_RIGHT;
                    rotationAnchor = TextAnchor.CENTER_RIGHT;
                    if (edge == RectangleEdge.TOP) {
                        angle = Math.PI / 2.0;
                    } else {
                        angle = -Math.PI / 2.0;
                    }
                } else {
                    if (edge == RectangleEdge.TOP) {
                        anchor = TextAnchor.BOTTOM_CENTER;
                        rotationAnchor = TextAnchor.BOTTOM_CENTER;
                    } else {
                        anchor = TextAnchor.TOP_CENTER;
                        rotationAnchor = TextAnchor.TOP_CENTER;
                    }
                }

                Tick tick = new DateTick(tickDate, tickLabel, anchor,
                        rotationAnchor, angle);
                result.add(tick);
                tickDate = unit.addToDate(tickDate);
                tickDate = alignToUnit(unit, tickDate);
            }
        }

        if (result.size() >= 1) {
            Tick tick = result.get(result.size() - 1);
            if (tick instanceof DateTick && isRunsOffScale(g2, (DateTick) tick,
                dataArea, edge)) {
                result.remove(tick);
            }
        }
        return result;
    }
    public boolean isRunsOffScale(Graphics2D g, DateTick tick,Rectangle2D dataArea,
            RectangleEdge edge) {
        double imageWidth = g.getClipBounds().getMaxX();
        FontMetrics fm = g.getFontMetrics(g.getFont());
        double position = valueToJava2D(tick.getDate().getTime(), dataArea, edge);
        // divide stringWidth by 2 becayse valueToJava2D returns the centerpoint
        // for the label, not the left edge
        double right = position + (fm.stringWidth(tick.getText()) / 2);
        boolean result = (right > imageWidth);
        return result;
    }

velazquezs
Posts: 8
Joined: Tue Apr 11, 2006 11:10 pm

Post by velazquezs » Wed Aug 16, 2006 10:05 pm

Thanks jwenting,

I cheked jfreechart DateAxis code and the code you provided and got a basic working version of the task I'm trying to achive.

These are the interface methods I've added/modified:

Code: Select all

class ModifiedDateValueAxis extends ValueAxis implements Cloneable, Serializable {
....

public void setFirstDateAxis(Date firstDateAxis) {
	this.firstDateAxis = firstDateAxis;
	
}

public void setLastDateAxis(Date lastDateAxis) {
	this.lastDateAxis = lastDateAxis;
}

public void refreshRange() {
	DateRange dr = new DateRange(getFirstDateAxis(), getLastDateAxis());
	this.setRange(dr);
}

protected List refreshTicksHorizontal(Graphics2D g2,
                                          Rectangle2D dataArea,
                                          RectangleEdge edge) {
....
}

Cheers!

jwenting
Posts: 157
Joined: Sat Jul 15, 2006 7:46 am

Post by jwenting » Fri Aug 18, 2006 2:16 pm

my pleasure.
Getting along nicely with my modifications to bludgeon that axis generation into shape ;)

jwenting
Posts: 157
Joined: Sat Jul 15, 2006 7:46 am

Post by jwenting » Fri Aug 18, 2006 6:22 pm

Here's a small sample of what I have so far...

Image

For some reason it extends the domain axis beyond the point it should go, but I'll figure that out monday.

manish
Posts: 10
Joined: Tue Aug 01, 2006 7:24 am

Post by manish » Wed Aug 23, 2006 8:39 am

hi,
At the right end of the x-Axis (DateAxis) the last TickLabel is cut off. How can i fix that ?
i have read the post by dave so it has been fixed yet or not.
if not fixed then how i can get the blank space on right of x-axis.
plz help me out its urgent.
my code for chart is here:-

XYPlot plot = (XYPlot) chart.getPlot();
plot.setDomainCrosshairVisible(true);
plot.setRangeCrosshairVisible(true);

XYItemRenderer r = plot.getRenderer();
if (r instanceof XYLineAndShapeRenderer) {
XYLineAndShapeRenderer renderer = (XYLineAndShapeRenderer) r;
renderer.setBaseShapesVisible(true);
renderer.setBaseShapesFilled(true);

}
DateAxis axis = (DateAxis) plot.getDomainAxis();

DateTickUnit dateTickUnit = new DateTickUnit(1,1,new SimpleDateFormat("MMM-yyyy"));
axis.setTickUnit(dateTickUnit);

return chart;

matinh
Posts: 483
Joined: Fri Aug 11, 2006 10:08 am
Location: Austria

Post by matinh » Wed Aug 23, 2006 11:45 am

Hi Mottfried!

I don't know if there is a version around where this bug has been addressed. But if not try something like this

Code: Select all

theChart.getPlot().setInsets(new RectangleInsets(UnitType.ABSOLUTE, 0, 0, 0, 30));
Adapt "30" to your needs, depending on your labels and font settings.

hth,
- martin

jwenting
Posts: 157
Joined: Sat Jul 15, 2006 7:46 am

Post by jwenting » Wed Aug 23, 2006 6:23 pm

manish wrote:hi,
At the right end of the x-Axis (DateAxis) the last TickLabel is cut off. How can i fix that ?
That's exactly what the code I posted will help correct...

onkar
Posts: 2
Joined: Wed Nov 01, 2006 8:02 am

Re: DateAxis Questions/Problems

Post by onkar » Wed Nov 01, 2006 8:09 am

david.gilbert wrote:
Mottfried wrote:* Is it possible to print the TickLabels for the DateAxis vertical and/or can i rotate those TickLabels ? Please a simple example.
Yes. The DateAxis inherits the setVerticalTickLabels(boolean) method.
Would anyone tell me how to rotate tick labels at say 45 degree or for that matter at any angle ? Because setVerticalTickLabels makes them to rotate by 90 degree only !

Thanks in advance !

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

Re: DateAxis Questions/Problems

Post by david.gilbert » Wed Nov 01, 2006 10:25 am

onkar wrote:Would anyone tell me how to rotate tick labels at say 45 degree or for that matter at any angle ? Because setVerticalTickLabels makes them to rotate by 90 degree only !
90 degrees is the only supported option in DateAxis and NumberAxis at present.
David Gilbert
JFreeChart Project Leader

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

onkar
Posts: 2
Joined: Wed Nov 01, 2006 8:02 am

Re: DateAxis Questions/Problems

Post by onkar » Thu Nov 02, 2006 4:35 am

david.gilbert wrote:90 degrees is the only supported option in DateAxis and NumberAxis at present.
Hi David,
I was trying to rotate the tick labels by modifying angle in the method
'refreshTicksVertical' of class DateAxis. But i am not getting the orientation of the tick labels right e.g. The date '03-03-2006:12.30' gets rotated
around '.30' and not around '03' which i want.

Any inputs ?















;

Locked