diff --git a/src/main/java/org/jfree/chart/renderer/DefaultPolarItemRenderer.java b/src/main/java/org/jfree/chart/renderer/DefaultPolarItemRenderer.java index 5d993b1b6..83d83aa97 100644 --- a/src/main/java/org/jfree/chart/renderer/DefaultPolarItemRenderer.java +++ b/src/main/java/org/jfree/chart/renderer/DefaultPolarItemRenderer.java @@ -123,7 +123,14 @@ public class DefaultPolarItemRenderer extends AbstractRenderer * connected or not. */ private boolean connectFirstAndLastPoint; - + + /** + * Flag that controls if NaN values should be hidden and a gap in the line + * will be drawn. If not active, NaN values will be drawn on top-left of the + * plot. + */ + private boolean hideNaNValues; + /** * A list of tool tip generators (one per series). */ @@ -156,6 +163,7 @@ public DefaultPolarItemRenderer() { this.legendLine = new Line2D.Double(-7.0, 0.0, 7.0, 0.0); this.shapesVisible = true; this.connectFirstAndLastPoint = true; + this.hideNaNValues = false; this.toolTipGeneratorMap = new HashMap<>(); this.urlGenerator = null; @@ -274,6 +282,29 @@ public void setConnectFirstAndLastPoint(boolean connect) { fireChangeEvent(); } + /** + * Returns {@code true} if NaN values should be hidden and a gap in the line + * will be drawn. If not active, NaN values will be drawn on top-left of the + * plot. + * + * @return The current status of the flag. + */ + public boolean getHideNaNValues() { + return this.hideNaNValues; + } + + /** + * Set the flag that controls whether NaN values should be hidden and a gap + * in the line will be drawn. If not active, NaN values will be drawn on + * top-left of the plot. + * + * @param hide the flag. + */ + public void setHideNaNValues(boolean hide) { + this.hideNaNValues = hide; + fireChangeEvent(); + } + /** * Returns the drawing supplier from the plot. * @@ -432,23 +463,47 @@ public void drawSeries(Graphics2D g2, Rectangle2D dataArea, if (numPoints == 0) { return; } - GeneralPath poly = null; + GeneralPath poly = new GeneralPath(); ValueAxis axis = plot.getAxisForDataset(plot.indexOf(dataset)); + boolean startNewSegment = true; for (int i = 0; i < numPoints; i++) { double theta = dataset.getXValue(seriesIndex, i); double radius = dataset.getYValue(seriesIndex, i); - Point p = plot.translateToJava2D(theta, radius, axis, dataArea); - if (poly == null) { - poly = new GeneralPath(); - poly.moveTo(p.x, p.y); + + // Skip NaN values + if (getHideNaNValues() && (Double.isNaN(theta) || Double.isNaN(radius))) { + startNewSegment = true; + continue; } - else { - poly.lineTo(p.x, p.y); + + Point p = plot.translateToJava2D(theta, radius, axis, dataArea); + if (startNewSegment) { + poly.moveTo(p.getX(), p.getY()); + startNewSegment = false; + } else { + poly.lineTo(p.getX(), p.getY()); } } + assert poly != null; if (getConnectFirstAndLastPoint()) { - poly.closePath(); + if (getHideNaNValues()) { + double thetaStart = dataset.getXValue(seriesIndex, 0); + double radiusStart = dataset.getYValue(seriesIndex, 0); + // If hideNanValues is true, check if last or first point is NaN + // If none is NaN, connect first and last point + // If one is NaN, don't connect first and last point + if (!Double.isNaN(dataset.getXValue(seriesIndex, numPoints - 1)) + && !Double.isNaN(dataset.getYValue(seriesIndex, numPoints - 1)) // last point is not NaN + && !Double.isNaN(thetaStart) + && !Double.isNaN(radiusStart)) { // first point is not NaN + // line to first point + Point p = plot.translateToJava2D(thetaStart, radiusStart, axis, dataArea); + poly.lineTo(p.getX(), p.getY()); + } + } else { + poly.closePath(); + } } g2.setPaint(lookupSeriesPaint(seriesIndex)); @@ -830,6 +885,9 @@ public boolean equals(Object obj) { if (this.connectFirstAndLastPoint != that.connectFirstAndLastPoint) { return false; } + if (this.hideNaNValues != that.hideNaNValues) { + return false; + } if (!this.toolTipGeneratorMap.equals(that.toolTipGeneratorMap)) { return false; }