JSci.awt.Histogram.vm 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 ${package};
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;
#if(!($api == "AWT"))import JSci.awt.*;
#end
import JSci.maths.ExtraMath;
/**
* A histogram ${api} component.
* The y-values are the counts for each bin.
* Each bin is specified by an interval.
* So that y[i] contains the counts for the bin from x[i-1] to x[i].
* The value of y[0] is disregarded.
* @version 1.0
* @author Mark Hale
*/
public class ${className} extends ${extendsClassName} implements GraphDataListener {
/**
* Data model.
*/
protected Graph2DModel model;
/**
* Origin.
*/
protected Point origin = new Point();
/**
* Series colors.
*/
protected Color seriesColor[]={Color.blue,Color.green,Color.red,Color.yellow,Color.cyan,Color.lightGray,Color.magenta,Color.orange,Color.pink};
/**
* Axis numbering.
*/
protected boolean numbering = true;
protected NumberFormat xNumberFormat = new DecimalFormat("${numberFormat}");
protected NumberFormat yNumberFormat = new DecimalFormat("${numberFormat}");
protected boolean gridLines = false;
private final Color gridLineColor = Color.lightGray;
/**
* Axis scaling.
*/
private float xScale,yScale;
/**
* Axis extrema.
*/
private float minX, minY, maxX, maxY;
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 histogram.
*/
public ${className}(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.
* 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) {
numbering=flag;
leftAxisPad=axisPad;
if(numbering && 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(minX<0.0f) {
final int negXLen = (int)((Math.max(getSize().width,getMinimumSize().width)-2*(axisPad+scalePad))*minX/(minX-maxX));
yNumPad = Math.max(yNumPad-negXLen, 0);
}
leftAxisPad += yNumPad;
}
rescale();
}
public void addNotify() {
super.addNotify();
// getFont() is now not null
// recalculate padding
setNumbering(numbering);
}
/**
* 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(numbering);
}
/**
* Sets the display format used for x-axis numbering.
*/
public final void setXNumberFormat(NumberFormat format) {
xNumberFormat = format;
setNumbering(numbering);
}
/**
* Sets the display format used for y-axis numbering.
*/
public final void setYNumberFormat(NumberFormat format) {
yNumberFormat = format;
setNumbering(numbering);
}
/**
* Turns grid lines on/off.
* Default is off.
*/
public final void setGridLines(boolean flag) {
gridLines = flag;
redraw();
}
/**
* 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 0.0f;
if(autoYInc) {
yInc = (float) ExtraMath.round((double)yIncPixels/(double)yScale, 1);
if(yInc == 0.0f)
yInc = Float.MIN_VALUE;
}
//assert yInc > 0.0f;
origin.x=leftAxisPad-Math.round(minX*xScale);
origin.y=thisHeight-axisPad+Math.round(minY*yScale);
redraw();
}
/**
* Converts a data point to screen coordinates.
*/
protected final Point dataToScreen(float x,float y) {
return new Point(origin.x+Math.round(xScale*x), origin.y-Math.round(yScale*y));
}
/**
* Converts a screen point to data coordinates.
*/
protected final Point2D.Float screenToData(Point p) {
double x = (double)(p.x-origin.x) / (double)xScale;
double y = (double)(origin.y-p.y) / (double)yScale;
return new Point2D.Float((float)x, (float)y);
}
/**
* Draws the graph axes.
*/
protected final void drawAxes(Graphics g) {
#if($api == "Swing")
// Swing optimised
final int width = getWidth();
final int height = getHeight();
#else
final Dimension size = getSize();
final int width = size.width;
final int height = size.height;
#end
g.setColor(getForeground());
// grid lines and numbering
if(gridLines || numbering) {
// x-axis numbering and vertical grid lines
float xAxisY;
if(minY > 0.0f) {
xAxisY = minY;
} else if(maxY <= 0.0f) {
xAxisY = maxY;
} else {
xAxisY = 0.0f;
}
for(double x=(minX>0.0f)?minX:xInc; x<=maxX; x+=xInc) {
Point p=dataToScreen((float)x, xAxisY);
if(gridLines) {
g.setColor(gridLineColor);
g.drawLine(p.x, axisPad-scalePad, p.x, height-(axisPad-scalePad));
g.setColor(getForeground());
}
if(numbering) {
drawXLabel(g, x, p);
}
}
for(double x=-xInc; x>=minX; x-=xInc) {
Point p=dataToScreen((float)x, xAxisY);
if(gridLines) {
g.setColor(gridLineColor);
g.drawLine(p.x, axisPad-scalePad, p.x, height-(axisPad-scalePad));
g.setColor(getForeground());
}
if(numbering) {
drawXLabel(g, x, p);
}
}
// y-axis numbering and horizontal grid lines
float yAxisX;
if(minX > 0.0f)
yAxisX = minX;
else if(maxX < 0.0f)
yAxisX = maxX;
else
yAxisX = 0.0f;
for(double y=(minY>0.0f)?minY:yInc; y<=maxY; y+=yInc) {
Point p=dataToScreen(yAxisX, (float)y);
if(gridLines) {
g.setColor(gridLineColor);
g.drawLine(leftAxisPad-scalePad, p.y, width-(axisPad-scalePad), p.y);
g.setColor(getForeground());
}
if(numbering) {
drawYLabel(g, y, p);
}
}
for(double y=-yInc; y>=minY; y-=yInc) {
Point p=dataToScreen(yAxisX, (float)y);
if(gridLines) {
g.setColor(gridLineColor);
g.drawLine(leftAxisPad-scalePad, p.y, width-(axisPad-scalePad), p.y);
g.setColor(getForeground());
}
if(numbering) {
drawYLabel(g, y, p);
}
}
}
// axis lines
// horizontal axis
if(minY > 0.0f) {
// draw at bottom
g.drawLine(leftAxisPad-scalePad, height-axisPad, width-(axisPad-scalePad), height-axisPad);
} else if(maxY < 0.0f) {
// draw at top
g.drawLine(leftAxisPad-scalePad, axisPad, width-(axisPad-scalePad), axisPad);
} else {
// draw through y origin
g.drawLine(leftAxisPad-scalePad, origin.y, width-(axisPad-scalePad), origin.y);
}
// vertical axis
if(minX > 0.0f) {
// draw at left
g.drawLine(leftAxisPad, axisPad-scalePad, leftAxisPad, height-(axisPad-scalePad));
} else if(maxX < 0.0f) {
// draw at right
g.drawLine(width-axisPad, axisPad-scalePad, width-axisPad, height-(axisPad-scalePad));
} else {
// draw through x origin
g.drawLine(origin.x, axisPad-scalePad, origin.x, height-(axisPad-scalePad));
}
}
protected void drawXLabel(Graphics g, double x, Point p) {
String str = xNumberFormat.format(x);
FontMetrics metrics=g.getFontMetrics();
int strWidth=metrics.stringWidth(str);
int strHeight=metrics.getHeight();
boolean numberingAbove = (maxY <= 0.0f);
if(numberingAbove) {
g.drawLine(p.x,p.y,p.x,p.y-5);
g.drawString(str,p.x-strWidth/2,p.y-7);
} else {
g.drawLine(p.x,p.y,p.x,p.y+5);
g.drawString(str,p.x-strWidth/2,p.y+5+strHeight);
}
}
protected void drawYLabel(Graphics g, double y, Point p) {
String str = yNumberFormat.format(y);
FontMetrics metrics=g.getFontMetrics();
int strWidth=metrics.stringWidth(str);
int strHeight=metrics.getHeight();
g.drawLine(p.x,p.y,p.x-5,p.y);
g.drawString(str,p.x-8-strWidth,p.y+strHeight/3);
}
/**
* Draws the graph data.
* Override this method to change how the graph data is plotted.
*/
protected void drawData(Graphics g) {
// bars
model.firstSeries();
for(int i=1; i