JSci.swing.JGraph2D Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jsci Show documentation
Show all versions of jsci Show documentation
JSci is a set of open source Java packages. The aim is to encapsulate scientific methods/principles in the most natural way possible. As such they should greatly aid the development of scientific based software.
It offers: abstract math interfaces, linear algebra (support for various matrix and vector types), statistics (including probability distributions), wavelets, newtonian mechanics, chart/graph components (AWT and Swing), MathML DOM implementation, ...
Note: some packages, like javax.comm, for the astro and instruments package aren't listed as dependencies (not available).
The newest version!
package JSci.swing;
import java.awt.*;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.ParseException;
import JSci.awt.*;import JSci.maths.ExtraMath;
/**
* The JGraph2D superclass provides an abstract encapsulation of 2D graphs.
* There is some support for the handling of NaN values.
* @version 1.8
* @author Mark Hale
*/
public abstract class JGraph2D extends JDoubleBufferedComponent implements GraphDataListener {
public final static int LINEAR_SCALE = 0;
public final static int LOG_SCALE = 1;
/**
* Data model.
*/
protected Graph2DModel model;
/**
* Origin.
*/
protected Point origin = new Point();
protected Graph2D.DataMarker dataMarker = Graph2D.DataMarker.NONE;
/**
* Series colors.
*/
protected Color seriesColor[]={Color.black,Color.blue,Color.green,Color.red,Color.yellow,Color.cyan,Color.lightGray,Color.magenta,Color.orange,Color.pink};
/**
* Axis numbering.
*/
protected boolean xNumbering = true, yNumbering = true;
protected NumberFormat xNumberFormat = new DecimalFormat("##0.0");
protected NumberFormat yNumberFormat = new DecimalFormat("##0.0");
protected boolean xAxisLine = true, yAxisLine = true;
protected boolean gridLines = false;
private final Color gridLineColor = Color.lightGray;
/**
* Axis scaling.
*/
private float xScale,yScale;
/**
* Axis scaling type.
*/
private int xScaleType, yScaleType;
/**
* Axis extrema.
*/
private float minX, minY, maxX, maxY;
private float scaledMinX, scaledMinY, scaledMaxX, scaledMaxY;
private boolean autoXExtrema=true, autoYExtrema=true;
private float xGrowth, yGrowth;
/**
* Axis numbering increment.
*/
private final float xIncPixels = 40.0f;
private final float yIncPixels = 40.0f;
private float xInc,yInc;
private boolean autoXInc=true,autoYInc=true;
/**
* Padding.
*/
protected final int scalePad=5;
protected final int axisPad=25;
protected int leftAxisPad;
/**
* Constructs a 2D graph.
*/
public JGraph2D(Graph2DModel gm) {
model=gm;
model.addGraphDataListener(this);
dataChanged(new GraphDataEvent(model));
}
/**
* Sets the data plotted by this graph to the specified data.
*/
public final void setModel(Graph2DModel gm) {
model.removeGraphDataListener(this);
model=gm;
model.addGraphDataListener(this);
dataChanged(new GraphDataEvent(model));
}
/**
* Returns the model used by this graph.
*/
public final Graph2DModel getModel() {
return model;
}
/**
* Implementation of GraphDataListener.
* Supports {@link JSci.awt.GraphDataEvent#isIncremental() incremental} updates.
* Application code will not use this method explicitly, it is used internally.
*/
public void dataChanged(GraphDataEvent e) {
if(e.isIncremental()) {
Graphics g = getOffscreenGraphics();
if(g == null)
return;
final int series = e.getSeries();
if(series == GraphDataEvent.ALL_SERIES) {
model.firstSeries();
int n = 0;
do {
final int i = model.seriesLength() - 1;
incrementalRescale(model.getXCoord(i), model.getYCoord(i));
g.setColor(seriesColor[n]);
drawDataPoint(g, i);
n++;
} while(model.nextSeries());
} else {
model.firstSeries();
int n=0;
for(; nseriesColor.length) {
Color tmp[]=seriesColor;
seriesColor=new Color[n];
System.arraycopy(tmp,0,seriesColor,0,tmp.length);
for(int i=tmp.length; i maxX)
max = autoXExtrema ? Math.max(x, maxX+xGrowth) : maxX+xGrowth;
else
max = maxX;
rescaleX(min, max);
if(y < minY)
min = autoYExtrema ? Math.min(y, minY-yGrowth) : minY-yGrowth;
else
min = minY;
if(y > maxY)
max = autoYExtrema ? Math.max(y, maxY+yGrowth) : maxY+yGrowth;
else
max = maxY;
rescaleY(min, max);
}
/**
* Turns axis numbering on/off.
* Default is on.
*/
public final void setNumbering(boolean flag) {
setNumbering(flag, flag);
}
public final void setNumbering(boolean xFlag, boolean yFlag) {
xNumbering = xFlag;
yNumbering = yFlag;
leftAxisPad = axisPad;
if(yNumbering && getFont() != null) {
// adjust leftAxisPad to accomodate y-axis numbering
final FontMetrics metrics = getFontMetrics(getFont());
final int maxYNumLen = metrics.stringWidth(yNumberFormat.format(maxY));
final int minYNumLen = metrics.stringWidth(yNumberFormat.format(minY));
int yNumPad = Math.max(minYNumLen, maxYNumLen);
if(scaledMinX<0.0f) {
final int negXLen = (int)((Math.max(getSize().width,getMinimumSize().width)-2*(axisPad+scalePad))*scaledMinX/(scaledMinX-scaledMaxX));
yNumPad = Math.max(yNumPad-negXLen, 0);
}
leftAxisPad += yNumPad;
}
rescale();
}
public void addNotify() {
super.addNotify();
// getFont() is now not null
// recalculate padding
setNumbering(xNumbering, yNumbering);
}
/**
* Sets the display format used for axis numbering.
* Convenience method.
* @see #setXNumberFormat(NumberFormat)
* @see #setYNumberFormat(NumberFormat)
*/
public final void setNumberFormat(NumberFormat format) {
xNumberFormat = format;
yNumberFormat = format;
setNumbering(xNumbering, yNumbering);
}
/**
* Sets the display format used for x-axis numbering.
*/
public final void setXNumberFormat(NumberFormat format) {
xNumberFormat = format;
setNumbering(xNumbering, yNumbering);
}
/**
* Sets the display format used for y-axis numbering.
*/
public final void setYNumberFormat(NumberFormat format) {
yNumberFormat = format;
setNumbering(xNumbering, yNumbering);
}
/**
* Turns the axis lines on/off.
*/
public final void setAxisLines(boolean xFlag, boolean yFlag) {
xAxisLine = xFlag;
yAxisLine = yFlag;
redraw();
}
/**
* Turns grid lines on/off.
* Default is off.
*/
public final void setGridLines(boolean flag) {
gridLines = flag;
redraw();
}
/**
* Sets the x-axis scale type.
* @param t a _SCALE constant.
*/
public final void setXScale(int t) {
if(xScaleType != t) {
xScaleType = t;
dataChanged(new GraphDataEvent(model));
}
}
/**
* Sets the y-axis scale type.
* @param t a _SCALE constant.
*/
public final void setYScale(int t) {
if(yScaleType != t) {
yScaleType = t;
dataChanged(new GraphDataEvent(model));
}
}
/**
* Sets the x-axis numbering increment.
* @param dx use 0.0f for auto-adjusting (default).
*/
public final void setXIncrement(float dx) {
if(dx < 0.0f) {
throw new IllegalArgumentException("Increment should be positive.");
} else if(dx == 0.0f) {
if(!autoXInc) {
autoXInc = true;
rescale();
}
} else {
autoXInc = false;
if(dx != xInc) {
xInc = dx;
rescale();
}
}
}
/**
* Returns the x-axis numbering increment.
*/
public final float getXIncrement() {
return xInc;
}
/**
* Sets the y-axis numbering increment.
* @param dy use 0.0f for auto-adjusting (default).
*/
public final void setYIncrement(float dy) {
if(dy < 0.0f) {
throw new IllegalArgumentException("Increment should be positive.");
} else if(dy == 0.0f) {
if(!autoYInc) {
autoYInc = true;
rescale();
}
} else {
autoYInc = false;
if(dy != yInc) {
yInc = dy;
rescale();
}
}
}
/**
* Returns the y-axis numbering increment.
*/
public final float getYIncrement() {
return yInc;
}
/**
* Sets the minimum/maximum values on the x-axis.
* Set both min and max to 0.0f for auto-adjusting (default).
*/
public final void setXExtrema(float min, float max) {
if(min==0.0f && max==0.0f) {
autoXExtrema=true;
// determine min and max from model
min=Float.POSITIVE_INFINITY;
max=Float.NEGATIVE_INFINITY;
float tmp;
model.firstSeries();
do {
for(int i=0;i