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
Custom CategoryAxis Labels
Re: Custom CategoryAxis Labels
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
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:
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;
}
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;
}
}
Re: Custom CategoryAxis Labels
Thanks! I was having the exact same issue. I used your extended SymbolAxis class and everything works fine
-
- Posts: 7
- Joined: Tue Mar 10, 2009 8:50 pm
Tick labels as HyperLinks on Symbol Axis
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
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