每个类别在条形图中的标签能否自定义?

3
最近我收到了一个要求,需要创建一个柱状图来展示每个项目的数据。以下是一个例子:
如您所见,"Category"是项目名称,"Series"是该项目中的不同类型的数据。
然而,由于系统不能保证项目名称的唯一性,将其用作类别可能会导致问题,我将无法使用项目名称为不同的项目生成URL。另一方面,如果我使用唯一ID作为类别,我将无法显示项目名称。这使我陷入了困境。
所以我的问题是:
在JFreeChart中是否有一种方法可以动态生成自定义类别标签?类似于"CategoryItemLabelGenerator"但是应用于类别本身。这样我就可以使用唯一ID作为类别,但在图表中显示项目名称。
2个回答

4
答案取决于您选择的CategoryDataset如何实现KeyedValues2D接口。该接口要求键是唯一的,默认实现DefaultKeyedValues2D要求键是可比较和不可变的。
独特的String实例是典型的具体参数类型,但是JFreeChart中没有强制执行唯一约束。一种方法是将您的String包装在一个实现Comparable并强制实施唯一性的类中。 class Valueexample,它利用底层Double实现。您的实现将需要一个额外的属性来区分一个project与另一个project,可能使用源关系的主键。您可以重写toString()以获得名称的格式化表示形式。

1
谢谢,我已将“UniqueValue”实现为类别,它确实解决了我的问题 :) - Rangi Lin
这是我如何实现UniqueValue类的方式请参见我的答案 - Rangi Lin

2
这是我实现“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;
        }
    }

您可以使用这个类来处理我在问题中提到的唯一性问题。

更新

然而,由于JFreeChart使用toString()方法创建类别标签,因此UniqueValue中的toString()实现可能非常奇怪。因此,这里有另一个尝试。

首先是一个生成器接口。

public interface CategoryLabelGenerator {
    public String generate(Comparable<?> category);
}

接下来,我为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));
    }
}

例子:

JFreeChart chart = makeChart();
CategoryPlot plot = chart.getCategoryPlot();

CategoryAxis axis = new CategoryLabelCustomizableCategoryAxis();
axis.setCategoryLabelGenerator(new MyCategoryLabelGenerator());
plot.setDomainAxis(axis);

这是我如何自定义类别标签的方法。(至少对于使用CategoryAxis作为域轴的图表来说是这样的。)

看起来不错。有没有什么(有用的)方法来消除 toString() 的结果歧义? - trashgod
除非JFreeChart更改从toString()创建类别标签的实现方式,否则我无法想出更好的方法。我也不喜欢现在的toString()的样子 :( - Rangi Lin
也许我可以重写 CategoryAxis 类中的 createLabel 方法,这样它就不会总是使用 toString() 来获取类别的文本了。 - Rangi Lin
也许需要一个更具描述性名称的工具提示生成器 - trashgod
我再试一次,这应该是更好的方法。请查看我的更新答案。 - Rangi Lin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接