Skip category labels

A discussion forum for JFreeChart (a 2D chart library for the Java platform).
guyknight
Posts: 10
Joined: Fri Dec 02, 2005 4:16 pm

Better patch for Category Skip Labels

Post by guyknight » Thu Oct 26, 2006 2:43 pm

Ray and I have a better patch that we will upload today. This patch automatically produces a skip label in a step wise fashion [credit for coding and extending CategoryAxis goes to Ray]. The current patch online from Ray produces a skip label using a best fit algorithm.
--
Also we added the ability to put stagger labels.

Image

Image

rita_dewan
Posts: 10
Joined: Tue Oct 31, 2006 9:26 am
Location: India

Post by rita_dewan » Fri Dec 08, 2006 1:55 pm

Hi can you send me your code of skipping the labels on x axis.

As I am also facing same problem, I need such kinda solution.

I appreciate your efforts and will be very much thankful for the same.

agent613
Posts: 2
Joined: Fri Dec 22, 2006 12:37 am

need staggering logic

Post by agent613 » Fri Dec 22, 2006 12:39 am

For my charts, I am using a PeriodAxis. This axis will automatically skip date labels that don't fit. Instead of this, I need the ability to stagger the dates like shown in your screen shot.

Can you post the code you used to do this?

Thanks!

guyknight
Posts: 10
Joined: Fri Dec 02, 2005 4:16 pm

Post by guyknight » Fri Dec 22, 2006 9:29 pm

The code is posted on the patch site.

http://sourceforge.net/tracker/?group_i ... tid=315494

patch #: 1585099

agent613
Posts: 2
Joined: Fri Dec 22, 2006 12:37 am

Thanks

Post by agent613 » Wed Dec 27, 2006 10:37 pm

:)

ravish
Posts: 9
Joined: Thu Feb 15, 2007 11:52 am

Using the interveaved method above for 3D bar chart

Post by ravish » Thu Feb 15, 2007 11:55 am

I'm using ChartFactory to create 3D effect on bar chart. How do I use the above patch on such jFreeChart object? Since, the factory dosen't allow any way of passing the customised category axis how do I set CategoryAxisSkipLabels.N_STEP_ALGO?

Is it possible in this version? Or do I have to switch back to 2D?

ravish
Posts: 9
Joined: Thu Feb 15, 2007 11:52 am

I think i found the way...but

Post by ravish » Thu Feb 15, 2007 1:48 pm

I did this:

chart = ChartFactory.createBarChart3D(title, "", "Frequency", dataset, PlotOrientation.VERTICAL, true, true, false);

CategoryPlot plot = chart.getCategoryPlot();

plot = categoryPlot;

So replaced the instance I got from chart object created by the factory with the customized category plot instance initialized with your custom axis. But i think ChartFactory method either needs to allow setting this in constructor or there should be a setCategoryPlot method may be. It seems the code organisation needs a second look maybe?

Any comments?

ravish
Posts: 9
Joined: Thu Feb 15, 2007 11:52 am

Nope, still dosen't work.

Post by ravish » Thu Feb 15, 2007 2:20 pm

Sorry, I thought it works cause I saw the labels being truncated to dots, but its not updating the instance within the already created JFreeChart object created using the ChartFactory (obviously :oops:) . How do I get around this? Any help will be much appreciated.

ravish wrote:I did this:

chart = ChartFactory.createBarChart3D(title, "", "Frequency", dataset, PlotOrientation.VERTICAL, true, true, false);

CategoryPlot plot = chart.getCategoryPlot();

plot = categoryPlot;

So replaced the instance I got from chart object created by the factory with the customized category plot instance initialized with your custom axis. But i think ChartFactory method either needs to allow setting this in constructor or there should be a setCategoryPlot method may be. It seems the code organisation needs a second look maybe?

Any comments?
:oops: :oops: :oops: :oops: :oops: :oops: :oops: :oops: :oops: :oops: :oops: :oops:

guyknight
Posts: 10
Joined: Fri Dec 02, 2005 4:16 pm

3d chart

Post by guyknight » Fri Feb 16, 2007 3:41 pm

Do you mean a 3d chart like this


Image

ravish
Posts: 9
Joined: Thu Feb 15, 2007 11:52 am

Yes, 3D Chart like that but with staggered labels...

Post by ravish » Sat Feb 17, 2007 12:27 am

Yes thats the kind of chart, but with lables staggered using your extremely handy patch...thanks! Did you create this one with the ChartFactory? Is there a way of creating the 3D chart without using the factory in current version?

inder14
Posts: 11
Joined: Fri Jul 10, 2009 7:09 pm

Re: help in using below code

Post by inder14 » Sun Jul 12, 2009 1:20 pm

jsaiz wrote:Below is the class that derives from CategoryAxis.

NOTE: This class has a drawback, in that it does not display tooltips on the tick labels. This is because drawCategoryLabels method prepares tooltips, but it has not access to CategoryAxis' private member categoryLabelToolTips, and there is no public nor protected getCategoryLabelToolTips() in CategoryAxis.

Code: Select all

/**
 * This class enhances <code>CategoryAxis</code> in that it allows
 * to skip some labels to be printed in the category axis.
 * However, it does not display tooltips on the labels.
 */
public class CategoryAxisSkipLabels extends CategoryAxis
{
  private static final int DEFAULT_INTERVAL = 1;
  private int m_interval;

  /** Default constructor. */
  public CategoryAxisSkipLabels()
  {
    this(null, DEFAULT_INTERVAL);
  }

  /**
   * Constructs an axis with a label.
   * @param label Axis label (may be null).
   */
  public CategoryAxisSkipLabels(String label)
  {
    this(label, DEFAULT_INTERVAL);
  }

  /**
   * Constructs a category axis with a label and an interval.
   * @param label Axis label (may be null).
   * @param interval This number controls the labels to be printed.
   * For instance, if <code>interval = 1</code>, all labels are printed; if
   * <code>interval = 10</code>, only one of every 10 labels are printed (first label
   * is always printed).
   */
  public CategoryAxisSkipLabels(String label, int interval)
  {
    super(label);
    m_interval = interval;
  }

  /**
   * Draws the category labels and returns the updated axis state.
   * NOTE: This method redefines the corresponding one in <code>CategoryAxis</code>,
   * and is a copy of that, with added control to skip some labels to be printed.
   * 
   * @param g2 the graphics device (<code>null</code> not permitted).
   * @param dataArea the area inside the axes (<code>null</code> not
   *          permitted).
   * @param edge the axis location (<code>null</code> not permitted).
   * @param state the axis state (<code>null</code> not permitted).
   * @param plotState collects information about the plot (<code>null</code>
   *          permitted).
   * 
   * @return The updated axis state (never <code>null</code>).
   */
  protected AxisState drawCategoryLabels(Graphics2D g2, Rectangle2D dataArea,
                                         RectangleEdge edge, AxisState state,
                                         PlotRenderingInfo plotState)
  {
    if (state == null)
    {
      throw new IllegalArgumentException("Null 'state' argument.");
    }

    if (isTickLabelsVisible())
    {
      g2.setFont(getTickLabelFont());
      g2.setPaint(getTickLabelPaint());
      List ticks = refreshTicks(g2, state, dataArea, edge);
      state.setTicks(ticks);

      int categoryIndex = 0;
      Iterator iterator = ticks.iterator();
      while (iterator.hasNext())
      {
        CategoryTick tick = (CategoryTick) iterator.next();
        g2.setPaint(getTickLabelPaint());

        CategoryLabelPosition position = getCategoryLabelPositions()
            .getLabelPosition(edge);
        double x0 = 0.0;
        double x1 = 0.0;
        double y0 = 0.0;
        double y1 = 0.0;
        if (edge == RectangleEdge.TOP)
        {
          x0 = getCategoryStart(categoryIndex, ticks.size(), dataArea, edge);
          x1 = getCategoryEnd(categoryIndex, ticks.size(), dataArea, edge);
          y1 = state.getCursor() - getCategoryLabelPositionOffset();
          y0 = y1 - state.getMax();
        }
        else if (edge == RectangleEdge.BOTTOM)
        {
          x0 = getCategoryStart(categoryIndex, ticks.size(), dataArea, edge);
          x1 = getCategoryEnd(categoryIndex, ticks.size(), dataArea, edge);
          y0 = state.getCursor() + getCategoryLabelPositionOffset();
          y1 = y0 + state.getMax();
        }
        else if (edge == RectangleEdge.LEFT)
        {
          y0 = getCategoryStart(categoryIndex, ticks.size(), dataArea, edge);
          y1 = getCategoryEnd(categoryIndex, ticks.size(), dataArea, edge);
          x1 = state.getCursor() - getCategoryLabelPositionOffset();
          x0 = x1 - state.getMax();
        }
        else if (edge == RectangleEdge.RIGHT)
        {
          y0 = getCategoryStart(categoryIndex, ticks.size(), dataArea, edge);
          y1 = getCategoryEnd(categoryIndex, ticks.size(), dataArea, edge);
          x0 = state.getCursor() + getCategoryLabelPositionOffset();
          x1 = x0 - state.getMax();
        }
        Rectangle2D area = new Rectangle2D.Double(x0, y0, (x1 - x0), (y1 - y0));
        Point2D anchorPoint =
          RectangleAnchor.coordinates(area, position.getCategoryAnchor());

        // THIS CODE IS NOW CONTROLLED BY THE "IF" =============
        if (categoryIndex % m_interval == 0)
        {
          TextBlock block = tick.getLabel();
          block.draw(g2, (float) anchorPoint.getX(), (float) anchorPoint.getY(),
                     position.getLabelAnchor(), (float) anchorPoint.getX(),
                     (float) anchorPoint.getY(), position.getAngle());
          Shape bounds = block.calculateBounds(g2, (float) anchorPoint.getX(),
                                               (float) anchorPoint.getY(),
                                               position.getLabelAnchor(),
                                               (float) anchorPoint.getX(),
                                               (float) anchorPoint.getY(),
                                               position.getAngle());
          if (plotState != null)
          {
            EntityCollection entities = plotState.getOwner().getEntityCollection();
            if (entities != null)
            {
              //String tooltip = (String) categoryLabelToolTips.get(tick.getCategory());
              String tooltip = null;
              entities.add(new TickLabelEntity(bounds, tooltip, null));
            }
          }
        }
        // END IF ========================================

        categoryIndex++;
      }

      if (edge.equals(RectangleEdge.TOP))
      {
        double h = state.getMax();
        state.cursorUp(h);
      }
      else if (edge.equals(RectangleEdge.BOTTOM))
      {
        double h = state.getMax();
        state.cursorDown(h);
      }
      else if (edge == RectangleEdge.LEFT)
      {
        double w = state.getMax();
        state.cursorLeft(w);
      }
      else if (edge == RectangleEdge.RIGHT)
      {
        double w = state.getMax();
        state.cursorRight(w);
      }
    }
    return state;
  }
}
What I propose is to add a constructor to CategoryAxis that receives the interval parameter, and redefine drawCategoryLabels to add the remarked "if". It would not break existing code (this would be only a new constructor) and the tooltips drawback would dissapear.

Regards,
Jaime
hello,
i code this code to skip the labels(code above given by Jaime) in categoryaxis but i am not sure how to use it..............
my code is here

//starts
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Stroke;

import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.CategoryAxis;
import org.jfree.chart.axis.CategoryLabelPositions;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.CombinedDomainCategoryPlot;
import org.jfree.chart.renderer.category.CategoryItemRenderer;
import org.jfree.chart.renderer.category.LayeredBarRenderer;
import org.jfree.chart.renderer.category.LineAndShapeRenderer;
import org.jfree.data.category.CategoryDataset;
import org.jfree.data.category.DefaultCategoryDataset;
import org.jfree.text.TextUtilities;
import org.jfree.ui.ApplicationFrame;
import org.jfree.ui.RefineryUtilities;


public class SingleGraph extends ApplicationFrame {
public double maxvalue =0.0;

public SingleGraph(String titel) {
super(titel);

final JFreeChart chart = createChartBar();
final ChartPanel chartPanel = new ChartPanel(chart);
chartPanel.setPreferredSize(new java.awt.Dimension(600, 300));
setContentPane(chartPanel);




}
public static void main(final String[] args) {

final String title = "Score";
TextUtilities.setUseFontMetricsGetStringBounds(false);
final SingleGraph chart = new SingleGraph(title);
chart.pack();
RefineryUtilities.centerFrameOnScreen(chart);
chart.setVisible(true);

}

public double[] run1() {
double[] run = new double[]{ 10, 6, 2, 4, 7, 2, 8, 12, 9
};
return run;
}
private CategoryDataset createRunDataset2() {
final DefaultCategoryDataset dataset = new DefaultCategoryDataset();

double[] run = run1();
String xvalues="";

for (int i = 0,k=0; i < run.length; i++) {
if(run>maxvalue){
maxvalue = run;
}

xvalues = "Inder"+i;

dataset.addValue(run, "Ist Team",xvalues);

}
return dataset;
}



private JFreeChart createChartBar() {
final CategoryDataset dataset1 = createRunDataset2();

final NumberAxis rangeAxis1 = new NumberAxis("Balls");
rangeAxis1.setLabelFont(new Font("Dialog", Font.BOLD, 11));
rangeAxis1.setUpperMargin(0.0);
rangeAxis1.setLowerBound(0);
rangeAxis1.setUpperBound(maxvalue);
rangeAxis1.setAxisLinePaint(Color.black);
rangeAxis1.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
rangeAxis1.setAutoTickUnitSelection(true);
rangeAxis1.setAutoTickUnitSelection(true);

final CategoryAxis domainAxis = new CategoryAxis("Score by");
domainAxis.setTickMarksVisible(true);
// renderer1.setPositiveItemLabelPositionFallback(p2);
domainAxis.setCategoryLabelPositions(CategoryLabelPositions.UP_90);
domainAxis.setTickLabelFont(new Font("Helvetica", Font.ITALIC, 14));
domainAxis.setLowerMargin(0.0);
domainAxis.setUpperMargin(0.0);
domainAxis.setLabelFont(new Font("Dialog", Font.BOLD, 11));

final LayeredBarRenderer renderer1 = new LayeredBarRenderer();
renderer1.setSeriesPaint(0, Color.red);

final CategoryPlot subplot1 = new CategoryPlot(dataset1, null, rangeAxis1, renderer1);
Stroke stroke = new BasicStroke(1,BasicStroke.CAP_SQUARE,BasicStroke.JOIN_BEVEL);
subplot1.setDomainGridlineStroke(stroke);
subplot1.setRangeGridlineStroke(stroke);

subplot1.setRenderer(1, renderer1);

final CombinedDomainCategoryPlot plot = new CombinedDomainCategoryPlot(domainAxis);
plot.add(subplot1, 1);
plot.setOutlinePaint(Color.RED);
plot.setOutlineVisible(true);

final JFreeChart chart = new JFreeChart(
"", new Font("SansSerif",Font.BOLD, 12),
plot, true);
chart.setBorderPaint(Color.BLACK);
chart.setBorderVisible(true);


return chart;
}
}

//end

Thanks in advance
Inder

inder14
Posts: 11
Joined: Fri Jul 10, 2009 7:09 pm

Re: Skip category labels

Post by inder14 » Mon Jul 13, 2009 6:10 am

Hi All,
i got it , thanks a lot for all your help.

regards,
Inder

yumex85
Posts: 4
Joined: Tue Aug 25, 2009 5:12 pm
antibot: No, of course not.

Re: Skip category labels

Post by yumex85 » Tue Aug 25, 2009 10:09 pm

Guys, maybe one thing might help you in case this patch doesnt work. At least that was happening to me, and that was because I was using a newer version of JFreeChart that does not have drawCategoryLabels method anymore. In other words, that method was not an override one anymore. I thought maybe this info would save someones time, so for those who got newer Jfreechart api version, just add the method below to the patch class. I know there r better ways to do it, this is just the "least-effot-way":

public AxisState draw(final Graphics2D g2, final double cursor, final Rectangle2D plotArea, final Rectangle2D dataArea, final RectangleEdge edge, final PlotRenderingInfo plotState) {

final AxisState axisState = new AxisState();

axisState.setCursor(cursor);

return drawCategoryLabels(g2, dataArea, edge, axisState, plotState); }

jla
Posts: 1
Joined: Wed Apr 06, 2011 8:54 pm
antibot: No, of course not.

Re: Skip category labels

Post by jla » Wed Apr 06, 2011 9:07 pm

My copy of JFreeChart has two drawCategoryLabels, it's just that the one with a single Rectangle2D is deprecated and seemingly no longer called.

Instead of overriding CategoryAxis.draw, I modified the CategoryAxisSkipLabels.drawCategoryLabels to take two Rectangle2D's. I tried to follow CategoryAxis' example and passed the dataArea to drawTheChart and plotArea to refreshTicks. Seems to work.

chuck.edw
Posts: 1
Joined: Tue Oct 25, 2011 2:24 pm
antibot: No, of course not.

Re: Skip category labels

Post by chuck.edw » Tue Oct 25, 2011 2:26 pm

Hey guys... to solve the problem with the deprecated method, just add the new one, like this:

Code: Select all

        @Override
	protected AxisState drawCategoryLabels(Graphics2D g2, Rectangle2D plotArea,
			Rectangle2D dataArea, RectangleEdge edge, AxisState state,
			PlotRenderingInfo plotState) {
		return drawCategoryLabels(g2, dataArea, edge, state, plotState);
	}

Locked