As mentioned in my last post, I’ve been developing a new plugin for Protégé and I’ve been using the JFreeChart library for some of the visual components. Last time I discussed some issues with JFreeChart enforcing it’s column and row keys to be Comparable, but then not actually using the compareTo method. I think I have figured out what the intention was behind this design.
In some types of charts, the library will allow you to sort the domain axis, so I’m guessing it uses the Comparable for this functionality. Unfortunately, the DefaultCategoryDataset class that I am using to create my area charts does not support this, but I want my domain axis to be sorted by ascending date.
I spent some time looking at the internal code of the library to try to figure out if there’s a way I could do this. It turns out that the DefaultCategoryDataset uses a DefaultKeyedValues2D class to store it’s actual data and this class supports a sort row keys option. However the DefaultCategoryDataset initiates the internal object with this always set to false. There’s no public methods to access to the internal data object, so I can’t modify it at runtime.
Also, it doesn’t appear that the code for sorting the key values really works as I would assume it should. Here’s the internal code from the DefaultKeyedValues2D class:
row = new DefaultKeyedValues();
if (this.sortRowKeys) {
rowIndex = -rowIndex - 1;
this.rowKeys.add(rowIndex, rowKey);
this.rows.add(rowIndex, row);
}
I would think that this sortRowKeys option should rely on the fact that the rowKey is Comparable, and should insert the new rowKey into the rowKeys list based on a comparison to the already existing keys. Instead all it does is insert the new rowKey at the beginning of the rowKeys list. This happens because of the line rowIndex = -rowIndex – 1. In this case, rowIndex will initially be equal to -1, the equation is -(-1) – 1, which is 1-1=0.
So, even if I copied the internal code for DefaultCategoryDataset into my own class, and modified it’s initiation of DefaultKeyedValues2D to set the sort key option to true, it still wouldn’t actually sort the keys properly!
In the end, I went with a somewhat hacky solution that I knew would work. While I process my data to display in the chart, I store all the unique dates that I encounter in a sorted set. Then, before I add all my values to the dataset, I make sure the first entry contains all the unique dates in the proper order. This forces JFreeChart’s DefaultKeyedValues2D class to actually insert the row keys into its internal list in the proper order.
Here’s the hack:
// get the first entry in the list
Entry<String, Map<Date, Integer>> firstEntry =
authorToChangesByMonthMap.entrySet().iterator().next();
// total hack to get the row keys to show up in sorted order
for(Date date : allDates) {
// check to see if the key exists, if not, create it
if(firstEntry.getValue().get(date) == null) {
// dummy entry
firstEntry.getValue().put(date, 0);
}
}
As for the plugin, I am planning to include it in the Protégé release that is scheduled for this week.