Custom CategoryAxis Labels

A discussion forum for JFreeChart (a 2D chart library for the Java platform).
Locked
mistercam
Posts: 2
Joined: Thu Apr 08, 2010 4:53 pm
antibot: No, of course not.

Custom CategoryAxis Labels

Post by mistercam » Thu Apr 08, 2010 5:11 pm

Hello,

I'm looking for a way to provide custom labels for a CategoryAxis object. The chart I have contains a bunch of columns. I outline a dumbed-down example of what I want to do. My situation is more complex in terms of the labels I want to show, but the following example explains what I'm looking to do. For the sake of this example, let's say I have columns 1, 2, ... , 100 in a chart's dataset. Typically the chart would render and display each of these labels individually. Instead of having each of these columns to appear under the domain axis, I would instead like only a subset of these columns appear at the appropriate position on the domain axis.

Here's some pseudo code:

Map<Comparable, String> columnsToDisplayNames = new HashMap<Comparable, String>();
columnsToDisplayNames.put(1, "ONE");
columnsToDisplayNames.put(2, "TWO");
columnsToDisplayNames.put(4, "FOUR");
columnsToDisplayNames.put(8, "EIGHT");
columnsToDisplayNames.put(16, "SIXTEEN");
...

// When drawing the labels for the CategoryAxis
for each column C in my chart's dataset
if columnsToDisplayNames.keys().contains(C) then display columnsToDisplayNames.get(C), otherwise display nothing


This code would ideally display labels "ONE", "TWO", "FOUR", "EIGHT", and "SIXTEEN", with the distance between each subsequent pair doubling in size on the rendered chart.

Is there any way to implement this? I've looked through the API and searched through various JFreeChart sites and articles, with no luck.

If you have any ideas, I'd love to hear them.

Thanks,
-- Cam

mistercam
Posts: 2
Joined: Thu Apr 08, 2010 4:53 pm
antibot: No, of course not.

Re: Custom CategoryAxis Labels

Post by mistercam » Mon Apr 12, 2010 2:55 pm

Hello,

I resolved this issue.

First I had to switch to an XYPlot because I had to be able to connect two non-consecutive points with a line. A LineAndShapeRenderer did not allow me to do this.

Second, I extended SymbolAxis to create a new version. Inside this class, I overrode two methods: valueToString and refreshTicksHorizontal. For both methods, I copied and modified the contents found in SymbolAxis.java

In the valueToString method, I returned null in the case of an exception. Also when I create my MySymbolAxis object, the String[] I pass into it can contain null values.

In the refreshTicksHorizontal method, I remove the surrounding if-statement that checks to see if count is less than ValueAxis.MAXIMUM_TICK_COUNT, as my chart can potentially contain thousands of values. After the line tickLabel = valueToString(currentTickValue);, I inserted

Code: Select all

if (tickLabel == null) { 
  continue; 
}
So using the example in my initial post, I could do something like:

String[] labels = new String[n];
labels[0] = null;
labels[1] = "ONE";
labels[2] = "TWO";
labels[3] = null;
labels[4] = "FOUR";
labels[5] = null;
labels[6] = null;
labels[7] = null;
labels[8] = "EIGHT";
...
labels[n-1] = ?

The full file can be found below:

Code: Select all

  private class MySymbolAxis extends SymbolAxis {

    private MySymbolAxis(String label, String[] sv) {
      super(label, sv);
    }

    @Override
    protected List refreshTicksHorizontal(Graphics2D g2, Rectangle2D dataArea, RectangleEdge edge) {

      List ticks = new java.util.ArrayList();

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

      double size = getTickUnit().getSize();
      int count = calculateVisibleTickCount();

      double lowestTickValue = calculateLowestVisibleTickValue();

      double previousDrawnTickLabelPos = 0.0;
      double previousDrawnTickLabelLength = 0.0;

      for (int i = 0; i < count; i++) {
        double currentTickValue = lowestTickValue + (i * size);
        double xx = valueToJava2D(currentTickValue, dataArea, edge);
        String tickLabel;
        NumberFormat formatter = getNumberFormatOverride();
        if (formatter != null) {
          tickLabel = formatter.format(currentTickValue);
        }
        else {
          tickLabel = valueToString(currentTickValue);

          if (tickLabel == null) {
            continue;
          }
        }

        // avoid to draw overlapping tick labels
        Rectangle2D bounds = TextUtilities.getTextBounds(tickLabel, g2, g2.getFontMetrics());
        double tickLabelLength = isVerticalTickLabels()
            ? bounds.getHeight() : bounds.getWidth();
        boolean tickLabelsOverlapping = false;
        if (i > 0) {
          double avgTickLabelLength = (previousDrawnTickLabelLength + tickLabelLength) / 2.0;
          if (Math.abs(xx - previousDrawnTickLabelPos) < avgTickLabelLength) {
            tickLabelsOverlapping = true;
          }
        }
        if (tickLabelsOverlapping) {
          tickLabel = ""; // don't draw this tick label
        }
        else {
          // remember these values for next comparison
          previousDrawnTickLabelPos = xx;
          previousDrawnTickLabelLength = tickLabelLength;
        }

        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 NumberTick(new Double(currentTickValue),
                                   tickLabel, anchor, rotationAnchor, angle);
        ticks.add(tick);
      }
      return ticks;
    }

    @Override
    public String valueToString(double value) {
      String strToReturn;
      try {
        strToReturn = this.getSymbols()[(int) value];
      }
      catch (IndexOutOfBoundsException ex) {
        strToReturn = null;
      }
      return strToReturn;
    }
  }

desaila
Posts: 3
Joined: Mon Jun 14, 2010 4:25 pm
antibot: No, of course not.

Re: Custom CategoryAxis Labels

Post by desaila » Wed Jun 16, 2010 7:37 pm

Thanks! I was having the exact same issue. I used your extended SymbolAxis class and everything works fine

kasineedis
Posts: 7
Joined: Tue Mar 10, 2009 8:50 pm

Tick labels as HyperLinks on Symbol Axis

Post by kasineedis » Wed Aug 25, 2010 3:38 pm

All,

My requirment is to create HyperLink on Symbol Axis Tick lables on Y-aix(Ex p1,p2,p3 ...etc).When you click on that hyper link I have to show another window in which I have to show some data by connecting to database.Could you pleaseGuide me or any body in forum.
1)How to make Symbol axis Tick labels as Hyper links.
2)How to create Pop-up window when you click on it.

I always appreciate your help.

Thanks
kasi

Locked