/* ====================================================== * JFreeChart : a chart library for the Java(tm) platform * ====================================================== * * (C) Copyright 2000-present, by David Gilbert and Contributors. * * Project Info: https://www.jfree.org/jfreechart/index.html * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, * USA. * * [Oracle and Java are registered trademarks of Oracle and/or its affiliates. * Other names may be trademarks of their respective owners.] * * ----------- * XYPlot.java * ----------- * (C) Copyright 2000-present, by David Gilbert and Contributors. * * Original Author: David Gilbert; * Contributor(s): Craig MacFarlane; * Mark Watson (www.markwatson.com); * Jonathan Nash; * Gideon Krause; * Klaus Rheinwald; * Xavier Poinsard; * Richard Atkinson; * Arnaud Lelievre; * Nicolas Brodu; * Eduardo Ramalho; * Sergei Ivanov; * Richard West, Advanced Micro Devices, Inc.; * Ulrich Voigt - patches 1997549 and 2686040; * Peter Kolb - patches 1934255, 2603321 and 2809117; * Andrew Mickish - patch 1868749; * */ package org.jfree.chart.plot; import org.jfree.chart.ChartElementVisitor; import org.jfree.chart.JFreeChart; import org.jfree.chart.annotations.Annotation; import org.jfree.chart.annotations.XYAnnotation; import org.jfree.chart.annotations.XYAnnotationBoundsInfo; import org.jfree.chart.api.Layer; import org.jfree.chart.api.PublicCloneable; import org.jfree.chart.api.RectangleEdge; import org.jfree.chart.api.RectangleInsets; import org.jfree.chart.axis.*; import org.jfree.chart.event.*; import org.jfree.chart.internal.Args; import org.jfree.chart.internal.CloneUtils; import org.jfree.chart.internal.PaintUtils; import org.jfree.chart.internal.SerialUtils; import org.jfree.chart.legend.LegendItem; import org.jfree.chart.legend.LegendItemCollection; import org.jfree.chart.renderer.RendererUtils; import org.jfree.chart.renderer.xy.AbstractXYItemRenderer; import org.jfree.chart.renderer.xy.XYItemRenderer; import org.jfree.chart.renderer.xy.XYItemRendererState; import org.jfree.chart.util.ShadowGenerator; import org.jfree.data.Range; import org.jfree.data.general.DatasetChangeEvent; import org.jfree.data.general.DatasetUtils; import org.jfree.data.xy.XYDataset; import java.awt.*; import java.awt.geom.Line2D; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.List; import java.util.*; import java.util.Map.Entry; /** * A general class for plotting data in the form of (x, y) pairs. This plot can * use data from any class that implements the {@link XYDataset} interface. *
* {@code XYPlot} makes use of an {@link XYItemRenderer} to draw each point * on the plot. By using different renderers, various chart types can be * produced. *
* The {@link org.jfree.chart.ChartFactory} class contains static methods for
* creating pre-configured charts.
*
* @param
* If the flag value is changed, a {@link PlotChangeEvent} is sent to all
* registered listeners.
*
* @param visible the new value of the flag.
*
* @see #isDomainGridlinesVisible()
*/
public void setDomainGridlinesVisible(boolean visible) {
if (this.domainGridlinesVisible != visible) {
this.domainGridlinesVisible = visible;
fireChangeEvent();
}
}
/**
* Returns {@code true} if the domain minor gridlines are visible, and
* {@code false} otherwise.
*
* @return {@code true} or {@code false}.
*
* @see #setDomainMinorGridlinesVisible(boolean)
*/
public boolean isDomainMinorGridlinesVisible() {
return this.domainMinorGridlinesVisible;
}
/**
* Sets the flag that controls whether the domain minor grid-lines
* are visible.
*
* If the flag value is changed, a {@link PlotChangeEvent} is sent to all
* registered listeners.
*
* @param visible the new value of the flag.
*
* @see #isDomainMinorGridlinesVisible()
*/
public void setDomainMinorGridlinesVisible(boolean visible) {
if (this.domainMinorGridlinesVisible != visible) {
this.domainMinorGridlinesVisible = visible;
fireChangeEvent();
}
}
/**
* Returns the stroke for the grid-lines (if any) plotted against the
* domain axis.
*
* @return The stroke (never {@code null}).
*
* @see #setDomainGridlineStroke(Stroke)
*/
public Stroke getDomainGridlineStroke() {
return this.domainGridlineStroke;
}
/**
* Sets the stroke for the grid lines plotted against the domain axis, and
* sends a {@link PlotChangeEvent} to all registered listeners.
*
* @param stroke the stroke ({@code null} not permitted).
*
* @see #getDomainGridlineStroke()
*/
public void setDomainGridlineStroke(Stroke stroke) {
Args.nullNotPermitted(stroke, "stroke");
this.domainGridlineStroke = stroke;
fireChangeEvent();
}
/**
* Returns the stroke for the minor grid-lines (if any) plotted against the
* domain axis.
*
* @return The stroke (never {@code null}).
*
* @see #setDomainMinorGridlineStroke(Stroke)
*/
public Stroke getDomainMinorGridlineStroke() {
return this.domainMinorGridlineStroke;
}
/**
* Sets the stroke for the minor grid lines plotted against the domain
* axis, and sends a {@link PlotChangeEvent} to all registered listeners.
*
* @param stroke the stroke ({@code null} not permitted).
*
* @see #getDomainMinorGridlineStroke()
*/
public void setDomainMinorGridlineStroke(Stroke stroke) {
Args.nullNotPermitted(stroke, "stroke");
this.domainMinorGridlineStroke = stroke;
fireChangeEvent();
}
/**
* Returns the paint for the grid lines (if any) plotted against the domain
* axis.
*
* @return The paint (never {@code null}).
*
* @see #setDomainGridlinePaint(Paint)
*/
public Paint getDomainGridlinePaint() {
return this.domainGridlinePaint;
}
/**
* Sets the paint for the grid lines plotted against the domain axis, and
* sends a {@link PlotChangeEvent} to all registered listeners.
*
* @param paint the paint ({@code null} not permitted).
*
* @see #getDomainGridlinePaint()
*/
public void setDomainGridlinePaint(Paint paint) {
Args.nullNotPermitted(paint, "paint");
this.domainGridlinePaint = paint;
fireChangeEvent();
}
/**
* Returns the paint for the minor grid lines (if any) plotted against the
* domain axis.
*
* @return The paint (never {@code null}).
*
* @see #setDomainMinorGridlinePaint(Paint)
*/
public Paint getDomainMinorGridlinePaint() {
return this.domainMinorGridlinePaint;
}
/**
* Sets the paint for the minor grid lines plotted against the domain axis,
* and sends a {@link PlotChangeEvent} to all registered listeners.
*
* @param paint the paint ({@code null} not permitted).
*
* @see #getDomainMinorGridlinePaint()
*/
public void setDomainMinorGridlinePaint(Paint paint) {
Args.nullNotPermitted(paint, "paint");
this.domainMinorGridlinePaint = paint;
fireChangeEvent();
}
/**
* Returns {@code true} if the range axis grid is visible, and
* {@code false} otherwise.
*
* @return A boolean.
*
* @see #setRangeGridlinesVisible(boolean)
*/
public boolean isRangeGridlinesVisible() {
return this.rangeGridlinesVisible;
}
/**
* Sets the flag that controls whether the range axis grid lines
* are visible.
*
* If the flag value is changed, a {@link PlotChangeEvent} is sent to all
* registered listeners.
*
* @param visible the new value of the flag.
*
* @see #isRangeGridlinesVisible()
*/
public void setRangeGridlinesVisible(boolean visible) {
if (this.rangeGridlinesVisible != visible) {
this.rangeGridlinesVisible = visible;
fireChangeEvent();
}
}
/**
* Returns the stroke for the grid lines (if any) plotted against the
* range axis.
*
* @return The stroke (never {@code null}).
*
* @see #setRangeGridlineStroke(Stroke)
*/
public Stroke getRangeGridlineStroke() {
return this.rangeGridlineStroke;
}
/**
* Sets the stroke for the grid lines plotted against the range axis,
* and sends a {@link PlotChangeEvent} to all registered listeners.
*
* @param stroke the stroke ({@code null} not permitted).
*
* @see #getRangeGridlineStroke()
*/
public void setRangeGridlineStroke(Stroke stroke) {
Args.nullNotPermitted(stroke, "stroke");
this.rangeGridlineStroke = stroke;
fireChangeEvent();
}
/**
* Returns the paint for the grid lines (if any) plotted against the range
* axis.
*
* @return The paint (never {@code null}).
*
* @see #setRangeGridlinePaint(Paint)
*/
public Paint getRangeGridlinePaint() {
return this.rangeGridlinePaint;
}
/**
* Sets the paint for the grid lines plotted against the range axis and
* sends a {@link PlotChangeEvent} to all registered listeners.
*
* @param paint the paint ({@code null} not permitted).
*
* @see #getRangeGridlinePaint()
*/
public void setRangeGridlinePaint(Paint paint) {
Args.nullNotPermitted(paint, "paint");
this.rangeGridlinePaint = paint;
fireChangeEvent();
}
/**
* Returns {@code true} if the range axis minor grid is visible, and
* {@code false} otherwise.
*
* @return A boolean.
*
* @see #setRangeMinorGridlinesVisible(boolean)
*/
public boolean isRangeMinorGridlinesVisible() {
return this.rangeMinorGridlinesVisible;
}
/**
* Sets the flag that controls whether the range axis minor grid
* lines are visible.
*
* If the flag value is changed, a {@link PlotChangeEvent} is sent to all
* registered listeners.
*
* @param visible the new value of the flag.
*
* @see #isRangeMinorGridlinesVisible()
*/
public void setRangeMinorGridlinesVisible(boolean visible) {
if (this.rangeMinorGridlinesVisible != visible) {
this.rangeMinorGridlinesVisible = visible;
fireChangeEvent();
}
}
/**
* Returns the stroke for the minor grid lines (if any) plotted against the
* range axis.
*
* @return The stroke (never {@code null}).
*
* @see #setRangeMinorGridlineStroke(Stroke)
*/
public Stroke getRangeMinorGridlineStroke() {
return this.rangeMinorGridlineStroke;
}
/**
* Sets the stroke for the minor grid lines plotted against the range axis,
* and sends a {@link PlotChangeEvent} to all registered listeners.
*
* @param stroke the stroke ({@code null} not permitted).
*
* @see #getRangeMinorGridlineStroke()
*/
public void setRangeMinorGridlineStroke(Stroke stroke) {
Args.nullNotPermitted(stroke, "stroke");
this.rangeMinorGridlineStroke = stroke;
fireChangeEvent();
}
/**
* Returns the paint for the minor grid lines (if any) plotted against the
* range axis.
*
* @return The paint (never {@code null}).
*
* @see #setRangeMinorGridlinePaint(Paint)
*/
public Paint getRangeMinorGridlinePaint() {
return this.rangeMinorGridlinePaint;
}
/**
* Sets the paint for the minor grid lines plotted against the range axis
* and sends a {@link PlotChangeEvent} to all registered listeners.
*
* @param paint the paint ({@code null} not permitted).
*
* @see #getRangeMinorGridlinePaint()
*/
public void setRangeMinorGridlinePaint(Paint paint) {
Args.nullNotPermitted(paint, "paint");
this.rangeMinorGridlinePaint = paint;
fireChangeEvent();
}
/**
* Returns a flag that controls whether a zero baseline is
* displayed for the domain axis.
*
* @return A boolean.
*
* @see #setDomainZeroBaselineVisible(boolean)
*/
public boolean isDomainZeroBaselineVisible() {
return this.domainZeroBaselineVisible;
}
/**
* Sets the flag that controls whether the zero baseline is
* displayed for the domain axis, and sends a {@link PlotChangeEvent} to
* all registered listeners.
*
* @param visible the flag.
*
* @see #isDomainZeroBaselineVisible()
*/
public void setDomainZeroBaselineVisible(boolean visible) {
this.domainZeroBaselineVisible = visible;
fireChangeEvent();
}
/**
* Returns the stroke used for the zero baseline against the domain axis.
*
* @return The stroke (never {@code null}).
*
* @see #setDomainZeroBaselineStroke(Stroke)
*/
public Stroke getDomainZeroBaselineStroke() {
return this.domainZeroBaselineStroke;
}
/**
* Sets the stroke for the zero baseline for the domain axis,
* and sends a {@link PlotChangeEvent} to all registered listeners.
*
* @param stroke the stroke ({@code null} not permitted).
*
* @see #getRangeZeroBaselineStroke()
*/
public void setDomainZeroBaselineStroke(Stroke stroke) {
Args.nullNotPermitted(stroke, "stroke");
this.domainZeroBaselineStroke = stroke;
fireChangeEvent();
}
/**
* Returns the paint for the zero baseline (if any) plotted against the
* domain axis.
*
* @return The paint (never {@code null}).
*
* @see #setDomainZeroBaselinePaint(Paint)
*/
public Paint getDomainZeroBaselinePaint() {
return this.domainZeroBaselinePaint;
}
/**
* Sets the paint for the zero baseline plotted against the domain axis and
* sends a {@link PlotChangeEvent} to all registered listeners.
*
* @param paint the paint ({@code null} not permitted).
*
* @see #getDomainZeroBaselinePaint()
*/
public void setDomainZeroBaselinePaint(Paint paint) {
Args.nullNotPermitted(paint, "paint");
this.domainZeroBaselinePaint = paint;
fireChangeEvent();
}
/**
* Returns a flag that controls whether a zero baseline is
* displayed for the range axis.
*
* @return A boolean.
*
* @see #setRangeZeroBaselineVisible(boolean)
*/
public boolean isRangeZeroBaselineVisible() {
return this.rangeZeroBaselineVisible;
}
/**
* Sets the flag that controls whether the zero baseline is
* displayed for the range axis, and sends a {@link PlotChangeEvent} to
* all registered listeners.
*
* @param visible the flag.
*
* @see #isRangeZeroBaselineVisible()
*/
public void setRangeZeroBaselineVisible(boolean visible) {
this.rangeZeroBaselineVisible = visible;
fireChangeEvent();
}
/**
* Returns the stroke used for the zero baseline against the range axis.
*
* @return The stroke (never {@code null}).
*
* @see #setRangeZeroBaselineStroke(Stroke)
*/
public Stroke getRangeZeroBaselineStroke() {
return this.rangeZeroBaselineStroke;
}
/**
* Sets the stroke for the zero baseline for the range axis,
* and sends a {@link PlotChangeEvent} to all registered listeners.
*
* @param stroke the stroke ({@code null} not permitted).
*
* @see #getRangeZeroBaselineStroke()
*/
public void setRangeZeroBaselineStroke(Stroke stroke) {
Args.nullNotPermitted(stroke, "stroke");
this.rangeZeroBaselineStroke = stroke;
fireChangeEvent();
}
/**
* Returns the paint for the zero baseline (if any) plotted against the
* range axis.
*
* @return The paint (never {@code null}).
*
* @see #setRangeZeroBaselinePaint(Paint)
*/
public Paint getRangeZeroBaselinePaint() {
return this.rangeZeroBaselinePaint;
}
/**
* Sets the paint for the zero baseline plotted against the range axis and
* sends a {@link PlotChangeEvent} to all registered listeners.
*
* @param paint the paint ({@code null} not permitted).
*
* @see #getRangeZeroBaselinePaint()
*/
public void setRangeZeroBaselinePaint(Paint paint) {
Args.nullNotPermitted(paint, "paint");
this.rangeZeroBaselinePaint = paint;
fireChangeEvent();
}
/**
* Returns the paint used for the domain tick bands. If this is
* {@code null}, no tick bands will be drawn.
*
* @return The paint (possibly {@code null}).
*
* @see #setDomainTickBandPaint(Paint)
*/
public Paint getDomainTickBandPaint() {
return this.domainTickBandPaint;
}
/**
* Sets the paint for the domain tick bands.
*
* @param paint the paint ({@code null} permitted).
*
* @see #getDomainTickBandPaint()
*/
public void setDomainTickBandPaint(Paint paint) {
this.domainTickBandPaint = paint;
fireChangeEvent();
}
/**
* Returns the paint used for the range tick bands. If this is
* {@code null}, no tick bands will be drawn.
*
* @return The paint (possibly {@code null}).
*
* @see #setRangeTickBandPaint(Paint)
*/
public Paint getRangeTickBandPaint() {
return this.rangeTickBandPaint;
}
/**
* Sets the paint for the range tick bands.
*
* @param paint the paint ({@code null} permitted).
*
* @see #getRangeTickBandPaint()
*/
public void setRangeTickBandPaint(Paint paint) {
this.rangeTickBandPaint = paint;
fireChangeEvent();
}
/**
* Returns the origin for the quadrants that can be displayed on the plot.
* This defaults to (0, 0).
*
* @return The origin point (never {@code null}).
*
* @see #setQuadrantOrigin(Point2D)
*/
public Point2D getQuadrantOrigin() {
return this.quadrantOrigin;
}
/**
* Sets the quadrant origin and sends a {@link PlotChangeEvent} to all
* registered listeners.
*
* @param origin the origin ({@code null} not permitted).
*
* @see #getQuadrantOrigin()
*/
public void setQuadrantOrigin(Point2D origin) {
Args.nullNotPermitted(origin, "origin");
this.quadrantOrigin = origin;
fireChangeEvent();
}
/**
* Returns the paint used for the specified quadrant.
*
* @param index the quadrant index (0-3).
*
* @return The paint (possibly {@code null}).
*
* @see #setQuadrantPaint(int, Paint)
*/
public Paint getQuadrantPaint(int index) {
if (index < 0 || index > 3) {
throw new IllegalArgumentException("The index value (" + index
+ ") should be in the range 0 to 3.");
}
return this.quadrantPaint[index];
}
/**
* Sets the paint used for the specified quadrant and sends a
* {@link PlotChangeEvent} to all registered listeners.
*
* @param index the quadrant index (0-3).
* @param paint the paint ({@code null} permitted).
*
* @see #getQuadrantPaint(int)
*/
public void setQuadrantPaint(int index, Paint paint) {
if (index < 0 || index > 3) {
throw new IllegalArgumentException("The index value (" + index
+ ") should be in the range 0 to 3.");
}
this.quadrantPaint[index] = paint;
fireChangeEvent();
}
/**
* Adds a marker for the domain axis and sends a {@link PlotChangeEvent}
* to all registered listeners.
*
* Typically a marker will be drawn by the renderer as a line perpendicular
* to the domain axis, however this is entirely up to the renderer.
*
* @param marker the marker ({@code null} not permitted).
*
* @see #addDomainMarker(Marker, Layer)
* @see #clearDomainMarkers()
*/
public void addDomainMarker(Marker marker) {
// defer argument checking...
addDomainMarker(marker, Layer.FOREGROUND);
}
/**
* Adds a marker for the domain axis in the specified layer and sends a
* {@link PlotChangeEvent} to all registered listeners.
*
* Typically a marker will be drawn by the renderer as a line perpendicular
* to the domain axis, however this is entirely up to the renderer.
*
* @param marker the marker ({@code null} not permitted).
* @param layer the layer (foreground or background).
*
* @see #addDomainMarker(int, Marker, Layer)
*/
public void addDomainMarker(Marker marker, Layer layer) {
addDomainMarker(0, marker, layer);
}
/**
* Clears all the (foreground and background) domain markers and sends a
* {@link PlotChangeEvent} to all registered listeners.
*
* @see #addDomainMarker(int, Marker, Layer)
*/
public void clearDomainMarkers() {
if (this.backgroundDomainMarkers != null) {
Set
* Typically a marker will be drawn by the renderer as a line perpendicular
* to the domain axis (that the renderer is mapped to), however this is
* entirely up to the renderer.
*
* @param index the dataset/renderer index.
* @param marker the marker.
* @param layer the layer (foreground or background).
*
* @see #clearDomainMarkers(int)
* @see #addRangeMarker(int, Marker, Layer)
*/
public void addDomainMarker(int index, Marker marker, Layer layer) {
addDomainMarker(index, marker, layer, true);
}
/**
* Adds a marker for a specific dataset/renderer and, if requested, sends a
* {@link PlotChangeEvent} to all registered listeners.
*
* Typically a marker will be drawn by the renderer as a line perpendicular
* to the domain axis (that the renderer is mapped to), however this is
* entirely up to the renderer.
*
* @param index the dataset/renderer index.
* @param marker the marker.
* @param layer the layer (foreground or background).
* @param notify notify listeners?
*/
public void addDomainMarker(int index, Marker marker, Layer layer,
boolean notify) {
Args.nullNotPermitted(marker, "marker");
Args.nullNotPermitted(layer, "layer");
if (layer == Layer.FOREGROUND) {
List
* Typically a marker will be drawn by the renderer as a line perpendicular
* to the range axis, however this is entirely up to the renderer.
*
* @param marker the marker ({@code null} not permitted).
*
* @see #addRangeMarker(Marker, Layer)
*/
public void addRangeMarker(Marker marker) {
addRangeMarker(marker, Layer.FOREGROUND);
}
/**
* Adds a marker for the range axis in the specified layer and sends a
* {@link PlotChangeEvent} to all registered listeners.
*
* Typically a marker will be drawn by the renderer as a line perpendicular
* to the range axis, however this is entirely up to the renderer.
*
* @param marker the marker ({@code null} not permitted).
* @param layer the layer (foreground or background).
*
* @see #addRangeMarker(int, Marker, Layer)
*/
public void addRangeMarker(Marker marker, Layer layer) {
addRangeMarker(0, marker, layer);
}
/**
* Clears all the range markers and sends a {@link PlotChangeEvent} to all
* registered listeners.
*
* @see #clearRangeMarkers()
*/
public void clearRangeMarkers() {
if (this.backgroundRangeMarkers != null) {
Set
* Typically a marker will be drawn by the renderer as a line perpendicular
* to the range axis, however this is entirely up to the renderer.
*
* @param index the dataset/renderer index.
* @param marker the marker.
* @param layer the layer (foreground or background).
*
* @see #clearRangeMarkers(int)
* @see #addDomainMarker(int, Marker, Layer)
*/
public void addRangeMarker(int index, Marker marker, Layer layer) {
addRangeMarker(index, marker, layer, true);
}
/**
* Adds a marker for a specific dataset/renderer and, if requested, sends a
* {@link PlotChangeEvent} to all registered listeners.
*
* Typically a marker will be drawn by the renderer as a line perpendicular
* to the range axis, however this is entirely up to the renderer.
*
* @param index the dataset/renderer index.
* @param marker the marker.
* @param layer the layer (foreground or background).
* @param notify notify listeners?
*/
public void addRangeMarker(int index, Marker marker, Layer layer,
boolean notify) {
if (layer == Layer.FOREGROUND) {
List
* The {@code info} and {@code crosshairState} arguments may be
* {@code null}.
*
* @param g2 the graphics device.
* @param dataArea the region in which the data is to be drawn.
* @param index the dataset index.
* @param info an optional object for collection dimension information.
* @param crosshairState collects crosshair information
* ({@code null} permitted).
*
* @return A flag that indicates whether any data was actually rendered.
*/
public boolean render(Graphics2D g2, Rectangle2D dataArea, int index,
PlotRenderingInfo info, CrosshairState crosshairState) {
boolean foundData = false;
XYDataset
* The axis ranges are updated if necessary.
*
* @param event information about the event (not used here).
*/
@Override
public void datasetChanged(DatasetChangeEvent event) {
configureDomainAxes();
configureRangeAxes();
if (getParent() != null) {
getParent().datasetChanged(event);
}
else {
PlotChangeEvent e = new PlotChangeEvent(this);
e.setType(ChartChangeEventType.DATASET_UPDATED);
notifyListeners(e);
}
}
/**
* Receives notification of a renderer change event.
*
* @param event the event.
*/
@Override
public void rendererChanged(RendererChangeEvent event) {
// if the event was caused by a change to series visibility, then
// the axis ranges might need updating...
if (event.getSeriesVisibilityChanged()) {
configureDomainAxes();
configureRangeAxes();
}
fireChangeEvent();
}
/**
* Returns a flag indicating whether the domain crosshair is visible.
*
* @return The flag.
*
* @see #setDomainCrosshairVisible(boolean)
*/
public boolean isDomainCrosshairVisible() {
return this.domainCrosshairVisible;
}
/**
* Sets the flag indicating whether the domain crosshair is visible
* and, if the flag changes, sends a {@link PlotChangeEvent} to all
* registered listeners.
*
* @param flag the new value of the flag.
*
* @see #isDomainCrosshairVisible()
*/
public void setDomainCrosshairVisible(boolean flag) {
if (this.domainCrosshairVisible != flag) {
this.domainCrosshairVisible = flag;
fireChangeEvent();
}
}
/**
* Returns a flag indicating whether the crosshair should "lock-on"
* to actual data values.
*
* @return The flag.
*
* @see #setDomainCrosshairLockedOnData(boolean)
*/
public boolean isDomainCrosshairLockedOnData() {
return this.domainCrosshairLockedOnData;
}
/**
* Sets the flag indicating whether the domain crosshair should
* "lock-on" to actual data values. If the flag value changes, this
* method sends a {@link PlotChangeEvent} to all registered listeners.
*
* @param flag the flag.
*
* @see #isDomainCrosshairLockedOnData()
*/
public void setDomainCrosshairLockedOnData(boolean flag) {
if (this.domainCrosshairLockedOnData != flag) {
this.domainCrosshairLockedOnData = flag;
fireChangeEvent();
}
}
/**
* Returns the domain crosshair value.
*
* @return The value.
*
* @see #setDomainCrosshairValue(double)
*/
public double getDomainCrosshairValue() {
return this.domainCrosshairValue;
}
/**
* Sets the domain crosshair value and sends a {@link PlotChangeEvent} to
* all registered listeners (provided that the domain crosshair is visible).
*
* @param value the value.
*
* @see #getDomainCrosshairValue()
*/
public void setDomainCrosshairValue(double value) {
setDomainCrosshairValue(value, true);
}
/**
* Sets the domain crosshair value and, if requested, sends a
* {@link PlotChangeEvent} to all registered listeners (provided that the
* domain crosshair is visible).
*
* @param value the new value.
* @param notify notify listeners?
*
* @see #getDomainCrosshairValue()
*/
public void setDomainCrosshairValue(double value, boolean notify) {
this.domainCrosshairValue = value;
if (isDomainCrosshairVisible() && notify) {
fireChangeEvent();
}
}
/**
* Returns the {@link Stroke} used to draw the crosshair (if visible).
*
* @return The crosshair stroke (never {@code null}).
*
* @see #setDomainCrosshairStroke(Stroke)
* @see #isDomainCrosshairVisible()
* @see #getDomainCrosshairPaint()
*/
public Stroke getDomainCrosshairStroke() {
return this.domainCrosshairStroke;
}
/**
* Sets the Stroke used to draw the crosshairs (if visible) and notifies
* registered listeners that the axis has been modified.
*
* @param stroke the new crosshair stroke ({@code null} not permitted).
*
* @see #getDomainCrosshairStroke()
*/
public void setDomainCrosshairStroke(Stroke stroke) {
Args.nullNotPermitted(stroke, "stroke");
this.domainCrosshairStroke = stroke;
fireChangeEvent();
}
/**
* Returns the domain crosshair paint.
*
* @return The crosshair paint (never {@code null}).
*
* @see #setDomainCrosshairPaint(Paint)
* @see #isDomainCrosshairVisible()
* @see #getDomainCrosshairStroke()
*/
public Paint getDomainCrosshairPaint() {
return this.domainCrosshairPaint;
}
/**
* Sets the paint used to draw the crosshairs (if visible) and sends a
* {@link PlotChangeEvent} to all registered listeners.
*
* @param paint the new crosshair paint ({@code null} not permitted).
*
* @see #getDomainCrosshairPaint()
*/
public void setDomainCrosshairPaint(Paint paint) {
Args.nullNotPermitted(paint, "paint");
this.domainCrosshairPaint = paint;
fireChangeEvent();
}
/**
* Returns a flag indicating whether the range crosshair is visible.
*
* @return The flag.
*
* @see #setRangeCrosshairVisible(boolean)
* @see #isDomainCrosshairVisible()
*/
public boolean isRangeCrosshairVisible() {
return this.rangeCrosshairVisible;
}
/**
* Sets the flag indicating whether the range crosshair is visible.
* If the flag value changes, this method sends a {@link PlotChangeEvent}
* to all registered listeners.
*
* @param flag the new value of the flag.
*
* @see #isRangeCrosshairVisible()
*/
public void setRangeCrosshairVisible(boolean flag) {
if (this.rangeCrosshairVisible != flag) {
this.rangeCrosshairVisible = flag;
fireChangeEvent();
}
}
/**
* Returns a flag indicating whether the crosshair should "lock-on"
* to actual data values.
*
* @return The flag.
*
* @see #setRangeCrosshairLockedOnData(boolean)
*/
public boolean isRangeCrosshairLockedOnData() {
return this.rangeCrosshairLockedOnData;
}
/**
* Sets the flag indicating whether the range crosshair should
* "lock-on" to actual data values. If the flag value changes, this method
* sends a {@link PlotChangeEvent} to all registered listeners.
*
* @param flag the flag.
*
* @see #isRangeCrosshairLockedOnData()
*/
public void setRangeCrosshairLockedOnData(boolean flag) {
if (this.rangeCrosshairLockedOnData != flag) {
this.rangeCrosshairLockedOnData = flag;
fireChangeEvent();
}
}
/**
* Returns the range crosshair value.
*
* @return The value.
*
* @see #setRangeCrosshairValue(double)
*/
public double getRangeCrosshairValue() {
return this.rangeCrosshairValue;
}
/**
* Sets the range crosshair value.
*
* Registered listeners are notified that the plot has been modified, but
* only if the crosshair is visible.
*
* @param value the new value.
*
* @see #getRangeCrosshairValue()
*/
public void setRangeCrosshairValue(double value) {
setRangeCrosshairValue(value, true);
}
/**
* Sets the range crosshair value and sends a {@link PlotChangeEvent} to
* all registered listeners, but only if the crosshair is visible.
*
* @param value the new value.
* @param notify a flag that controls whether listeners are
* notified.
*
* @see #getRangeCrosshairValue()
*/
public void setRangeCrosshairValue(double value, boolean notify) {
this.rangeCrosshairValue = value;
if (isRangeCrosshairVisible() && notify) {
fireChangeEvent();
}
}
/**
* Returns the stroke used to draw the crosshair (if visible).
*
* @return The crosshair stroke (never {@code null}).
*
* @see #setRangeCrosshairStroke(Stroke)
* @see #isRangeCrosshairVisible()
* @see #getRangeCrosshairPaint()
*/
public Stroke getRangeCrosshairStroke() {
return this.rangeCrosshairStroke;
}
/**
* Sets the stroke used to draw the crosshairs (if visible) and sends a
* {@link PlotChangeEvent} to all registered listeners.
*
* @param stroke the new crosshair stroke ({@code null} not
* permitted).
*
* @see #getRangeCrosshairStroke()
*/
public void setRangeCrosshairStroke(Stroke stroke) {
Args.nullNotPermitted(stroke, "stroke");
this.rangeCrosshairStroke = stroke;
fireChangeEvent();
}
/**
* Returns the range crosshair paint.
*
* @return The crosshair paint (never {@code null}).
*
* @see #setRangeCrosshairPaint(Paint)
* @see #isRangeCrosshairVisible()
* @see #getRangeCrosshairStroke()
*/
public Paint getRangeCrosshairPaint() {
return this.rangeCrosshairPaint;
}
/**
* Sets the paint used to color the crosshairs (if visible) and sends a
* {@link PlotChangeEvent} to all registered listeners.
*
* @param paint the new crosshair paint ({@code null} not permitted).
*
* @see #getRangeCrosshairPaint()
*/
public void setRangeCrosshairPaint(Paint paint) {
Args.nullNotPermitted(paint, "paint");
this.rangeCrosshairPaint = paint;
fireChangeEvent();
}
/**
* Returns the fixed domain axis space.
*
* @return The fixed domain axis space (possibly {@code null}).
*
* @see #setFixedDomainAxisSpace(AxisSpace)
*/
public AxisSpace getFixedDomainAxisSpace() {
return this.fixedDomainAxisSpace;
}
/**
* Sets the fixed domain axis space and sends a {@link PlotChangeEvent} to
* all registered listeners.
*
* @param space the space ({@code null} permitted).
*
* @see #getFixedDomainAxisSpace()
*/
public void setFixedDomainAxisSpace(AxisSpace space) {
setFixedDomainAxisSpace(space, true);
}
/**
* Sets the fixed domain axis space and, if requested, sends a
* {@link PlotChangeEvent} to all registered listeners.
*
* @param space the space ({@code null} permitted).
* @param notify notify listeners?
*
* @see #getFixedDomainAxisSpace()
*/
public void setFixedDomainAxisSpace(AxisSpace space, boolean notify) {
this.fixedDomainAxisSpace = space;
if (notify) {
fireChangeEvent();
}
}
/**
* Returns the fixed range axis space.
*
* @return The fixed range axis space (possibly {@code null}).
*
* @see #setFixedRangeAxisSpace(AxisSpace)
*/
public AxisSpace getFixedRangeAxisSpace() {
return this.fixedRangeAxisSpace;
}
/**
* Sets the fixed range axis space and sends a {@link PlotChangeEvent} to
* all registered listeners.
*
* @param space the space ({@code null} permitted).
*
* @see #getFixedRangeAxisSpace()
*/
public void setFixedRangeAxisSpace(AxisSpace space) {
setFixedRangeAxisSpace(space, true);
}
/**
* Sets the fixed range axis space and, if requested, sends a
* {@link PlotChangeEvent} to all registered listeners.
*
* @param space the space ({@code null} permitted).
* @param notify notify listeners?
*
* @see #getFixedRangeAxisSpace()
*/
public void setFixedRangeAxisSpace(AxisSpace space, boolean notify) {
this.fixedRangeAxisSpace = space;
if (notify) {
fireChangeEvent();
}
}
/**
* Returns {@code true} if panning is enabled for the domain axes,
* and {@code false} otherwise.
*
* @return A boolean.
*/
@Override
public boolean isDomainPannable() {
return this.domainPannable;
}
/**
* Sets the flag that enables or disables panning of the plot along the
* domain axes.
*
* @param pannable the new flag value.
*/
public void setDomainPannable(boolean pannable) {
this.domainPannable = pannable;
}
/**
* Returns {@code true} if panning is enabled for the range axis/axes,
* and {@code false} otherwise. The default value is {@code false}.
*
* @return A boolean.
*/
@Override
public boolean isRangePannable() {
return this.rangePannable;
}
/**
* Sets the flag that enables or disables panning of the plot along
* the range axis/axes.
*
* @param pannable the new flag value.
*/
public void setRangePannable(boolean pannable) {
this.rangePannable = pannable;
}
/**
* Pans the domain axes by the specified percentage.
*
* @param percent the distance to pan (as a percentage of the axis length).
* @param info the plot info
* @param source the source point where the pan action started.
*/
@Override
public void panDomainAxes(double percent, PlotRenderingInfo info,
Point2D source) {
if (!isDomainPannable()) {
return;
}
int domainAxisCount = getDomainAxisCount();
for (int i = 0; i < domainAxisCount; i++) {
ValueAxis axis = getDomainAxis(i);
if (axis == null) {
continue;
}
axis.pan(axis.isInverted() ? -percent : percent);
}
}
/**
* Pans the range axes by the specified percentage.
*
* @param percent the distance to pan (as a percentage of the axis length).
* @param info the plot info
* @param source the source point where the pan action started.
*/
@Override
public void panRangeAxes(double percent, PlotRenderingInfo info,
Point2D source) {
if (!isRangePannable()) {
return;
}
int rangeAxisCount = getRangeAxisCount();
for (int i = 0; i < rangeAxisCount; i++) {
ValueAxis axis = getRangeAxis(i);
if (axis == null) {
continue;
}
axis.pan(axis.isInverted() ? -percent : percent);
}
}
/**
* Multiplies the range on the domain axis/axes by the specified factor.
*
* @param factor the zoom factor.
* @param info the plot rendering info.
* @param source the source point (in Java2D space).
*
* @see #zoomRangeAxes(double, PlotRenderingInfo, Point2D)
*/
@Override
public void zoomDomainAxes(double factor, PlotRenderingInfo info,
Point2D source) {
// delegate to other method
zoomDomainAxes(factor, info, source, false);
}
/**
* Multiplies the range on the domain axis/axes by the specified factor.
*
* @param factor the zoom factor.
* @param info the plot rendering info.
* @param source the source point (in Java2D space).
* @param useAnchor use source point as zoom anchor?
*
* @see #zoomRangeAxes(double, PlotRenderingInfo, Point2D, boolean)
*/
@Override
public void zoomDomainAxes(double factor, PlotRenderingInfo info,
Point2D source, boolean useAnchor) {
// perform the zoom on each domain axis
for (ValueAxis xAxis : this.domainAxes.values()) {
if (xAxis == null) {
continue;
}
if (useAnchor) {
// get the relevant source coordinate given the plot orientation
double sourceX = source.getX();
if (this.orientation == PlotOrientation.HORIZONTAL) {
sourceX = source.getY();
}
double anchorX = xAxis.java2DToValue(sourceX,
info.getDataArea(), getDomainAxisEdge());
xAxis.resizeRange2(factor, anchorX);
} else {
xAxis.resizeRange(factor);
}
}
}
/**
* Zooms in on the domain axis/axes. The new lower and upper bounds are
* specified as percentages of the current axis range, where 0 percent is
* the current lower bound and 100 percent is the current upper bound.
*
* @param lowerPercent a percentage that determines the new lower bound
* for the axis (e.g. 0.20 is twenty percent).
* @param upperPercent a percentage that determines the new upper bound
* for the axis (e.g. 0.80 is eighty percent).
* @param info the plot rendering info.
* @param source the source point (ignored).
*
* @see #zoomRangeAxes(double, double, PlotRenderingInfo, Point2D)
*/
@Override
public void zoomDomainAxes(double lowerPercent, double upperPercent,
PlotRenderingInfo info, Point2D source) {
for (ValueAxis xAxis : this.domainAxes.values()) {
if (xAxis != null) {
xAxis.zoomRange(lowerPercent, upperPercent);
}
}
}
/**
* Multiplies the range on the range axis/axes by the specified factor.
*
* @param factor the zoom factor.
* @param info the plot rendering info.
* @param source the source point.
*
* @see #zoomDomainAxes(double, PlotRenderingInfo, Point2D, boolean)
*/
@Override
public void zoomRangeAxes(double factor, PlotRenderingInfo info,
Point2D source) {
// delegate to other method
zoomRangeAxes(factor, info, source, false);
}
/**
* Multiplies the range on the range axis/axes by the specified factor.
*
* @param factor the zoom factor.
* @param info the plot rendering info.
* @param source the source point.
* @param useAnchor a flag that controls whether the source point
* is used for the zoom anchor.
*
* @see #zoomDomainAxes(double, PlotRenderingInfo, Point2D, boolean)
*/
@Override
public void zoomRangeAxes(double factor, PlotRenderingInfo info,
Point2D source, boolean useAnchor) {
// perform the zoom on each range axis
for (ValueAxis yAxis : this.rangeAxes.values()) {
if (yAxis == null) {
continue;
}
if (useAnchor) {
// get the relevant source coordinate given the plot orientation
double sourceY = source.getY();
if (this.orientation == PlotOrientation.HORIZONTAL) {
sourceY = source.getX();
}
double anchorY = yAxis.java2DToValue(sourceY,
info.getDataArea(), getRangeAxisEdge());
yAxis.resizeRange2(factor, anchorY);
} else {
yAxis.resizeRange(factor);
}
}
}
/**
* Zooms in on the range axes.
*
* @param lowerPercent the lower bound.
* @param upperPercent the upper bound.
* @param info the plot rendering info.
* @param source the source point.
*
* @see #zoomDomainAxes(double, double, PlotRenderingInfo, Point2D)
*/
@Override
public void zoomRangeAxes(double lowerPercent, double upperPercent,
PlotRenderingInfo info, Point2D source) {
for (ValueAxis yAxis : this.rangeAxes.values()) {
if (yAxis != null) {
yAxis.zoomRange(lowerPercent, upperPercent);
}
}
}
/**
* Returns {@code true}, indicating that the domain axis/axes for this
* plot are zoomable.
*
* @return A boolean.
*
* @see #isRangeZoomable()
*/
@Override
public boolean isDomainZoomable() {
return true;
}
/**
* Returns {@code true}, indicating that the range axis/axes for this
* plot are zoomable.
*
* @return A boolean.
*
* @see #isDomainZoomable()
*/
@Override
public boolean isRangeZoomable() {
return true;
}
/**
* Returns the number of series in the primary dataset for this plot. If
* the dataset is {@code null}, the method returns 0.
*
* @return The series count.
*/
public int getSeriesCount() {
int result = 0;
XYDatasetThe type for the series keys.
*/
public class XYPlot> extends Plot
implements ValueAxisPlot, Pannable, Zoomable,
RendererChangeListener, Cloneable, PublicCloneable, Serializable {
/** For serialization. */
private static final long serialVersionUID = 7044148245716569264L;
/** The default grid line stroke. */
public static final Stroke DEFAULT_GRIDLINE_STROKE = new BasicStroke(0.5f,
BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, 0.0f,
new float[] {2.0f, 2.0f}, 0.0f);
/** The default grid line paint. */
public static final Paint DEFAULT_GRIDLINE_PAINT = Color.LIGHT_GRAY;
/** The default crosshair visibility. */
public static final boolean DEFAULT_CROSSHAIR_VISIBLE = false;
/** The default crosshair stroke. */
public static final Stroke DEFAULT_CROSSHAIR_STROKE
= DEFAULT_GRIDLINE_STROKE;
/** The default crosshair paint. */
public static final Paint DEFAULT_CROSSHAIR_PAINT = Color.BLUE;
/** The resourceBundle for the localization. */
protected static ResourceBundle localizationResources
= ResourceBundle.getBundle("org.jfree.chart.plot.LocalizationBundle");
/** The plot orientation. */
private PlotOrientation orientation;
/** The offset between the data area and the axes. */
private RectangleInsets axisOffset;
/** The domain axis / axes (used for the x-values). */
private Map dataset, ValueAxis domainAxis, ValueAxis rangeAxis,
XYItemRenderer renderer) {
super();
this.orientation = PlotOrientation.VERTICAL;
this.weight = 1; // only relevant when this is a subplot
this.axisOffset = RectangleInsets.ZERO_INSETS;
// allocate storage for datasets, axes and renderers (all optional)
this.domainAxes = new HashMap<>();
this.domainAxisLocations = new HashMap<>();
this.foregroundDomainMarkers = new HashMap<>();
this.backgroundDomainMarkers = new HashMap<>();
this.rangeAxes = new HashMap<>();
this.rangeAxisLocations = new HashMap<>();
this.foregroundRangeMarkers = new HashMap<>();
this.backgroundRangeMarkers = new HashMap<>();
this.datasets = new HashMap<>();
this.renderers = new HashMap<>();
this.datasetToDomainAxesMap = new TreeMap<>();
this.datasetToRangeAxesMap = new TreeMap<>();
this.annotations = new ArrayList<>();
if (dataset != null) {
dataset.addChangeListener(this);
this.datasets.put(0, dataset);
}
if (renderer != null) {
renderer.setPlot(this);
renderer.addChangeListener(this);
this.renderers.put(0, renderer);
}
if (domainAxis != null) {
domainAxis.setPlot(this);
domainAxis.addChangeListener(this);
this.domainAxes.put(0, domainAxis);
mapDatasetToDomainAxis(0, 0);
}
this.domainAxisLocations.put(0, AxisLocation.BOTTOM_OR_LEFT);
if (rangeAxis != null) {
rangeAxis.setPlot(this);
rangeAxis.addChangeListener(this);
this.rangeAxes.put(0, rangeAxis);
mapDatasetToRangeAxis(0, 0);
}
this.rangeAxisLocations.put(0, AxisLocation.BOTTOM_OR_LEFT);
configureDomainAxes();
configureRangeAxes();
this.domainGridlinesVisible = true;
this.domainGridlineStroke = DEFAULT_GRIDLINE_STROKE;
this.domainGridlinePaint = DEFAULT_GRIDLINE_PAINT;
this.domainMinorGridlinesVisible = false;
this.domainMinorGridlineStroke = DEFAULT_GRIDLINE_STROKE;
this.domainMinorGridlinePaint = Color.WHITE;
this.domainZeroBaselineVisible = false;
this.domainZeroBaselinePaint = Color.BLACK;
this.domainZeroBaselineStroke = new BasicStroke(0.5f);
this.rangeGridlinesVisible = true;
this.rangeGridlineStroke = DEFAULT_GRIDLINE_STROKE;
this.rangeGridlinePaint = DEFAULT_GRIDLINE_PAINT;
this.rangeMinorGridlinesVisible = false;
this.rangeMinorGridlineStroke = DEFAULT_GRIDLINE_STROKE;
this.rangeMinorGridlinePaint = Color.WHITE;
this.rangeZeroBaselineVisible = false;
this.rangeZeroBaselinePaint = Color.BLACK;
this.rangeZeroBaselineStroke = new BasicStroke(0.5f);
this.domainCrosshairVisible = false;
this.domainCrosshairValue = 0.0;
this.domainCrosshairStroke = DEFAULT_CROSSHAIR_STROKE;
this.domainCrosshairPaint = DEFAULT_CROSSHAIR_PAINT;
this.rangeCrosshairVisible = false;
this.rangeCrosshairValue = 0.0;
this.rangeCrosshairStroke = DEFAULT_CROSSHAIR_STROKE;
this.rangeCrosshairPaint = DEFAULT_CROSSHAIR_PAINT;
this.shadowGenerator = null;
}
/**
* Returns the plot type as a string.
*
* @return A short string describing the type of plot.
*/
@Override
public String getPlotType() {
return localizationResources.getString("XY_Plot");
}
/**
* Returns the orientation of the plot.
*
* @return The orientation (never {@code null}).
*
* @see #setOrientation(PlotOrientation)
*/
@Override
public PlotOrientation getOrientation() {
return this.orientation;
}
/**
* Sets the orientation for the plot and sends a {@link PlotChangeEvent} to
* all registered listeners.
*
* @param orientation the orientation ({@code null} not allowed).
*
* @see #getOrientation()
*/
public void setOrientation(PlotOrientation orientation) {
Args.nullNotPermitted(orientation, "orientation");
if (orientation != this.orientation) {
this.orientation = orientation;
fireChangeEvent();
}
}
/**
* Returns the axis offset.
*
* @return The axis offset (never {@code null}).
*
* @see #setAxisOffset(RectangleInsets)
*/
public RectangleInsets getAxisOffset() {
return this.axisOffset;
}
/**
* Sets the axis offsets (gap between the data area and the axes) and sends
* a {@link PlotChangeEvent} to all registered listeners.
*
* @param offset the offset ({@code null} not permitted).
*
* @see #getAxisOffset()
*/
public void setAxisOffset(RectangleInsets offset) {
Args.nullNotPermitted(offset, "offset");
this.axisOffset = offset;
fireChangeEvent();
}
/**
* Returns the domain axis with index 0. If the domain axis for this plot
* is {@code null}, then the method will return the parent plot's
* domain axis (if there is a parent plot).
*
* @return The domain axis (possibly {@code null}).
*
* @see #getDomainAxis(int)
* @see #setDomainAxis(ValueAxis)
*/
public ValueAxis getDomainAxis() {
return getDomainAxis(0);
}
/**
* Returns the domain axis with the specified index, or {@code null} if
* there is no axis with that index.
*
* @param index the axis index.
*
* @return The axis ({@code null} possible).
*
* @see #setDomainAxis(int, ValueAxis)
*/
public ValueAxis getDomainAxis(int index) {
ValueAxis result = this.domainAxes.get(index);
if (result == null) {
Plot parent = getParent();
if (parent instanceof XYPlot) {
@SuppressWarnings("unchecked")
XYPlot xy = (XYPlot) parent;
result = xy.getDomainAxis(index);
}
}
return result;
}
/**
* Returns a map containing the domain axes that are assigned to this plot.
* The map is unmodifiable.
*
* @return A map containing the domain axes that are assigned to the plot
* (never {@code null}).
*
* @since 1.5.4
*/
public Map xy = (XYPlot) parent;
result = xy.getRangeAxis(index);
}
}
return result;
}
/**
* Returns a map containing the range axes that are assigned to this plot.
* The map is unmodifiable.
*
* @return A map containing the range axes that are assigned to the plot
* (never {@code null}).
*
* @since 1.5.4
*/
public Map getDataset() {
return getDataset(0);
}
/**
* Returns the dataset with the specified index, or {@code null} if there
* is no dataset with that index.
*
* @param index the dataset index (must be >= 0).
*
* @return The dataset (possibly {@code null}).
*
* @see #setDataset(int, XYDataset)
*/
public XYDataset getDataset(int index) {
return this.datasets.get(index);
}
/**
* Returns a map containing the datasets that are assigned to this plot.
* The map is unmodifiable.
*
* @return A map containing the datasets that are assigned to the plot
* (never {@code null}).
*
* @since 1.5.4
*/
public Map dataset) {
setDataset(0, dataset);
}
/**
* Sets a dataset for the plot and sends a change event to all registered
* listeners.
*
* @param index the dataset index (must be >= 0).
* @param dataset the dataset ({@code null} permitted).
*
* @see #getDataset(int)
*/
public void setDataset(int index, XYDataset dataset) {
XYDataset existing = getDataset(index);
if (existing != null) {
existing.removeChangeListener(this);
}
this.datasets.put(index, dataset);
if (dataset != null) {
dataset.addChangeListener(this);
}
// send a dataset change event to self...
DatasetChangeEvent event = new DatasetChangeEvent(this, dataset);
datasetChanged(event);
}
/**
* Returns the number of datasets.
*
* @return The number of datasets.
*/
public int getDatasetCount() {
return this.datasets.size();
}
/**
* Returns the index of the specified dataset, or {@code -1} if the
* dataset does not belong to the plot.
*
* @param dataset the dataset ({@code null} not permitted).
*
* @return The index or -1.
*/
public int indexOf(XYDataset dataset) {
for (Map.Entry dataset) {
int datasetIndex = indexOf(dataset);
if (datasetIndex < 0) {
return null;
}
XYItemRenderer result = this.renderers.get(datasetIndex);
if (result == null) {
result = getRenderer();
}
return result;
}
/**
* Returns the weight for this plot when it is used as a subplot within a
* combined plot.
*
* @return The weight.
*
* @see #setWeight(int)
*/
public int getWeight() {
return this.weight;
}
/**
* Sets the weight for the plot and sends a {@link PlotChangeEvent} to all
* registered listeners.
*
* @param weight the weight.
*
* @see #getWeight()
*/
public void setWeight(int weight) {
this.weight = weight;
fireChangeEvent();
}
/**
* Returns {@code true} if the domain gridlines are visible, and
* {@code false} otherwise.
*
* @return {@code true} or {@code false}.
*
* @see #setDomainGridlinesVisible(boolean)
*/
public boolean isDomainGridlinesVisible() {
return this.domainGridlinesVisible;
}
/**
* Sets the flag that controls whether the domain grid-lines are
* visible.
* dataset: this.datasets.values()) {
int datasetIndex = indexOf(dataset);
drawDomainMarkers(g2, dataArea, datasetIndex, Layer.BACKGROUND);
}
for (XYDataset dataset: this.datasets.values()) {
int datasetIndex = indexOf(dataset);
drawRangeMarkers(g2, dataArea, datasetIndex, Layer.BACKGROUND);
}
// now draw annotations and render data items...
boolean foundData = false;
DatasetRenderingOrder order = getDatasetRenderingOrder();
List dataset = getDataset(index);
if (!DatasetUtils.isEmptyOrNull(dataset)) {
foundData = true;
ValueAxis xAxis = getDomainAxisForDataset(index);
ValueAxis yAxis = getRangeAxisForDataset(index);
if (xAxis == null || yAxis == null) {
return foundData; // can't render anything without axes
}
XYItemRenderer renderer = getRenderer(index);
if (renderer == null) {
renderer = getRenderer();
if (renderer == null) { // no default renderer available
return foundData;
}
}
XYItemRendererState state = renderer.initialise(g2, dataArea, this,
dataset, info);
int passCount = renderer.getPassCount();
SeriesRenderingOrder seriesOrder = getSeriesRenderingOrder();
if (seriesOrder == SeriesRenderingOrder.REVERSE) {
//render series in reverse order
for (int pass = 0; pass < passCount; pass++) {
int seriesCount = dataset.getSeriesCount();
for (int series = seriesCount - 1; series >= 0; series--) {
int firstItem = 0;
int lastItem = dataset.getItemCount(series) - 1;
if (lastItem == -1) {
continue;
}
if (state.getProcessVisibleItemsOnly()) {
int[] itemBounds = RendererUtils.findLiveItems(
dataset, series, xAxis.getLowerBound(),
xAxis.getUpperBound());
firstItem = Math.max(itemBounds[0] - 1, 0);
lastItem = Math.min(itemBounds[1] + 1, lastItem);
}
state.startSeriesPass(dataset, series, firstItem,
lastItem, pass, passCount);
for (int item = firstItem; item <= lastItem; item++) {
renderer.drawItem(g2, state, dataArea, info,
this, xAxis, yAxis, dataset, series, item,
crosshairState, pass);
}
state.endSeriesPass(dataset, series, firstItem,
lastItem, pass, passCount);
}
}
}
else {
//render series in forward order
for (int pass = 0; pass < passCount; pass++) {
int seriesCount = dataset.getSeriesCount();
for (int series = 0; series < seriesCount; series++) {
int firstItem = 0;
int lastItem = dataset.getItemCount(series) - 1;
if (state.getProcessVisibleItemsOnly()) {
int[] itemBounds = RendererUtils.findLiveItems(
dataset, series, xAxis.getLowerBound(),
xAxis.getUpperBound());
firstItem = Math.max(itemBounds[0] - 1, 0);
lastItem = Math.min(itemBounds[1] + 1, lastItem);
}
state.startSeriesPass(dataset, series, firstItem,
lastItem, pass, passCount);
for (int item = firstItem; item <= lastItem; item++) {
renderer.drawItem(g2, state, dataArea, info,
this, xAxis, yAxis, dataset, series, item,
crosshairState, pass);
}
state.endSeriesPass(dataset, series, firstItem,
lastItem, pass, passCount);
}
}
}
}
return foundData;
}
/**
* Returns the domain axis for a dataset.
*
* @param index the dataset index (must be >= 0).
*
* @return The axis.
*/
public ValueAxis getDomainAxisForDataset(int index) {
Args.requireNonNegative(index, "index");
ValueAxis valueAxis;
List p = (XYPlot) parent;
result = p.getDomainAxisIndex(axis);
}
}
return result;
}
private int findDomainAxisIndex(ValueAxis axis) {
for (Map.Entry p = (XYPlot) parent;
result = p.getRangeAxisIndex(axis);
}
}
return result;
}
private int findRangeAxisIndex(ValueAxis axis) {
for (Map.Entry d : mappedDatasets) {
if (d != null) {
XYItemRenderer r = getRendererForDataset(d);
if (isDomainAxis) {
if (r != null) {
result = Range.combine(result, r.findDomainBounds(d));
}
else {
result = Range.combine(result,
DatasetUtils.findDomainBounds(d));
}
}
else {
if (r != null) {
result = Range.combine(result, r.findRangeBounds(d));
}
else {
result = Range.combine(result,
DatasetUtils.findRangeBounds(d));
}
}
if (r != null) {
for (XYAnnotation annotation : r.getAnnotations()) {
if (annotation instanceof XYAnnotationBoundsInfo) {
includedAnnotations.add(annotation);
}
}
}
}
}
for (XYAnnotation includedAnnotation : includedAnnotations) {
XYAnnotationBoundsInfo xyabi = (XYAnnotationBoundsInfo) includedAnnotation;
if (xyabi.getIncludeInDataBounds()) {
if (isDomainAxis) {
result = Range.combine(result, xyabi.getXRange());
}
else {
result = Range.combine(result, xyabi.getYRange());
}
}
}
return result;
}
/**
* Receives notification of a change to an {@link Annotation} added to
* this plot.
*
* @param event information about the event (not used here).
*/
@Override
public void annotationChanged(AnnotationChangeEvent event) {
if (getParent() != null) {
getParent().annotationChanged(event);
}
else {
PlotChangeEvent e = new PlotChangeEvent(this);
notifyListeners(e);
}
}
/**
* Receives notification of a change to the plot's dataset.
* dataset = getDataset();
if (dataset != null) {
result = dataset.getSeriesCount();
}
return result;
}
/**
* Returns the fixed legend items, if any.
*
* @return The legend items (possibly {@code null}).
*
* @see #setFixedLegendItems(LegendItemCollection)
*/
public LegendItemCollection getFixedLegendItems() {
return this.fixedLegendItems;
}
/**
* Sets the fixed legend items for the plot. Leave this set to
* {@code null} if you prefer the legend items to be created
* automatically.
*
* @param items the legend items ({@code null} permitted).
*
* @see #getFixedLegendItems()
*/
public void setFixedLegendItems(LegendItemCollection items) {
this.fixedLegendItems = items;
fireChangeEvent();
}
/**
* Returns the legend items for the plot. Each legend item is generated by
* the plot's renderer, since the renderer is responsible for the visual
* representation of the data.
*
* @return The legend items.
*/
@Override
public LegendItemCollection getLegendItems() {
if (this.fixedLegendItems != null) {
return this.fixedLegendItems;
}
LegendItemCollection result = new LegendItemCollection();
for (XYDataset dataset : this.datasets.values()) {
if (dataset == null) {
continue;
}
int datasetIndex = indexOf(dataset);
XYItemRenderer renderer = getRenderer(datasetIndex);
if (renderer == null) {
renderer = getRenderer(0);
}
if (renderer != null) {
int seriesCount = dataset.getSeriesCount();
for (int i = 0; i < seriesCount; i++) {
if (renderer.isSeriesVisible(i)
&& renderer.isSeriesVisibleInLegend(i)) {
LegendItem item = renderer.getLegendItem(
datasetIndex, i);
if (item != null) {
result.add(item);
}
}
}
}
}
return result;
}
/**
* Tests this plot for equality with another object.
*
* @param obj the object ({@code null} permitted).
*
* @return {@code true} or {@code false}.
*/
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof XYPlot)) {
return false;
}
@SuppressWarnings("unchecked")
XYPlot that = (XYPlot) obj;
if (this.weight != that.weight) {
return false;
}
if (this.orientation != that.orientation) {
return false;
}
if (!this.domainAxes.equals(that.domainAxes)) {
return false;
}
if (!this.domainAxisLocations.equals(that.domainAxisLocations)) {
return false;
}
if (this.rangeCrosshairLockedOnData
!= that.rangeCrosshairLockedOnData) {
return false;
}
if (this.domainGridlinesVisible != that.domainGridlinesVisible) {
return false;
}
if (this.rangeGridlinesVisible != that.rangeGridlinesVisible) {
return false;
}
if (this.domainMinorGridlinesVisible
!= that.domainMinorGridlinesVisible) {
return false;
}
if (this.rangeMinorGridlinesVisible
!= that.rangeMinorGridlinesVisible) {
return false;
}
if (this.domainZeroBaselineVisible != that.domainZeroBaselineVisible) {
return false;
}
if (this.rangeZeroBaselineVisible != that.rangeZeroBaselineVisible) {
return false;
}
if (this.domainCrosshairVisible != that.domainCrosshairVisible) {
return false;
}
if (this.domainCrosshairValue != that.domainCrosshairValue) {
return false;
}
if (this.domainCrosshairLockedOnData
!= that.domainCrosshairLockedOnData) {
return false;
}
if (this.rangeCrosshairVisible != that.rangeCrosshairVisible) {
return false;
}
if (this.rangeCrosshairValue != that.rangeCrosshairValue) {
return false;
}
if (!Objects.equals(this.axisOffset, that.axisOffset)) {
return false;
}
if (!Objects.equals(this.renderers, that.renderers)) {
return false;
}
if (!Objects.equals(this.rangeAxes, that.rangeAxes)) {
return false;
}
if (!this.rangeAxisLocations.equals(that.rangeAxisLocations)) {
return false;
}
if (!Objects.equals(this.datasetToDomainAxesMap, that.datasetToDomainAxesMap)) {
return false;
}
if (!Objects.equals(this.datasetToRangeAxesMap, that.datasetToRangeAxesMap)) {
return false;
}
if (!Objects.equals(this.domainGridlineStroke, that.domainGridlineStroke)) {
return false;
}
if (!PaintUtils.equal(this.domainGridlinePaint,
that.domainGridlinePaint)) {
return false;
}
if (!Objects.equals(this.rangeGridlineStroke, that.rangeGridlineStroke)) {
return false;
}
if (!PaintUtils.equal(this.rangeGridlinePaint,
that.rangeGridlinePaint)) {
return false;
}
if (!Objects.equals(this.domainMinorGridlineStroke, that.domainMinorGridlineStroke)) {
return false;
}
if (!PaintUtils.equal(this.domainMinorGridlinePaint,
that.domainMinorGridlinePaint)) {
return false;
}
if (!Objects.equals(this.rangeMinorGridlineStroke, that.rangeMinorGridlineStroke)) {
return false;
}
if (!PaintUtils.equal(this.rangeMinorGridlinePaint,
that.rangeMinorGridlinePaint)) {
return false;
}
if (!PaintUtils.equal(this.domainZeroBaselinePaint,
that.domainZeroBaselinePaint)) {
return false;
}
if (!Objects.equals(this.domainZeroBaselineStroke, that.domainZeroBaselineStroke)) {
return false;
}
if (!PaintUtils.equal(this.rangeZeroBaselinePaint,
that.rangeZeroBaselinePaint)) {
return false;
}
if (!Objects.equals(this.rangeZeroBaselineStroke, that.rangeZeroBaselineStroke)) {
return false;
}
if (!Objects.equals(this.domainCrosshairStroke, that.domainCrosshairStroke)) {
return false;
}
if (!PaintUtils.equal(this.domainCrosshairPaint,
that.domainCrosshairPaint)) {
return false;
}
if (!Objects.equals(this.rangeCrosshairStroke, that.rangeCrosshairStroke)) {
return false;
}
if (!PaintUtils.equal(this.rangeCrosshairPaint,
that.rangeCrosshairPaint)) {
return false;
}
if (!Objects.equals(this.foregroundDomainMarkers, that.foregroundDomainMarkers)) {
return false;
}
if (!Objects.equals(this.backgroundDomainMarkers, that.backgroundDomainMarkers)) {
return false;
}
if (!Objects.equals(this.foregroundRangeMarkers, that.foregroundRangeMarkers)) {
return false;
}
if (!Objects.equals(this.backgroundRangeMarkers, that.backgroundRangeMarkers)) {
return false;
}
if (!Objects.equals(this.foregroundDomainMarkers, that.foregroundDomainMarkers)) {
return false;
}
if (!Objects.equals(this.backgroundDomainMarkers, that.backgroundDomainMarkers)) {
return false;
}
if (!Objects.equals(this.foregroundRangeMarkers, that.foregroundRangeMarkers)) {
return false;
}
if (!Objects.equals(this.backgroundRangeMarkers, that.backgroundRangeMarkers)) {
return false;
}
if (!Objects.equals(this.annotations, that.annotations)) {
return false;
}
if (!Objects.equals(this.fixedLegendItems, that.fixedLegendItems)) {
return false;
}
if (!PaintUtils.equal(this.domainTickBandPaint,
that.domainTickBandPaint)) {
return false;
}
if (!PaintUtils.equal(this.rangeTickBandPaint,
that.rangeTickBandPaint)) {
return false;
}
if (!this.quadrantOrigin.equals(that.quadrantOrigin)) {
return false;
}
for (int i = 0; i < 4; i++) {
if (!PaintUtils.equal(this.quadrantPaint[i],
that.quadrantPaint[i])) {
return false;
}
}
if (!Objects.equals(this.shadowGenerator, that.shadowGenerator)) {
return false;
}
return super.equals(obj);
}
@Override
public int hashCode()
{
int hash = 7;
hash = 43 * hash + Objects.hashCode(this.orientation);
hash = 43 * hash + Objects.hashCode(this.axisOffset);
hash = 43 * hash + Objects.hashCode(this.domainAxes);
hash = 43 * hash + Objects.hashCode(this.domainAxisLocations);
hash = 43 * hash + Objects.hashCode(this.rangeAxes);
hash = 43 * hash + Objects.hashCode(this.rangeAxisLocations);
hash = 43 * hash + Objects.hashCode(this.renderers);
hash = 43 * hash + Objects.hashCode(this.datasetToDomainAxesMap);
hash = 43 * hash + Objects.hashCode(this.datasetToRangeAxesMap);
hash = 43 * hash + Objects.hashCode(this.quadrantOrigin);
hash = 43 * hash + Arrays.deepHashCode(this.quadrantPaint);
hash = 43 * hash + (this.domainGridlinesVisible ? 1 : 0);
hash = 43 * hash + Objects.hashCode(this.domainGridlineStroke);
hash = 43 * hash + Objects.hashCode(this.domainGridlinePaint);
hash = 43 * hash + (this.rangeGridlinesVisible ? 1 : 0);
hash = 43 * hash + Objects.hashCode(this.rangeGridlineStroke);
hash = 43 * hash + Objects.hashCode(this.rangeGridlinePaint);
hash = 43 * hash + (this.domainMinorGridlinesVisible ? 1 : 0);
hash = 43 * hash + Objects.hashCode(this.domainMinorGridlineStroke);
hash = 43 * hash + Objects.hashCode(this.domainMinorGridlinePaint);
hash = 43 * hash + (this.rangeMinorGridlinesVisible ? 1 : 0);
hash = 43 * hash + Objects.hashCode(this.rangeMinorGridlineStroke);
hash = 43 * hash + Objects.hashCode(this.rangeMinorGridlinePaint);
hash = 43 * hash + (this.domainZeroBaselineVisible ? 1 : 0);
hash = 43 * hash + Objects.hashCode(this.domainZeroBaselineStroke);
hash = 43 * hash + Objects.hashCode(this.domainZeroBaselinePaint);
hash = 43 * hash + (this.rangeZeroBaselineVisible ? 1 : 0);
hash = 43 * hash + Objects.hashCode(this.rangeZeroBaselineStroke);
hash = 43 * hash + Objects.hashCode(this.rangeZeroBaselinePaint);
hash = 43 * hash + (this.domainCrosshairVisible ? 1 : 0);
hash = 43 * hash + Long.hashCode(Double.doubleToLongBits(this.domainCrosshairValue));
hash = 43 * hash + Objects.hashCode(this.domainCrosshairStroke);
hash = 43 * hash + Objects.hashCode(this.domainCrosshairPaint);
hash = 43 * hash + (this.domainCrosshairLockedOnData ? 1 : 0);
hash = 43 * hash + (this.rangeCrosshairVisible ? 1 : 0);
hash = 43 * hash + Long.hashCode(Double.doubleToLongBits(this.rangeCrosshairValue));
hash = 43 * hash + Objects.hashCode(this.rangeCrosshairStroke);
hash = 43 * hash + Objects.hashCode(this.rangeCrosshairPaint);
hash = 43 * hash + (this.rangeCrosshairLockedOnData ? 1 : 0);
hash = 43 * hash + Objects.hashCode(this.foregroundDomainMarkers);
hash = 43 * hash + Objects.hashCode(this.backgroundDomainMarkers);
hash = 43 * hash + Objects.hashCode(this.foregroundRangeMarkers);
hash = 43 * hash + Objects.hashCode(this.backgroundRangeMarkers);
hash = 43 * hash + Objects.hashCode(this.annotations);
hash = 43 * hash + Objects.hashCode(this.domainTickBandPaint);
hash = 43 * hash + Objects.hashCode(this.rangeTickBandPaint);
hash = 43 * hash + this.weight;
hash = 43 * hash + Objects.hashCode(this.fixedLegendItems);
hash = 43 * hash + Objects.hashCode(this.shadowGenerator);
return hash;
}
/**
* Returns a clone of the plot.
*
* @return A clone.
*
* @throws CloneNotSupportedException this can occur if some component of
* the plot cannot be cloned.
*/
@Override
public Object clone() throws CloneNotSupportedException {
@SuppressWarnings("unchecked")
XYPlot clone = (XYPlot) super.clone();
clone.domainAxes = CloneUtils.cloneMapValues(this.domainAxes);
for (ValueAxis axis : clone.domainAxes.values()) {
if (axis != null) {
axis.setPlot(clone);
axis.addChangeListener(clone);
}
}
clone.rangeAxes = CloneUtils.cloneMapValues(this.rangeAxes);
for (ValueAxis axis : clone.rangeAxes.values()) {
if (axis != null) {
axis.setPlot(clone);
axis.addChangeListener(clone);
}
}
clone.domainAxisLocations = new HashMap<>(this.domainAxisLocations);
clone.rangeAxisLocations = new HashMap<>(this.rangeAxisLocations);
// the datasets are not cloned, but listeners need to be added...
clone.datasets = new HashMap<>(this.datasets);
for (XYDataset dataset : clone.datasets.values()) {
if (dataset != null) {
dataset.addChangeListener(clone);
}
}
clone.datasetToDomainAxesMap = new TreeMap<>();
clone.datasetToDomainAxesMap.putAll(this.datasetToDomainAxesMap);
clone.datasetToRangeAxesMap = new TreeMap<>();
clone.datasetToRangeAxesMap.putAll(this.datasetToRangeAxesMap);
clone.renderers = CloneUtils.cloneMapValues(this.renderers);
for (XYItemRenderer renderer : clone.renderers.values()) {
if (renderer != null) {
renderer.setPlot(clone);
renderer.addChangeListener(clone);
}
}
clone.foregroundDomainMarkers = CloneUtils.clone(
this.foregroundDomainMarkers);
clone.backgroundDomainMarkers = CloneUtils.clone(
this.backgroundDomainMarkers);
clone.foregroundRangeMarkers = CloneUtils.clone(
this.foregroundRangeMarkers);
clone.backgroundRangeMarkers = CloneUtils.clone(
this.backgroundRangeMarkers);
clone.annotations = CloneUtils.cloneList(this.annotations);
if (this.fixedDomainAxisSpace != null) {
clone.fixedDomainAxisSpace = CloneUtils.clone(
this.fixedDomainAxisSpace);
}
if (this.fixedRangeAxisSpace != null) {
clone.fixedRangeAxisSpace = CloneUtils.clone(
this.fixedRangeAxisSpace);
}
if (this.fixedLegendItems != null) {
clone.fixedLegendItems
= (LegendItemCollection) this.fixedLegendItems.clone();
}
clone.quadrantOrigin = CloneUtils.clone(this.quadrantOrigin);
clone.quadrantPaint = this.quadrantPaint.clone();
return clone;
}
/**
* Provides serialization support.
*
* @param stream the output stream.
*
* @throws IOException if there is an I/O error.
*/
private void writeObject(ObjectOutputStream stream) throws IOException {
stream.defaultWriteObject();
SerialUtils.writeStroke(this.domainGridlineStroke, stream);
SerialUtils.writePaint(this.domainGridlinePaint, stream);
SerialUtils.writeStroke(this.rangeGridlineStroke, stream);
SerialUtils.writePaint(this.rangeGridlinePaint, stream);
SerialUtils.writeStroke(this.domainMinorGridlineStroke, stream);
SerialUtils.writePaint(this.domainMinorGridlinePaint, stream);
SerialUtils.writeStroke(this.rangeMinorGridlineStroke, stream);
SerialUtils.writePaint(this.rangeMinorGridlinePaint, stream);
SerialUtils.writeStroke(this.rangeZeroBaselineStroke, stream);
SerialUtils.writePaint(this.rangeZeroBaselinePaint, stream);
SerialUtils.writeStroke(this.domainCrosshairStroke, stream);
SerialUtils.writePaint(this.domainCrosshairPaint, stream);
SerialUtils.writeStroke(this.rangeCrosshairStroke, stream);
SerialUtils.writePaint(this.rangeCrosshairPaint, stream);
SerialUtils.writePaint(this.domainTickBandPaint, stream);
SerialUtils.writePaint(this.rangeTickBandPaint, stream);
SerialUtils.writePoint2D(this.quadrantOrigin, stream);
for (int i = 0; i < 4; i++) {
SerialUtils.writePaint(this.quadrantPaint[i], stream);
}
SerialUtils.writeStroke(this.domainZeroBaselineStroke, stream);
SerialUtils.writePaint(this.domainZeroBaselinePaint, stream);
}
/**
* Provides serialization support.
*
* @param stream the input stream.
*
* @throws IOException if there is an I/O error.
* @throws ClassNotFoundException if there is a classpath problem.
*/
private void readObject(ObjectInputStream stream)
throws IOException, ClassNotFoundException {
stream.defaultReadObject();
this.domainGridlineStroke = SerialUtils.readStroke(stream);
this.domainGridlinePaint = SerialUtils.readPaint(stream);
this.rangeGridlineStroke = SerialUtils.readStroke(stream);
this.rangeGridlinePaint = SerialUtils.readPaint(stream);
this.domainMinorGridlineStroke = SerialUtils.readStroke(stream);
this.domainMinorGridlinePaint = SerialUtils.readPaint(stream);
this.rangeMinorGridlineStroke = SerialUtils.readStroke(stream);
this.rangeMinorGridlinePaint = SerialUtils.readPaint(stream);
this.rangeZeroBaselineStroke = SerialUtils.readStroke(stream);
this.rangeZeroBaselinePaint = SerialUtils.readPaint(stream);
this.domainCrosshairStroke = SerialUtils.readStroke(stream);
this.domainCrosshairPaint = SerialUtils.readPaint(stream);
this.rangeCrosshairStroke = SerialUtils.readStroke(stream);
this.rangeCrosshairPaint = SerialUtils.readPaint(stream);
this.domainTickBandPaint = SerialUtils.readPaint(stream);
this.rangeTickBandPaint = SerialUtils.readPaint(stream);
this.quadrantOrigin = SerialUtils.readPoint2D(stream);
this.quadrantPaint = new Paint[4];
for (int i = 0; i < 4; i++) {
this.quadrantPaint[i] = SerialUtils.readPaint(stream);
}
this.domainZeroBaselineStroke = SerialUtils.readStroke(stream);
this.domainZeroBaselinePaint = SerialUtils.readPaint(stream);
// register the plot as a listener with its axes, datasets, and
// renderers...
for (ValueAxis axis : this.domainAxes.values()) {
if (axis != null) {
axis.setPlot(this);
axis.addChangeListener(this);
}
}
for (ValueAxis axis : this.rangeAxes.values()) {
if (axis != null) {
axis.setPlot(this);
axis.addChangeListener(this);
}
}
for (XYDataset dataset : this.datasets.values()) {
if (dataset != null) {
dataset.addChangeListener(this);
}
}
for (XYItemRenderer renderer : this.renderers.values()) {
if (renderer != null) {
renderer.addChangeListener(this);
}
}
}
}