1

I have a box chart with multiple boxes in rows and columns. The ordering of the boxes is wrong. Each row (color) is labeled by an enum constant of type Multiple, and each column (group) is labeled by an enum constant of type Type. (The real names of the types are different; This is simplified.)

The code to generate the chart is like this, but this has many things omitted because I think that they are not important:

var results; // results are predefined
var dataset = new DefaultBoxAndWhiskerCategoryDataset();

for (Type type : results.keySet()) { // type is an enum constant
    var innerResults = results.get(type);
    for (Multiple multiple : innerResults.keySet()) { // multiple is an enum constant
        List<Double> values; // calculate values here
        dataset.add(values, multiple, type);
} }

var chart = ChartFactory.createBoxAndWhiskerChart(
    "",
    "type",
    "",
    dataset,
    true
);

This is the resulting chart:

box chart with wrongly ordered columns

The order of the multiples is supposed to be ascending (“0.25”, “0.5”, …). The order of the types is supposed to be “hard MW”, “soft MW”, “multiple-overlay MW”. That is how they are declared in the source code, so that is how they are ordered according to compareTo. I didn't find that JFreeChart would have a documented ordering for rows and columns, but that is how I expect it.

Why are the boxes in this order and not the expected one? How can I force JFreeChart to sort the rows and columns how I expect it? I have no idea what causes this; I have a very similar chart, but the order there is correct.

matj1
  • 158
  • 1
  • 11
  • Do your row and column keys implement `Comparable` as intended? – trashgod Apr 29 '22 at 17:09
  • Related examples are seen [here](https://stackoverflow.com/search?tab=votes&q=user%3a230513%20DefaultBoxAndWhiskerCategoryDataset). – trashgod Apr 30 '22 at 12:17
  • @trashgod Yes, enums automatically implement `Comparable`, and their order is how they are declared in the source code. That's why I mentioned it in the question. I didn't override the comparing. – matj1 May 01 '22 at 05:20
  • I [see](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Enum.html#compareTo(E)): "The natural order implemented by this method is the order in which the constants are declared." This [example](https://stackoverflow.com/a/6849654/230513) appears to be ordered as expected according to `String name`. – trashgod May 01 '22 at 12:18
  • As the `keySet()` of a `Map` is generally unordered, you may need to use a `SortedSet` to get the desired behavior. – trashgod May 04 '22 at 22:50
  • @trashgod That is a good point. I expected that the order of insertion of the data would not matter, but it matters. I didn't use a SortedSet; I sorted the values in a stream, like `…keySet().stream().sorted().toList()`. I prefer that because the method calls go just to the right. – matj1 May 12 '22 at 16:18
  • Glad you got it sorted! I've summarized the comments below. Please don't hesitate to correct any errors. – trashgod May 12 '22 at 21:52

1 Answers1

1

Summarizing our colloquy, your dataset row and column keys are held by an Enum, which implements Comparable. In particular, "The natural order implemented by this method is the order in which the constants are declared." However, because the values come from a keySet() held by the enum, they are generally unordered. While it may be possible to substitute a SortedSet, you have chosen to sort each set explicitly:

keySet().stream().sorted().toList()
trashgod
  • 203,806
  • 29
  • 246
  • 1,045