Hi,
I managed to produce the following image, which is the expected result of the above code.
It's quite a quick&dirty implementation by subclassing the LineAndShapeRenderer, but maybe the idea is useful, if you consider to fix this bug within the library.
Inherited is the
drawItem() method, the code is copied from the base implementation. Inserted/replaced are the lines:
Code: Select all
determineAllCategories();
double x1 = domainAxis.getCategoryMiddle(allCategories.indexOf(
dataset.getColumnKey(column)), allCategories.size(),
dataArea, plot.getDomainAxisEdge());
double x0 = domainAxis.getCategoryMiddle(
allCategories.indexOf(dataset.getColumnKey(column - 1)),
allCategories.size(), dataArea,
plot.getDomainAxisEdge());
Where
determineAllCategories() is:
Code: Select all
private ArrayList<Comparable> allCategories;
protected void determineAllCategories() {
if (allCategories == null) {
allCategories = new ArrayList<Comparable>();
int datasetCount = getPlot().getDatasetCount();
for (int i = 0; i < datasetCount; i++) {
CategoryDataset dataset = getPlot().getDataset(i);
for (int j = 0; j < dataset.getColumnCount(); j++) {
Comparable col = dataset.getColumnKey(j);
if (!allCategories.contains(col))
allCategories.add(col);
}
}
}
}
The complete code can be found here: (fully runable)
So a (cached) list of all categories is created. This could be provided by the plot later on. The list needs to have the correct order and every name is to be unique. This list is used to paint the items resp. to determine the item's and line's x starting position.
Does this help you at all? Do you think it makes sense?
Chris
Complete code:
Code: Select all
private static class XLineAndShapeRenderer extends LineAndShapeRenderer {
// ----8<---- START Custom changes ----8<---------------------------------------
private ArrayList<Comparable> allCategories;
protected void determineAllCategories() {
if (allCategories == null) {
allCategories = new ArrayList<Comparable>();
int datasetCount = getPlot().getDatasetCount();
for (int i = 0; i < datasetCount; i++) {
CategoryDataset dataset = getPlot().getDataset(i);
for (int j = 0; j < dataset.getColumnCount(); j++) {
Comparable col = dataset.getColumnKey(j);
if (!allCategories.contains(col))
allCategories.add(col);
}
}
}
}
// ----8<---- END Custom changes ----8<-----------------------------------------
@Override
public void drawItem(Graphics2D g2, CategoryItemRendererState state,
Rectangle2D dataArea, CategoryPlot plot, CategoryAxis domainAxis,
ValueAxis rangeAxis, CategoryDataset dataset, int row, int column,
int pass) {
// ----8<---- START Custom changes ----8<---------------------------------------
determineAllCategories();
// ----8<---- END Custom changes ----8<-----------------------------------------
// do nothing if item is not visible
if (!getItemVisible(row, column)) {
return;
}
// do nothing if both the line and shape are not visible
if (!getItemLineVisible(row, column)
&& !getItemShapeVisible(row, column)) {
return;
}
// nothing is drawn for null...
Number v = dataset.getValue(row, column);
if (v == null) {
return;
}
PlotOrientation orientation = plot.getOrientation();
// current data point...
// ----8<---- START Custom changes ----8<---------------------------------------
/*double x1 = domainAxis.getCategoryMiddle(column, getColumnCount(),
dataArea, plot.getDomainAxisEdge());*/
double x1 = domainAxis.getCategoryMiddle(allCategories.indexOf(
dataset.getColumnKey(column)), allCategories.size(),
dataArea, plot.getDomainAxisEdge());
// ----8<---- END Custom changes ----8<-----------------------------------------
double value = v.doubleValue();
double y1 = rangeAxis.valueToJava2D(value, dataArea,
plot.getRangeAxisEdge());
if (pass == 0 && getItemLineVisible(row, column)) {
if (column != 0) {
Number previousValue = dataset.getValue(row, column - 1);
if (previousValue != null) {
// previous data point...
double previous = previousValue.doubleValue();
// ----8<---- START Custom changes ----8<---------------------------------------
/*double x0 = domainAxis.getCategoryMiddle(column - 1,
getColumnCount(), dataArea,
plot.getDomainAxisEdge());*/
double x0 = domainAxis.getCategoryMiddle(
allCategories.indexOf(dataset.getColumnKey(column - 1)),
allCategories.size(), dataArea,
plot.getDomainAxisEdge());
//----8<---- END Custom changes ----8<-----------------------------------------
double y0 = rangeAxis.valueToJava2D(previous, dataArea,
plot.getRangeAxisEdge());
Line2D line = null;
if (orientation == PlotOrientation.HORIZONTAL) {
line = new Line2D.Double(y0, x0, y1, x1);
}
else if (orientation == PlotOrientation.VERTICAL) {
line = new Line2D.Double(x0, y0, x1, y1);
}
g2.setPaint(getItemPaint(row, column));
g2.setStroke(getItemStroke(row, column));
g2.draw(line);
}
}
}
if (pass == 1) {
Shape shape = getItemShape(row, column);
if (orientation == PlotOrientation.HORIZONTAL) {
shape = ShapeUtilities.createTranslatedShape(shape, y1, x1);
}
else if (orientation == PlotOrientation.VERTICAL) {
shape = ShapeUtilities.createTranslatedShape(shape, x1, y1);
}
if (getItemShapeVisible(row, column)) {
if (getItemShapeFilled(row, column)) {
if (getUseFillPaint()) {
g2.setPaint(getItemFillPaint(row, column));
}
else {
g2.setPaint(getItemPaint(row, column));
}
g2.fill(shape);
}
if (getDrawOutlines()) {
if (getUseFillPaint()) {
g2.setPaint(getItemOutlinePaint(row, column));
}
else {
g2.setPaint(getItemPaint(row, column));
}
g2.setStroke(getItemOutlineStroke(row, column));
g2.draw(shape);
}
}
// draw the item label if there is one...
if (isItemLabelVisible(row, column)) {
if (orientation == PlotOrientation.HORIZONTAL) {
drawItemLabel(g2, orientation, dataset, row, column, y1,
x1, (value < 0.0));
}
else if (orientation == PlotOrientation.VERTICAL) {
drawItemLabel(g2, orientation, dataset, row, column, x1,
y1, (value < 0.0));
}
}
// add an item entity, if this information is being collected
EntityCollection entities = state.getEntityCollection();
if (entities != null) {
addItemEntity(entities, dataset, row, column, shape);
}
}
}
}