split axis label into 3 lines 2 Questions URGENT

A discussion forum for JFreeChart (a 2D chart library for the Java platform).
Locked
prolaznik22
Posts: 11
Joined: Fri Feb 03, 2006 9:27 pm

split axis label into 3 lines 2 Questions URGENT

Post by prolaznik22 » Thu Jun 01, 2006 8:17 pm

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 |

prolaznik22
Posts: 11
Joined: Fri Feb 03, 2006 9:27 pm

Solution-Demo line chart

Post by prolaznik22 » Sat Jun 03, 2006 4:06 pm

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);

    }

 }

}
*/
}
	
}





Locked