new patch posted, skip category labels and tick marks

A discussion forum for JFreeChart (a 2D chart library for the Java platform).
Locked
ray lukas
Posts: 12
Joined: Thu Jul 06, 2006 6:18 pm
Location: Cambridge MA

new patch posted, skip category labels and tick marks

Post by ray lukas » Tue Aug 01, 2006 8:49 pm

:D Simply go to the Patch section of the JFreeChart page. The id for this post is 1532660 the title is CategoryAxis Skip Labels and Tick Marks. Posted today, August 01, 2006..

the code is documented and has been tested. It seems to work pretty well.
of all the things I lost, I miss my mind the most

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 » Wed Aug 02, 2006 3:25 pm

Thanks Ray. I will give this a run once I've got 1.0.2 out the door (in the next couple of days I hope). If other developers have a chance to try this out and comment, that would be quite a help...
David Gilbert
JFreeChart Project Leader

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

ray lukas
Posts: 12
Joined: Thu Jul 06, 2006 6:18 pm
Location: Cambridge MA

hey thanks man..

Post by ray lukas » Wed Aug 02, 2006 7:32 pm

I would like to make one small change to my code before I head off into the great white north.

The spacing of the category labels is dead on.. But it would be better if there was a gap between them.. This code change will provide such a gap.. I really should have written a setter method for CATEGORY_GAP_SIZE but.. I will add that simple method in when I get a chance.. For now 8 pixels seems to look pretty good..

Here is the change real quick..

I know I have to add comments, which I will do.

Code: Select all

package chartingTest;

import java.awt.Shape;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.List;
import java.util.Vector;
import java.util.Iterator;

import org.jfree.chart.axis.CategoryTick;

public class LabelDefs extends Vector {
	public static int CATEGORY_TICK = 0;
	public static int BOUNDS = 1;
	public static int ANCHOR_POINT = 2;
	public static int DRAWN = 3;
	public static int TICK_MARK_LINE = 4;
	
	private static double CATEGORY_GAP_SIZE = 8.0;
	
	
	public void add(String name, CategoryTick tick, Line2D mark, Shape bounds, Point2D anchorPoint){
		this.add(new LabelDef(name, tick, mark, bounds, anchorPoint));
	}
	public Shape getCandidateShape(int candidatePosition){
		return ((LabelDef)this.get(candidatePosition)).getBounds();
	}
	public Object getField(Object labelDef, int fieldID) throws Exception {
		Object returnObj = null;
		if (labelDef instanceof LabelDef){
			if (fieldID == CATEGORY_TICK) {
				returnObj = ((LabelDef)labelDef).getTick();
			} else if (fieldID == BOUNDS) {
				returnObj = ((LabelDef)labelDef).getBounds();
			} else if (fieldID == ANCHOR_POINT) {
				returnObj = ((LabelDef)labelDef).getAnchorPoint();
			} else if (fieldID == ANCHOR_POINT) {
				returnObj = ((LabelDef)labelDef).drawn;
			} else if (fieldID == TICK_MARK_LINE) {
				returnObj = ((LabelDef)labelDef).mark;
			}
			else {
				notifyInvalidFieldIDReuquested("[LabelDefs::getField]", labelDef, fieldID);
			}
		}
		else {
			notifyInternalCastError("[LabelDefs::getField]", labelDef, LabelDef.class);
		}
		return returnObj;
	}
	public boolean drawThisLabel(Object labelDef) throws Exception {
		boolean shouldIDrawThisLabel = false;
		if (labelDef instanceof LabelDef) {
			shouldIDrawThisLabel = ((LabelDef)labelDef).isDrawn();
		} else {
			notifyInternalCastError("[LabelDefs::drawThisLabel]", labelDef, LabelDef.class);
		}
		return shouldIDrawThisLabel;
	}
	

	// look through all drawn lables
	public boolean intersectsAny(final Shape candidateShape){
		boolean intersects = false;
		LabelDef labelDef = null;
		Rectangle2D currentBounds = gappedRectange(candidateShape.getBounds2D());
	
		
		
		Iterator LabelDefIter = this.iterator();
		while ((LabelDefIter.hasNext()) && (!intersects) ){
			labelDef = (LabelDef)LabelDefIter.next();
			if (labelDef.isDrawn()) {
				
				intersects = gappedRectange(labelDef.getBounds().getBounds2D()).intersects(currentBounds);
				
				//intersects = labelDef.getBounds().intersects(currentBounds);
			}
		}
		return intersects;
	}
	
	
	
	  
	private Rectangle2D gappedRectange(Rectangle2D rectToGap){
		double newMaxX = rectToGap.getBounds2D().getX() + CATEGORY_GAP_SIZE;
		double newMaxY = rectToGap.getBounds2D().getY();
		Rectangle2D currentBoundsWithGap = new Rectangle2D.Double(newMaxX, newMaxY, 
				rectToGap.getBounds2D().getWidth() + CATEGORY_GAP_SIZE, 
				rectToGap.getBounds2D().getHeight());
		return currentBoundsWithGap;
	}
	public void markForDraw(int candidatePosition){
		((LabelDef)this.get(candidatePosition)).markAsDrawn();
	}
	private void notifyInternalCastError(String caller, Object unknown, Class expectedClass) throws Exception {
		String errorMessage = caller + "InternalCastError" +
				"\n\tThe system tried to invoke this method with a " + unknown.getClass().getName()+ 
				"\n\ttype object when a " + expectedClass.getName() + " type object was expected. This " +
				"\n\tis an internal error and should be reported to the development team. In addition " +
				"\n\tyou could also report this error to the author of this code at ray_lukas@comcast.net.";
		throw new Exception(errorMessage);
	}
	private void notifyInvalidFieldIDReuquested(String caller, Object unknown, int fieldID) throws Exception {
		String errorMessage = caller + "InvalidFieldIDReuquested" +
		"\n\tThe system tried to request a filed from a LabelDef object, which is not supported. " +
		"\n\tThis is an internal error and should be reported to the development team. In addition " +
		"\n\tyou could also report this error to the author of this code at ray_lukas@comcast.net. " +
		"\n\tIn general you should only invoke this method using one of the shared public constants " +
		"\n\texposed by this class.\n\t\tOffending Class=>" + unknown.getClass().getName() +
		"\n\t\tOffending Field ID=>" + fieldID;
		throw new Exception(errorMessage);
	}
	
	private class LabelDef {
		private String name = null;
		private Boolean drawn = new Boolean(false);
		private CategoryTick tick = null;
		private Line2D mark = null;
		private Shape bounds = null;  
		private Point2D anchorPoint =  null;
		public LabelDef(String name, CategoryTick tick, Line2D mark, Shape bounds, Point2D anchorPoint){
			this.name = name;
			this.tick = tick;
			this.mark = mark;
			this.anchorPoint = anchorPoint;
			this.bounds = bounds;
		}
		public boolean isDrawn() {
			return drawn.booleanValue();
		}
		public void markAsDrawn() {
			this.drawn = new Boolean(true);
		}	
		public void setDrawn(boolean markAsDrawnFlag) {
			this.drawn = new Boolean(markAsDrawnFlag);
		}
		public CategoryTick getTick() {
			return tick;
		}
		public Line2D getMark() {
			return mark;
		}
		public Point2D getAnchorPoint() {
			return anchorPoint;
		}
		public Shape getBounds() {
			return bounds;
		}
		public String toString(){
			  return "LabelPoint" +  name +
				  "\n\tanchorPoint=>(" + anchorPoint.getX() + ", " + anchorPoint.getY() + ")" + 
				  "\n\tgetMinX()=>" + (bounds.getBounds2D()).getMinX() + " getMaxX()=>" + (bounds.getBounds2D()).getMaxX();
		  }
	  }	  
}
Note the basic change appears in intersectsAny() method.. Hope this helps.. I did some testing and it seems to work really well.. So far anyhow.. :) So far JFreeChart looks like a pretty decent piece of software. I am pretty happy with it..

ray lukas
of all the things I lost, I miss my mind the most

Sidicas
Posts: 1
Joined: Wed Aug 09, 2006 2:56 am

Post by Sidicas » Wed Aug 09, 2006 3:06 am

I'm new here, I just started using JFreeChart a few days ago.


Good job, I'm glad this patch was made..

I had a few things that I wasn't so sure I was doing right..

1) The labels are too far apart when using label rotations... Is there a way to use label rotations and get the label skipping to work properly? When I use a rotation like this (this line is actually from another example source).. The labels are so far apart that it barely fits 5 or 6 labels on a 3000 pixel wide graph. My labels are long (about 20+ chars). Probably that is part of the problem. But clearly it could fit 30 or 40 more labels in all that empty space!

Code: Select all

            domainAxis.setCategoryLabelPositions(CategoryLabelPositions.createUpRotationLabelPositions(Math.PI / 6.0));
2) In my original code, I was setting the axis from the plot.. But now I get an exception when I try to do so...

Code: Select all

CategoryAxis domainAxis = (CategoryAxisSkipLabels)plot.getDomainAxis();  // new CategoryAxis("Category");
So I had to create a new domain axis as shown in the demo for the label skipping and then add the axis to the plot...

Code: Select all

CategoryAxis domainAxis = new CategoryAxisSkipLabels();  // new CategoryAxis("Category");
...
...
..
.....
...
plot.setDomainAxis(domainAxis);
Is this the proper way to do it? Or am I missing something?

Note: I took the .java files from the patch and added them to my project without actually changing or patching any of the JFreeChart libararies. Probably not the right thing to do?

Thanks for the help.

Locked