1) I have a number axis. I am using the latest jfree chart. Basically, my axis label is two long and I would like to split into three lines. I did the research in the newsgroup and I found that it is not implemened in the older versions. I tried playing with the latest version to no success. Could anybody tell me how to do this? I really need this.
2) Is it possible to place two labels on the axis. Something like
label a |
|
|
|
label b |
split axis label into 3 lines 2 Questions URGENT
-
- Posts: 11
- Joined: Fri Feb 03, 2006 9:27 pm
-
- Posts: 11
- Joined: Fri Feb 03, 2006 9:27 pm
Solution-Demo line chart
Here is the code for this problem. I had to re-implement drawLabel method to fit my requirements. I wrote a sample demo for it. The code is below
Code: Select all
package demo;
import java.awt.*;
import java.awt.geom.*;
import java.text.*;
import java.util.*;
import java.util.ArrayList;
import java.util.List;
import org.jfree.chart.*;
import org.jfree.chart.axis.*;
import org.jfree.chart.plot.*;
import org.jfree.data.time.*;
import java.util.Date;
import org.jfree.chart.servlet.*;
import org.jfree.chart.entity.*;
import javax.servlet.http.HttpSession;
import java.io.PrintWriter;
import org.jfree.chart.labels.*;
import org.jfree.data.xy.*;
import org.jfree.chart.renderer.xy.*;
import org.jfree.text.TextUtilities;
import java.awt.*;
import org.jfree.ui.RectangleEdge;
import org.jfree.ui.TextAnchor;
import org.jfree.ui.RectangleInsets;
public class Chart {
private JFreeChart TimeSeriesChart;
//private MyStackedBarRenderer myRenderer;
private double startRange, endRange, currentDate;
private double MOVE_FACTOR = 86400000;
private final String DEFAULT_LABEL_SOURCE_ORIENTATION = "Opportunity to ";
private JFreeChart createTimeSeriesChart() {
MyAxis domainAxis = new MyAxis("Month");
domainAxis.setAutoRangeTimePeriodClass(Month.class);
PeriodAxisLabelInfo[] info = new PeriodAxisLabelInfo[1];
//info[1] = new PeriodAxisLabelInfo(Day.class, new SimpleDateFormat("d"));
info[0] = new PeriodAxisLabelInfo(Month.class,new SimpleDateFormat("MMM"));
domainAxis.setLabelInfo(info);
TimePeriodValuesCollection coll2 = new TimePeriodValuesCollection ();
TimePeriodValues values2 = new TimePeriodValues ("PPO");
RegularTimePeriod period2 = null;
Date time2 = null;
double shift2 = currentDate;
double value2 = .1;
for (int i = 0; i < 150; i ++) {
shift2 += MOVE_FACTOR;
time2 = new Date ((long)shift2);
period2 = new Day (time2);
value2 += .01;
values2.add (period2,value2);
}
coll2.addSeries(values2);
DateAxis dateAxis2 = new DateAxis();
startRange = currentDate;
endRange = currentDate + MOVE_FACTOR*160;
dateAxis2.setRange(startRange, endRange);
String formatString2 = "MM/dd/yyyy";
DateFormat format2 = new SimpleDateFormat(formatString2);
dateAxis2.setDateFormatOverride(format2);
//need to supply the labelWidth in order to invoke drawItemLabel
String labelComponents = "Favoured|Performance@Target@" + DEFAULT_LABEL_SOURCE_ORIENTATION + "|Improve|Performance";
MyNumberAxis numberAxis2 = new MyNumberAxis (DEFAULT_LABEL_SOURCE_ORIENTATION,labelComponents);
numberAxis2.setLabelAngle((double)3.14/(double)2);
NumberFormat percentageFormat2 = new DecimalFormat ("###%");
numberAxis2.setNumberFormatOverride(percentageFormat2);
numberAxis2.setLowerBound(.5);
numberAxis2.setUpperBound(1.5);
XYItemRenderer renderer2 = new XYLineAndShapeRenderer();;
Marker marker = new ValueMarker(1);
//marker.setLabel("Target");
marker.setPaint(Color.BLUE);
marker.setLabelTextAnchor(TextAnchor.BASELINE_LEFT);
//float[] dashed = new float[] {10.0f, 4.0f};
//BasicStroke stroke = new BasicStroke(4.0f, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_BEVEL, 10.0f, dashed, 0.0f);
float[] dashed = new float[] {10.0f, 10.0f};
BasicStroke stroke = new BasicStroke(2, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_BEVEL, 10.0f, dashed, 10.0f);
marker.setOutlineStroke(stroke);
XYPlot plotDown = new XYPlot ();
plotDown.setRangeGridlinesVisible(false);
plotDown.setDomainGridlinesVisible(false);
plotDown.setDomainAxis(domainAxis);
plotDown.setRangeAxis(numberAxis2);
plotDown.setDataset(coll2);
plotDown.setRenderer(renderer2);
plotDown.addRangeMarker(marker);
Rectangle rectangle = new Rectangle (1,1);
//renderer2.set
plotDown.getRenderer().setSeriesShape(0,rectangle);
JFreeChart TimeSeriesChart = new JFreeChart (plotDown);
TimeSeriesChart.setBackgroundPaint(Color.WHITE);
return TimeSeriesChart;
}
public String getTimeSeriesChart (HttpSession session, PrintWriter pw) {
String filename = null;
try {
currentDate = (double)Calendar.getInstance().getTimeInMillis();
TimeSeriesChart = createTimeSeriesChart();
// Write the chart image to the temporary directory
ChartRenderingInfo info = new ChartRenderingInfo(new StandardEntityCollection());
filename = ServletUtilities.saveChartAsPNG(TimeSeriesChart, 500, 300, info, session);
// Write the image map to the PrintWriter
ChartUtilities.writeImageMap(pw, filename, info, false);
pw.flush();
} catch (Exception e) {
System.out.println("Exception - " + e.toString());
e.printStackTrace(System.out);
filename = "public_error_500x300.png";
}
return filename;
}
class myStandardXYItemLabelGenerator extends StandardXYItemLabelGenerator implements XYItemLabelGenerator
{
public myStandardXYItemLabelGenerator() {
super ();
}
public String generateLabel(XYDataset dataset, int series, int item) {
return "10%";
}
}
class MyNumberAxis extends NumberAxis {
public MyNumberAxis (String labelSourceOrientation, String labelComponents) {
super (labelSourceOrientation);
this.labelComponents = labelComponents;
this.labelSourceOrientation = labelSourceOrientation;
}
private static final int UPPER_LABEL =-1;
private static final int LOWER_LABEL = 1;
private static final int MIDDLE_LABEL = 0;
private double labelAlignmentAlongX = 0;
private String labelComponents;
private String labelSourceOrientation;
private Rectangle2D labelSouceOrientationBound;
private double biggestLabelBoundsWidth = 0;
private void drawLabelComponents (ArrayList labelComponents,Graphics2D g2,Rectangle2D dataArea,
AxisState state, int labelType) {
Font font = getLabelFont();
RectangleInsets insets = getLabelInsets();
g2.setFont(font);
if (labelType != MIDDLE_LABEL) {
g2.setPaint(getLabelPaint());
}else{
g2.setPaint(Color.BLUE);
}
FontMetrics fm = g2.getFontMetrics();
AffineTransform t;
List labelBoundsCollection = new ArrayList ();
double totalOfLabelBoundsHeight = 0;
//double biggestLabelBoundsWidth = 0;
Iterator compIt = labelComponents.iterator();
while (compIt.hasNext()) {
String labelComponent = (String)compIt.next();
Rectangle2D labelBounds = TextUtilities.getTextBounds(labelComponent, g2, fm);
t = AffineTransform.getRotateInstance(
getLabelAngle() - Math.PI / 2.0,
labelBounds.getCenterX(), labelBounds.getCenterY()
);
Shape rotatedLabelBounds = t.createTransformedShape(labelBounds);
labelBounds = rotatedLabelBounds.getBounds2D();
labelBoundsCollection.add(labelBounds);
if (labelBounds.getWidth() > biggestLabelBoundsWidth)
biggestLabelBoundsWidth = labelBounds.getWidth();
totalOfLabelBoundsHeight += labelBounds.getHeight();
}
double labelx;
double labely;
double startLabelYPosition =
dataArea.getCenterY() + labelType*(dataArea.getHeight()/4) - totalOfLabelBoundsHeight/2;
Iterator it = labelBoundsCollection.iterator();
int counter = 0;
while (it.hasNext()) {
//if true, it means that x-position along which all labels get are aligned is not set
Rectangle2D element = (Rectangle2D)it.next();
labelx = state.getCursor() - insets.getRight() - element.getWidth() / 2.0;
double distance = labelx-labelAlignmentAlongX;
labelx = labelx - 2*distance;
labely = startLabelYPosition;
startLabelYPosition += element.getHeight();
/*
* Centering works if you use this code
TextUtilities.drawRotatedString(
(String)labelComponents.get(counter), g2, (float) labelAlignmentAlongX, (float) labely, TextAnchor.CENTER,
getLabelAngle() - Math.PI / 2.0, TextAnchor.CENTER
);
*/
TextUtilities.drawRotatedString(
(String)labelComponents.get(counter), g2, (float) labelx, (float) labely, TextAnchor.CENTER,
getLabelAngle() - Math.PI / 2.0, TextAnchor.CENTER
);
counter ++;
}
}
/**
* Draws the axis label.
*
* @param label the label text.
* @param g2 the graphics device.
* @param plotArea the plot area.
* @param dataArea the area inside the axes.
* @param edge the location of the axis.
* @param state the axis state (<code>null</code> not permitted).
* @return Information about the axis.
*/
protected AxisState drawLabel(String label,
Graphics2D g2,
Rectangle2D plotArea,
Rectangle2D dataArea,
RectangleEdge edge,
AxisState state) {
// it is unlikely that 'state' will be null, but check anyway...
if (state == null) {
throw new IllegalArgumentException("Null 'state' argument.");
}
if ((label == null) || (label.equals(""))) {
return state;
}
String [] labels = new String [3];
StringTokenizer labelTokenizer = new StringTokenizer (labelComponents , "@");
ArrayList upperLabelComponentsCollection = new ArrayList ();
ArrayList lowerLabelComponentsCollection = new ArrayList ();
ArrayList middleLabelComponentsCollection = new ArrayList ();
int i = 0;
while (labelTokenizer.hasMoreElements()) {
labels[i] = labelTokenizer.nextToken();
i ++;
}
StringTokenizer upperLabelTokenizer = new StringTokenizer (labels[0], "|");
StringTokenizer middleLabelTokenizer = new StringTokenizer (labels[1], "|");
StringTokenizer lowerLabelTokenizer = new StringTokenizer (labels[2], "|");
while (upperLabelTokenizer.hasMoreElements()) {
upperLabelComponentsCollection.add(upperLabelTokenizer.nextToken());
}
while (middleLabelTokenizer.hasMoreElements()) {
middleLabelComponentsCollection.add(middleLabelTokenizer.nextToken());
}
while (lowerLabelTokenizer.hasMoreElements()) {
String token = lowerLabelTokenizer.nextToken();
lowerLabelComponentsCollection.add(token);
if (token.equals(labelSourceOrientation)) {
Font font = getLabelFont();
g2.setFont(font);
g2.setPaint(getLabelPaint());
FontMetrics fm = g2.getFontMetrics();
Rectangle2D labelBounds = TextUtilities.getTextBounds(token, g2, fm);
AffineTransform t = AffineTransform.getRotateInstance(
getLabelAngle() - Math.PI / 2.0,
labelBounds.getCenterX(), labelBounds.getCenterY()
);
Shape rotatedLabelBounds = t.createTransformedShape(labelBounds);
labelBounds = rotatedLabelBounds.getBounds2D();
labelSouceOrientationBound = labelBounds;
labelAlignmentAlongX =
state.getCursor() - getLabelInsets().getRight() - labelSouceOrientationBound.getWidth() / 2.0;
}
}
drawLabelComponents (upperLabelComponentsCollection, g2,dataArea,state, UPPER_LABEL);
drawLabelComponents (middleLabelComponentsCollection, g2,dataArea,state, MIDDLE_LABEL);
drawLabelComponents (lowerLabelComponentsCollection, g2,dataArea,state, LOWER_LABEL);
state.cursorLeft(getLabelInsets().getLeft() + biggestLabelBoundsWidth + getLabelInsets().getRight());
return state;
}
}
class MyAxis extends PeriodAxis {
public MyAxis (String label) {
super(label);
}
protected void drawTickMarksHorizontal(Graphics2D g2, AxisState state,
Rectangle2D dataArea,
RectangleEdge edge) {
List ticks = new ArrayList();
double x0 = dataArea.getX();
double y0 = state.getCursor();
double insideLength = getTickMarkInsideLength();
double outsideLength = getTickMarkOutsideLength();
RegularTimePeriod t = RegularTimePeriod.createInstance(
super.getMajorTickTimePeriodClass(), super.getFirst().getStart(), getTimeZone());
long t0 = t.getFirstMillisecond(getTimeZone());
Line2D inside = null;
Line2D outside = null;
long firstOnAxis = getFirst().getFirstMillisecond(getTimeZone());
long lastOnAxis = getLast().getLastMillisecond(getTimeZone());
while (t0 <= lastOnAxis) {
ticks.add(new NumberTick(new Double(t0), "", TextAnchor.CENTER, TextAnchor.CENTER, 0.0));
x0 = valueToJava2D(t0, dataArea, edge);
if (edge == RectangleEdge.TOP) {
inside = new Line2D.Double(x0, y0, x0, y0 + insideLength);
outside = new Line2D.Double(x0, y0, x0, y0 - outsideLength);
}
else if (edge == RectangleEdge.BOTTOM) {
inside = new Line2D.Double(x0, y0, x0, y0 - insideLength);
outside = new Line2D.Double(x0, y0, x0, y0 + outsideLength);
}
if (t0 > firstOnAxis) {
/*
g2.setPaint(getTickMarkPaint());
g2.setStroke(getTickMarkStroke());
g2.draw(inside);
g2.draw(outside);
*/
g2.setPaint(getTickMarkPaint());
g2.setStroke(getTickMarkStroke());
g2.draw(inside);
//g2.setPaint(Color.WHITE);
//g2.setStroke(getTickMarkStroke());
//g2.draw(outside);
}
// draw minor tic
if (false) {
RegularTimePeriod tminor = RegularTimePeriod.createInstance(
super.getMinorTickTimePeriodClass(), new Date(t0), getTimeZone());
long tt0 = tminor.getFirstMillisecond(getTimeZone());
while (tt0 < t.getLastMillisecond(getTimeZone())
&& tt0 < lastOnAxis) {
double xx0 = valueToJava2D(tt0, dataArea, edge);
if (edge == RectangleEdge.TOP) {
inside = new Line2D.Double(xx0, y0, xx0, y0 + super.getMinorTickMarkInsideLength());
outside = new Line2D.Double(xx0, y0, xx0, y0 - super.getMinorTickMarkOutsideLength());
}
else if (edge == RectangleEdge.BOTTOM) {
inside = new Line2D.Double(xx0, y0, xx0, y0 - super.getMinorTickMarkInsideLength());
outside = new Line2D.Double(xx0, y0, xx0, y0 + super.getMinorTickMarkOutsideLength());
}
if (tt0 >= firstOnAxis) {
g2.setPaint(super.getMinorTickMarkPaint());
g2.setStroke(super.getMinorTickMarkStroke());
g2.draw(inside);
g2.draw(outside);
}
tminor = tminor.next();
tt0 = tminor.getFirstMillisecond(getTimeZone());
}
}
t = t.next();
t0 = t.getFirstMillisecond(getTimeZone());
}
if (edge == RectangleEdge.TOP) {
state.cursorUp(Math.max(outsideLength, super.getMinorTickMarkOutsideLength()));
}else if (edge == RectangleEdge.BOTTOM) {
state.cursorDown(Math.max(outsideLength, super.getMinorTickMarkOutsideLength()));
}
state.setTicks(ticks);
}
}
class MyTimeSeriesRenderer extends DefaultXYItemRenderer
{
private myStandardXYItemLabelGenerator myXYItemLabelGenerator;
MyTimeSeriesRenderer () {
super();
myXYItemLabelGenerator = new myStandardXYItemLabelGenerator();
}
/*
protected void drawItemLabel(Graphics2D g2, PlotOrientation orientation,
XYDataset dataset, int series, int item, double x, double y,
boolean negative) {
//XYItemLabelGenerator generator = getItemLabelGenerator(series, item);
XYItemLabelGenerator generator = this.myXYItemLabelGenerator;
if (generator != null) {
Font labelFont = getItemLabelFont(series, item);
Paint paint = getItemLabelPaint(series, item);
g2.setFont(labelFont);
g2.setPaint(paint);
String label = generator.generateLabel(dataset, series, item);
System.out.println("The label is" + label);
ItemLabelPosition position = null;
if (!negative) {
position = getPositiveItemLabelPosition(series, item);
}
else {
position = getNegativeItemLabelPosition(series, item);
}
// work out the label anchor point...
Point2D anchorPoint = calculateLabelAnchorPoint(
position.getItemLabelAnchor(), x, y, orientation);
TextUtilities.drawRotatedString(label, g2,
(float) anchorPoint.getX(), (float) anchorPoint.getY(),
position.getTextAnchor(), position.getAngle(),
position.getRotationAnchor());
}
}
*/
/*
public LegendItem getLegendItem(int datasetIndex, int series) {
//don't draw the first series because it is not data-relevant.
if(series == 0)
return null;
return super.getLegendItem(datasetIndex, series);
}
public void
drawItem(Graphics2D g2, CategoryItemRendererState state,
Rectangle2D dataArea, CategoryPlot plot, CategoryAxis domainAxis,
ValueAxis rangeAxis, CategoryDataset dataset, int row, int column, int pass) {
Object oldValue = g2.getRenderingHint(RenderingHints.KEY_ANTIALIASING);
Object newValue = RenderingHints.VALUE_ANTIALIAS_OFF;
boolean valueChanged = false;
if (oldValue == null || !oldValue.equals(newValue)) {
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, newValue);
valueChanged = true;
}
super.drawItem
(g2,state,dataArea,plot,domainAxis,rangeAxis,dataset,row,column,pass);
if (valueChanged) {
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, oldValue);
}
}
}
*/
}
}