问题
Recently I get a requirement to create a bar chart that show data for each project. Here's an example :

As you can see, the Category
is the name of the project, and Series
are different types of data in that project.
However, since system dose not guarantee the uniqueness of project name, using it as categories can cause problem, and I will not able to use project name to generate URL for different projects. On the other hand, If I use unique id as category, I won't able to display the project name. This put me into a difficult situation.
So my problem is :
Is there a way to generate customize category label on the fly in JFreeChart ?
Something similar to CategoryItemLabelGenerator
but for category itself. So I can use unique Id as category, but display project name in chart.
回答1:
The answer depends on how your chosen CategoryDataset
implements the KeyedValues2D
interface. The interface expects the keys to be unique, and the default implementation, DefaultKeyedValues2D
, requires that the keys be Comparable
and immutable.
Unique String
instances are the typical concrete parameter type, but nothing in JFreeChart
enforces the unique constraint. One approach wold be to wrap your String
in a class that implements Comparable
and also enforces uniqueness. The class Value
is an example that leverages the underlying Double
implementation. Your implementation would require an additional attribute to distinguish one project
form another, perhaps using the primary key of the source relation. You could override toString()
to get a formatted representation of the name.
回答2:
This is how I implement UniqueValue
public class UniqueValue implements Comparable<UniqueValue> {
private final String uniqueId;
private final String value;
public UniqueValue(String uniqueId, String value) {
this.uniqueId = uniqueId;
this.value = value;
}
@Override
public int compareTo(UniqueValue o) {
return uniqueId.compareTo(o.uniqueId);
}
@Override
public int hashCode() {
return uniqueId.hashCode();
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof UniqueValue) {
return uniqueId.equals(((UniqueValue)obj).uniqueId);
}
return false;
}
@Override
public String toString() {
return value;
}
}
You can use this class to deal with the uniqueness issue I mentioned in questions.
UPDATE
However, since JFreeChart use toString()
method to create the label for categories. So the toString()
implementation in UniqueValue
can be pretty weird. So here is another attempt.
First, a generator interface
public interface CategoryLabelGenerator {
public String generate(Comparable<?> category);
}
then I make a subclass for CategoryAxis
public class CategoryLabelCustomizableCategoryAxis extends CategoryAxis {
private static final long serialVersionUID = 1L;
private CategoryLabelGenerator labelGenerator;
public CategoryLabelCustomizableCategoryAxis(String label) {
super(label);
}
public void setCategoryLabelGenerator(CategoryLabelGenerator generator) {
this.labelGenerator = generator;
}
@Override
protected TextBlock createLabel(Comparable category, float width,
RectangleEdge edge, Graphics2D g2) {
if (generator == null) {
return super.createLabel(category, width, edge, g2);
}
return TextUtilities.createTextBlock(
labelGenerator.generate(category), // generate label for category on the fly
getTickLabelFont(category), getTickLabelPaint(category), width,
getMaximumCategoryLabelLines(), new G2TextMeasurer(g2));
}
}
example :
JFreeChart chart = makeChart();
CategoryPlot plot = chart.getCategoryPlot();
CategoryAxis axis = new CategoryLabelCustomizableCategoryAxis();
axis.setCategoryLabelGenerator(new MyCategoryLabelGenerator());
plot.setDomainAxis(axis);
This is how I customize category label. (At least for chart that use CategoryAxis
as domain axis..)
来源:https://stackoverflow.com/questions/10930550/is-it-possible-to-customize-label-for-each-category-in-bar-chart