/** * Draws a grid line against the range axis. * * @param g2 the graphics device. * @param plot the plot. * @param axis the value axis. * @param dataArea the area for plotting data (not yet adjusted for any 3D effect). * @param value the value at which the grid line should be drawn. */ public void drawRangeGridline( Graphics2D g2, CategoryPlot plot, ValueAxis axis, Rectangle2D dataArea, double value) { Range range = axis.getRange(); if (!range.contains(value)) { return; } PlotOrientation orientation = plot.getOrientation(); double v = axis.valueToJava2D(value, dataArea, plot.getRangeAxisEdge()); Line2D line = null; if (orientation == PlotOrientation.HORIZONTAL) { line = new Line2D.Double(v, dataArea.getMinY(), v, dataArea.getMaxY()); } else if (orientation == PlotOrientation.VERTICAL) { line = new Line2D.Double(dataArea.getMinX(), v, dataArea.getMaxX(), v); } Paint paint = plot.getRangeGridlinePaint(); if (paint == null) { paint = CategoryPlot.DEFAULT_GRIDLINE_PAINT; } g2.setPaint(paint); Stroke stroke = plot.getRangeGridlineStroke(); if (stroke == null) { stroke = CategoryPlot.DEFAULT_GRIDLINE_STROKE; } g2.setStroke(stroke); g2.draw(line); }
/** * Converts a coordinate from Java 2D space to data space. * * @param java2DValue the coordinate in Java2D space. * @param dataArea the data area. * @param edge the edge. * @return The data value. */ public double java2DToValue(double java2DValue, Rectangle2D dataArea, RectangleEdge edge) { Range range = getRange(); double vmax = range.getUpperBound(); double vp = getCycleBound(); double jmin = 0.0; double jmax = 0.0; if (RectangleEdge.isTopOrBottom(edge)) { jmin = dataArea.getMinX(); jmax = dataArea.getMaxX(); } else if (RectangleEdge.isLeftOrRight(edge)) { jmin = dataArea.getMaxY(); jmax = dataArea.getMinY(); } if (isInverted()) { double jbreak = jmax - (vmax - vp) * (jmax - jmin) / this.period; if (java2DValue >= jbreak) { return vp + (jmax - java2DValue) * this.period / (jmax - jmin); } else { return vp - (java2DValue - jmin) * this.period / (jmax - jmin); } } else { double jbreak = (vmax - vp) * (jmax - jmin) / this.period + jmin; if (java2DValue <= jbreak) { return vp + (java2DValue - jmin) * this.period / (jmax - jmin); } else { return vp - (jmax - java2DValue) * this.period / (jmax - jmin); } } }
/** * Returns the content size for the title. This will reflect the fact that a text title positioned * on the left or right of a chart will be rotated 90 degrees. * * @param g2 the graphics device. * @param widthRange the width range. * @param heightRange the height range. * @return The content size. */ protected Size2D arrangeRR(Graphics2D g2, Range widthRange, Range heightRange) { RectangleEdge position = getPosition(); if (position == RectangleEdge.TOP || position == RectangleEdge.BOTTOM) { float maxWidth = (float) widthRange.getUpperBound(); // determine the space required for the axis AxisSpace space = this.axis.reserveSpace( g2, null, new Rectangle2D.Double(0, 0, maxWidth, 100), RectangleEdge.BOTTOM, null); return new Size2D( maxWidth, this.stripWidth + this.axisOffset + space.getTop() + space.getBottom()); } else if (position == RectangleEdge.LEFT || position == RectangleEdge.RIGHT) { float maxHeight = (float) heightRange.getUpperBound(); AxisSpace space = this.axis.reserveSpace( g2, null, new Rectangle2D.Double(0, 0, 100, maxHeight), RectangleEdge.RIGHT, null); return new Size2D( this.stripWidth + this.axisOffset + space.getLeft() + space.getRight(), maxHeight); } else { throw new RuntimeException("Unrecognised position."); } }
/** * Converts a coordinate in Java2D space to the corresponding data value, assuming that the axis * runs along one edge of the specified plotArea. * * @param java2DValue the coordinate in Java2D space. * @param plotArea the area in which the data is plotted. * @param edge the axis location. * @return The data value. */ @Override public double java2DToValue(double java2DValue, Rectangle2D plotArea, RectangleEdge edge) { Range range = getRange(); double axisMin = switchedLog10(range.getLowerBound()); double axisMax = switchedLog10(range.getUpperBound()); double plotMin = 0.0; double plotMax = 0.0; if (RectangleEdge.isTopOrBottom(edge)) { plotMin = plotArea.getX(); plotMax = plotArea.getMaxX(); } else if (RectangleEdge.isLeftOrRight(edge)) { plotMin = plotArea.getMaxY(); plotMax = plotArea.getMinY(); } if (isInverted()) { return switchedPow10( axisMax - ((java2DValue - plotMin) / (plotMax - plotMin)) * (axisMax - axisMin)); } else { return switchedPow10( axisMin + ((java2DValue - plotMin) / (plotMax - plotMin)) * (axisMax - axisMin)); } }
/** * Scales the range by the specified factor. * * @param base the base range (<code>null</code> not permitted). * @param factor the scaling factor (must be non-negative). * @return A new range. * @since 1.0.9 */ public static Range scale(Range base, double factor) { ParamChecks.nullNotPermitted(base, "base"); if (factor < 0) { throw new IllegalArgumentException("Negative 'factor' argument."); } return new Range(base.getLowerBound() * factor, base.getUpperBound() * factor); }
/** Rescales the axis to ensure that all data is visible. */ @Override protected void autoAdjustRange() { Plot plot = getPlot(); if (plot == null) { return; // no plot, no data } if (plot instanceof ValueAxisPlot) { ValueAxisPlot vap = (ValueAxisPlot) plot; Range r = vap.getDataRange(this); if (r == null) { r = getDefaultAutoRange(); } long upper = Math.round(r.getUpperBound()); long lower = Math.round(r.getLowerBound()); this.first = createInstance( this.autoRangeTimePeriodClass, new Date(lower), this.timeZone, this.locale); this.last = createInstance( this.autoRangeTimePeriodClass, new Date(upper), this.timeZone, this.locale); setRange(r, false, false); } }
/** * Converts a data value to a coordinate in Java2D space, assuming that the axis runs along one * edge of the specified plotArea. Note that it is possible for the coordinate to fall outside the * plotArea. * * @param value the data value. * @param plotArea the area for plotting the data. * @param edge the axis location. * @return The Java2D coordinate. */ @Override public double valueToJava2D(double value, Rectangle2D plotArea, RectangleEdge edge) { Range range = getRange(); double axisMin = switchedLog10(range.getLowerBound()); double axisMax = switchedLog10(range.getUpperBound()); double min = 0.0; double max = 0.0; if (RectangleEdge.isTopOrBottom(edge)) { min = plotArea.getMinX(); max = plotArea.getMaxX(); } else if (RectangleEdge.isLeftOrRight(edge)) { min = plotArea.getMaxY(); max = plotArea.getMinY(); } value = switchedLog10(value); if (isInverted()) { return max - (((value - axisMin) / (axisMax - axisMin)) * (max - min)); } else { return min + (((value - axisMin) / (axisMax - axisMin)) * (max - min)); } }
/** * Sets a new axis range. The period is extended to fit the range size, if necessary. * * @param range the range. * @param turnOffAutoRange switch off the auto range. * @param notify notify? * @see org.jfree.chart.axis.ValueAxis#setRange(Range, boolean, boolean) */ public void setRange(Range range, boolean turnOffAutoRange, boolean notify) { double size = range.getUpperBound() - range.getLowerBound(); if (size > this.period) { this.period = size; } super.setRange(range, turnOffAutoRange, notify); }
protected int calculateVisibleTickCount() { double unit = getTickUnit().getSize(); Range range = getRange(); return (int) ((Math.floor(range.getUpperBound() / unit) - Math.ceil(range.getLowerBound() / unit)) + NormalizedMatrixSeries.DEFAULT_SCALE_FACTOR); }
/** Replaces the dataset and checks that the data range is as expected. */ public void testReplaceDataset() { // create a dataset... Number[][] data = new Integer[][] { {new Integer(-30), new Integer(-20)}, {new Integer(-10), new Integer(10)}, {new Integer(20), new Integer(30)} }; CategoryDataset newData = DatasetUtilities.createCategoryDataset("S", "C", data); LocalListener l = new LocalListener(); this.chart.addChangeListener(l); this.chart.getCategoryPlot().setDataset(newData); assertEquals(true, l.flag); ValueAxis axis = this.chart.getCategoryPlot().getRangeAxis(); Range range = axis.getRange(); assertTrue( "Expecting the lower bound of the range to be around -30: " + range.getLowerBound(), range.getLowerBound() <= -30); assertTrue( "Expecting the upper bound of the range to be around 30: " + range.getUpperBound(), range.getUpperBound() >= 30); }
public void stateChanged(ChangeEvent changeevent) { int i = slider.getValue(); XYPlot xyplot = (XYPlot) chart.getPlot(); ValueAxis valueaxis = xyplot.getDomainAxis(); Range range = valueaxis.getRange(); double d = valueaxis.getLowerBound() + ((double) i / 100D) * range.getLength(); xyplot.setDomainCrosshairValue(d); }
/** * Handles a state change event. * * @param event the event. */ public void stateChanged(ChangeEvent event) { int value = this.slider.getValue(); XYPlot plot = this.chart.getXYPlot(); ValueAxis domainAxis = plot.getDomainAxis(); Range range = domainAxis.getRange(); double c = domainAxis.getLowerBound() + (value / 100.0) * range.getLength(); plot.setDomainCrosshairValue(c); }
/** * Arranges the content for this title assuming a range constraint for the width and no bounds on * the height, and returns the required size. This will reflect the fact that a text title * positioned on the left or right of a chart will be rotated by 90 degrees. * * @param g2 the graphics target. * @param widthRange the range for the width. * @return The content size. * @since 1.0.9 */ protected Size2D arrangeRN(Graphics2D g2, Range widthRange) { Size2D s = arrangeNN(g2); if (widthRange.contains(s.getWidth())) { return s; } double ww = widthRange.constrain(s.getWidth()); return arrangeFN(g2, ww); }
/** * Returns the maximum x-value in the dataset. * * @param includeInterval a flag that determines whether or not the x-interval is taken into * account. * @return The maximum value. */ public double getDomainUpperBound(boolean includeInterval) { double result = Double.NaN; Range r = getDomainBounds(includeInterval); if (r != null) { result = r.getUpperBound(); } return result; }
/** * Shifts the range by the specified amount. * * @param base the base range (<code>null</code> not permitted). * @param delta the shift amount. * @param allowZeroCrossing a flag that determines whether or not the bounds of the range are * allowed to cross zero after adjustment. * @return A new range. */ public static Range shift(Range base, double delta, boolean allowZeroCrossing) { ParamChecks.nullNotPermitted(base, "base"); if (allowZeroCrossing) { return new Range(base.getLowerBound() + delta, base.getUpperBound() + delta); } else { return new Range( shiftWithNoZeroCrossing(base.getLowerBound(), delta), shiftWithNoZeroCrossing(base.getUpperBound(), delta)); } }
/** * Returns the lower and upper bounds (range) of the x-values in the specified dataset. * * @param dataset the dataset (<code>null</code> permitted). * @return The range (<code>null</code> if the dataset is <code>null</code> or empty). * @see #findRangeBounds(XYDataset) */ public Range findDomainBounds(XYDataset dataset) { if (dataset == null) { return null; } Range r = DatasetUtilities.findDomainBounds(dataset, false); if (r == null) { return null; } return new Range( r.getLowerBound() + this.xOffset, r.getUpperBound() + this.blockWidth + this.xOffset); }
/** * Combines two ranges. This method has a special handling for Double.NaN. * * @param range1 the first range (<code>null</code> permitted). * @param range2 the second range (<code>null</code> permitted). * @return A new range (possibly <code>null</code>). * @since 1.0.15 */ public static Range combineIgnoringNaN(Range range1, Range range2) { if (range1 == null) { return range2; } if (range2 == null) { return range1; } double l = min(range1.getLowerBound(), range2.getLowerBound()); double u = max(range1.getUpperBound(), range2.getUpperBound()); return new Range(l, u); }
/** * Returns the range of values the renderer requires to display all the items from the specified * dataset. * * @param dataset the dataset (<code>null</code> permitted). * @return The range (<code>null</code> if the dataset is <code>null</code> or empty). */ public Range findRangeBounds(XYDataset dataset) { if (dataset == null) { return null; } Range r = DatasetUtilities.findRangeBounds(dataset, false); if (r == null) { return null; } double offset = 0; // TODO getSeriesShape(n).getBounds().height / 2; return new Range(r.getLowerBound() + offset, r.getUpperBound() + offset); }
/** * Creates a new range by adding margins to an existing range. * * @param range the range (<code>null</code> not permitted). * @param lowerMargin the lower margin (expressed as a percentage of the range length). * @param upperMargin the upper margin (expressed as a percentage of the range length). * @return The expanded range. */ public static Range expand(Range range, double lowerMargin, double upperMargin) { ParamChecks.nullNotPermitted(range, "range"); double length = range.getLength(); double lower = range.getLowerBound() - length * lowerMargin; double upper = range.getUpperBound() + length * upperMargin; if (lower > upper) { lower = lower / 2.0 + upper / 2.0; upper = lower; } return new Range(lower, upper); }
/** A test for bug 3072674. */ @Test public void test3072674() { DefaultStatisticalCategoryDataset dataset = new DefaultStatisticalCategoryDataset(); dataset.add(1.0, Double.NaN, "R1", "C1"); assertEquals(1.0, dataset.getRangeLowerBound(true), EPSILON); assertEquals(1.0, dataset.getRangeUpperBound(true), EPSILON); Range r = dataset.getRangeBounds(true); assertEquals(1.0, r.getLowerBound(), EPSILON); assertEquals(1.0, r.getUpperBound(), EPSILON); }
/** * Sets the range for the axis, if requested, sends an {@link AxisChangeEvent} to all registered * listeners. As a side-effect, the auto-range flag is set to <code>false</code> (optional). * * @param range the range (<code>null</code> not permitted). * @param turnOffAutoRange a flag that controls whether or not the auto range is turned off. * @param notify a flag that controls whether or not listeners are notified. */ public void setRange(Range range, boolean turnOffAutoRange, boolean notify) { long upper = Math.round(range.getUpperBound()); long lower = Math.round(range.getLowerBound()); this.first = createInstance(this.autoRangeTimePeriodClass, new Date(lower), this.timeZone, this.locale); this.last = createInstance(this.autoRangeTimePeriodClass, new Date(upper), this.timeZone, this.locale); super.setRange( new Range(this.first.getFirstMillisecond(), this.last.getLastMillisecond() + 1.0), turnOffAutoRange, notify); }
/** * Returns the range of the values in the dataset's domain, including or excluding the interval * around each x-value as specified. * * @param includeInterval a flag that determines whether or not the x-interval should be taken * into account. * @return The range. */ @Override public Range getDomainBounds(boolean includeInterval) { // first get the range without the interval, then expand it for the // interval width Range range = DatasetUtilities.findDomainBounds(this.dataset, false); if (includeInterval && range != null) { double lowerAdj = getIntervalWidth() * getIntervalPositionFactor(); double upperAdj = getIntervalWidth() - lowerAdj; range = new Range(range.getLowerBound() - lowerAdj, range.getUpperBound() + upperAdj); } return range; }
/** * Returns a range that includes all the values in the specified <code>range</code> AND the * specified <code>value</code>. * * @param range the range (<code>null</code> permitted). * @param value the value that must be included. * @return A range. * @since 1.0.1 */ public static Range expandToInclude(Range range, double value) { if (range == null) { return new Range(value, value); } if (value < range.getLowerBound()) { return new Range(value, range.getUpperBound()); } else if (value > range.getUpperBound()) { return new Range(range.getLowerBound(), value); } else { return range; } }
/** * Returns the range of values the renderer requires to display all the items from the specified * dataset. * * @param dataset the dataset (<code>null</code> permitted). * @return The range (<code>null</code> if the dataset is <code>null</code> or empty). * @see #findDomainBounds(XYDataset) */ public Range findRangeBounds(XYDataset dataset) { if (dataset != null) { Range r = DatasetUtilities.findRangeBounds(dataset, false); if (r == null) { return null; } else { return new Range( r.getLowerBound() + this.yOffset, r.getUpperBound() + this.blockHeight + this.yOffset); } } else { return null; } }
private Range trimToContentHeight(Range r) { if (r == null) { return null; } double lowerBound = 0.0; double upperBound = Double.POSITIVE_INFINITY; if (r.getLowerBound() > 0.0) { lowerBound = trimToContentHeight(r.getLowerBound()); } if (r.getUpperBound() < Double.POSITIVE_INFINITY) { upperBound = trimToContentHeight(r.getUpperBound()); } return new Range(lowerBound, upperBound); }
/** * Draws a range marker. * * @param g2 the graphics device. * @param plot the plot. * @param axis the value axis. * @param marker the marker. * @param dataArea the area for plotting data (not including 3D effect). */ @Override public void drawRangeMarker( Graphics2D g2, CategoryPlot plot, ValueAxis axis, Marker marker, Rectangle2D dataArea) { Rectangle2D adjusted = new Rectangle2D.Double( dataArea.getX(), dataArea.getY() + getYOffset(), dataArea.getWidth() - getXOffset(), dataArea.getHeight() - getYOffset()); if (marker instanceof ValueMarker) { ValueMarker vm = (ValueMarker) marker; double value = vm.getValue(); Range range = axis.getRange(); if (!range.contains(value)) { return; } GeneralPath path = null; PlotOrientation orientation = plot.getOrientation(); if (orientation == PlotOrientation.HORIZONTAL) { float x = (float) axis.valueToJava2D(value, adjusted, plot.getRangeAxisEdge()); float y = (float) adjusted.getMaxY(); path = new GeneralPath(); path.moveTo(x, y); path.lineTo((float) (x + getXOffset()), y - (float) getYOffset()); path.lineTo((float) (x + getXOffset()), (float) (adjusted.getMinY() - getYOffset())); path.lineTo(x, (float) adjusted.getMinY()); path.closePath(); } else if (orientation == PlotOrientation.VERTICAL) { float y = (float) axis.valueToJava2D(value, adjusted, plot.getRangeAxisEdge()); float x = (float) dataArea.getX(); path = new GeneralPath(); path.moveTo(x, y); path.lineTo(x + (float) this.xOffset, y - (float) this.yOffset); path.lineTo((float) (adjusted.getMaxX() + this.xOffset), y - (float) this.yOffset); path.lineTo((float) (adjusted.getMaxX()), y); path.closePath(); } g2.setPaint(marker.getPaint()); g2.fill(path); g2.setPaint(marker.getOutlinePaint()); g2.draw(path); } else { super.drawRangeMarker(g2, plot, axis, marker, adjusted); // TODO: draw the interval marker with a 3D effect } }
/** * Draws a line perpendicular to the range axis. * * @param g2 the graphics device. * @param plot the plot. * @param axis the value axis. * @param dataArea the area for plotting data (not yet adjusted for any 3D effect). * @param value the value at which the grid line should be drawn. * @param paint the paint. * @param stroke the stroke. * @see #drawRangeGridline * @since 1.0.13 */ public void drawRangeLine( Graphics2D g2, CategoryPlot plot, ValueAxis axis, Rectangle2D dataArea, double value, Paint paint, Stroke stroke) { Range range = axis.getRange(); if (!range.contains(value)) { return; } Rectangle2D adjusted = new Rectangle2D.Double( dataArea.getX(), dataArea.getY() + getYOffset(), dataArea.getWidth() - getXOffset(), dataArea.getHeight() - getYOffset()); Line2D line1 = null; Line2D line2 = null; PlotOrientation orientation = plot.getOrientation(); if (orientation == PlotOrientation.HORIZONTAL) { double x0 = axis.valueToJava2D(value, adjusted, plot.getRangeAxisEdge()); double x1 = x0 + getXOffset(); double y0 = dataArea.getMaxY(); double y1 = y0 - getYOffset(); double y2 = dataArea.getMinY(); line1 = new Line2D.Double(x0, y0, x1, y1); line2 = new Line2D.Double(x1, y1, x1, y2); } else if (orientation == PlotOrientation.VERTICAL) { double y0 = axis.valueToJava2D(value, adjusted, plot.getRangeAxisEdge()); double y1 = y0 - getYOffset(); double x0 = dataArea.getMinX(); double x1 = x0 + getXOffset(); double x2 = dataArea.getMaxX(); line1 = new Line2D.Double(x0, y0, x1, y1); line2 = new Line2D.Double(x1, y1, x2, y1); } g2.setPaint(paint); g2.setStroke(stroke); g2.draw(line1); g2.draw(line2); }
public double java2DToValue(double java2DValue, Rectangle2D area, RectangleEdge edge) { Range range = getRange(); double axisMin = range.getLowerBound(); double axisMax = range.getUpperBound(); double min = 0.0d; double max = 0.0d; if (RectangleEdge.isTopOrBottom(edge)) { min = area.getX(); max = area.getMaxX(); } else if (RectangleEdge.isLeftOrRight(edge)) { min = area.getMaxY(); max = area.getY(); } if (isInverted()) { return axisMax - (((java2DValue - min) / (max - min)) * (axisMax - axisMin)); } return (((java2DValue - min) / (max - min)) * (axisMax - axisMin)) + axisMin; }
/** Check that the renderer is calculating the range bounds correctly. */ @Test public void testFindRangeBounds() { TableXYDataset dataset = RendererXYPackageTests.createTestTableXYDataset(); JFreeChart chart = ChartFactory.createStackedXYAreaChart("Test Chart", "X", "Y", dataset); XYPlot plot = (XYPlot) chart.getPlot(); StackedXYAreaRenderer2 renderer = new StackedXYAreaRenderer2(); plot.setRenderer(renderer); NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis(); Range bounds = rangeAxis.getRange(); assertTrue(bounds.contains(6.0)); assertTrue(bounds.contains(8.0)); // try null argument assertNull(renderer.findRangeBounds(null)); // try empty dataset assertNull(renderer.findRangeBounds(new DefaultTableXYDataset())); }
/** * Returns the content size for the title. This will reflect the fact that a text title positioned * on the left or right of a chart will be rotated 90 degrees. * * @param g2 the graphics device. * @param widthRange the width range. * @param heightRange the height range. * @return The content size. */ protected Size2D arrangeRR(Graphics2D g2, Range widthRange, Range heightRange) { RectangleEdge position = getPosition(); if (position == RectangleEdge.TOP || position == RectangleEdge.BOTTOM) { float maxWidth = (float) widthRange.getUpperBound(); g2.setFont(this.font); this.content = TextUtilities.createTextBlock( this.text, this.font, this.paint, maxWidth, this.maximumLinesToDisplay, new G2TextMeasurer(g2)); this.content.setLineAlignment(this.textAlignment); Size2D contentSize = this.content.calculateDimensions(g2); if (this.expandToFitSpace) { return new Size2D(maxWidth, contentSize.getHeight()); } else { return contentSize; } } else if (position == RectangleEdge.LEFT || position == RectangleEdge.RIGHT) { float maxWidth = (float) heightRange.getUpperBound(); g2.setFont(this.font); this.content = TextUtilities.createTextBlock( this.text, this.font, this.paint, maxWidth, this.maximumLinesToDisplay, new G2TextMeasurer(g2)); this.content.setLineAlignment(this.textAlignment); Size2D contentSize = this.content.calculateDimensions(g2); // transpose the dimensions, because the title is rotated if (this.expandToFitSpace) { return new Size2D(contentSize.getHeight(), maxWidth); } else { return new Size2D(contentSize.height, contentSize.width); } } else { throw new RuntimeException("Unrecognised exception."); } }