To define a new function that can be displayed on a plot in Java Analysis Studio you must define a class that extends one of the following classes:
In addition your class must implement jas.hist.HasHandles if you want the user to be able to manipulate the function by dragging handles in the histogram window. Your class must implement the jas.hist.FunctionAdvancedOptions interface if you wish to have an advanced options dialog box available. This dialog is suitable if your function has options that the user could not otherwise control. For example, the order of the polynomial function is set by default to 2, but that can be changed in the advanced dialog for jas.hist.test.PolynomoialFunction to any other valid integer.
[Extending jas.hist.Basic1DFunction][Extending jas.hist.Fittable1DFunction][Implementing jas.hist.HasHandles][Implementing jas.hist.FunctionAdvancedOptions]
You will need to define a series of parameters that define your function. For example, the class jas.hist.test.PolynomialFunction has the following instance variables:
protected double[] p; // coefficients
protected int order;
There are two constructors in most classes.
public GaussianFunction(double xmin, double xmax, double ymin, double ymax)
{
max = ymin + (ymax - ymin) * 0.8;
mean = (xmin + xmax) / 2.0;
sigma = (xmax - xmin) / 6.0;
}
The curve's amplitude will be 80% of the region's height, the mean will be exactly
in the middle, and standard deviation will be appropriate to the region's boundaries.PolynomialFunction(double[] coefficients)
{
order = coefficients.length - 1;
p = coefficients;
}GaussianFunction(double amplitude, double mean, double sigma)
{
this.max = amplitude;
this.mean = mean;
this.sigma = sigma;
}
public double valueAt(double x) throws FunctionValueUndefined
This method simply returns f(x). Omit the
throwsclause if the function is defined for all values of x.
public String[] getParameterNames()
This method returns names of all the parameters. The class jas.hist.test.PolynomialFunction returns the array {"A", "B", "C", ...}, and the class jas.hist.test.StraightLineFunction simply returns {"slope", "yoffset"}.
public double[] getParameterValues()
Be sure to return the parameters in the same order as you returned their names in the above method.
public void setParameter(int index, double value) throws InvalidFunctionParameter
Note that indexes begin with zero. Once the parameters have been changed, clearFit() should be called if the curve is fittable to indicate that the parameters no longer reflect a fit curve, and setChanged() chould be called to indicate that the curve has changed. In the class jas.hist.test.GaussianFunction, the code is:
public void setParameter(int index, double value) throws InvalidFunctionParameter
{
if (index == 0) max = value;
else if (index == 1) mean = value;
else if (index == 2) sigma = value;
else throw new IllegalArgumentException("Invalid index to setParameter()");
clearFit(); /* the function is no longer considered
* to have been fit (use only for
* fittable functions that extend
* jas.hist.Fittable1DFunction
*/
setChanged(); /* update the image on the screen
* and indicate that the function
* has changed
*/
}
public String getTitle()
Return a suitable descriptor. For example, the class jas.hist.test.PolynomialFunction has:
return "Polynomial (order "+ order +")";
Follow the procedure for extending jas.hist.Basic1DFunction, but overwrite the following additional methods:
public double valueAt(double x, double[] param) throws FunctionValueUndefined
This method returns the value at the function defined with the parameters specified. For example, the class jas.hist.test.GaussianFunction has the following implementation:
Where a[0] is the amplitude, a[1] is the mean, and a[2] is the standard deviation.
public double valueAt(double x, double[] a)
{
return a[0] * Math.exp( -Math.pow( (x - a[1]) / a[2], 2 ) / 2.0 );
}
abstract public void setFit(Fitter fit, double[] param) throws
InvalidFunctionParameter
This method sets the parameters according to a fit. This method must invoke the setFit(fit) method to set the fitter, plus the setChanged() method. In jas.hist.test.PolynomialFunction, the implementation is:
public void setFit(Fitter fit, double[] value) throws InvalidFunctionParameter
{
if (value.length != p.length)
throw new IllegalArgumentException
("Argument to set parameters is of wrong length");
p = value; /* adopt new coefficients */
setFit(fit);
setChanged(); /* indicate that the curve has changed */
}
The following method must be implemented:
public abstract Handle[] getHandles(double xlow, double xhigh, double ylow,
double yhigh)
The parameters (xlow, xhigh, ...) hold the bounds to the on-screen plot. They can be used in assigning positions to the handles. In the method getHandles(), create and return an array of handles that will be used to alter the curve. jas.hist.Handle is an abstract class with three abstract methods that you must implement:
public double getX()
public double getY()
These methods return the location of the handle. You may wish to use the method's parameters (xlow, xhigh, ...) in assigning locations to parameters.
protected void moveTo(double x, double y)
This method is called when the handle has been moved. Use the given x and y values to modify the parameters of the function.
Here is the annotated implementation of getHandles() from jas.hist.test.GaussianFunction:
public Handle[] getHandles(double xLow, double xHigh, double yLow, double yHigh)/* there will be 3 handles */
{
Handle[] result = new Handle[3];
/* an anonymous class */
result[0] = new Handle()
/* this handle is at the mean of
the distribution */
{
/* when this handle has been moved to the
x and y
public void moveTo(double x, double y)
* values supplied as parameters, the parameters
* of the Gaussian function are modified accordingly.
*//* the function
is no longer considered to have been fit */
{
mean = x;
max = y;
clearFit();
/*
register that the function has been changed */
setChanged(); /* This handle is at the
left of the mean
}
public double getX()
{
return mean;
}
public double getY()
{
return max;
}
};
result[1] = new Handle()
{
* at half of the
curve's amplitude */ /* This handle is at the right
of the mean
public void moveTo(double x, double y)
{
sigma = (mean - x) /
fwhm;
clearFit();
setChanged();
}
public double getY()
{
return max / 2.0;
}
public double getX()
{
return mean -
sigma*fwhm;
}
};
result[2] = new Handle()
{
* at
half of the curve's amplitude */
public void moveTo(double x, double y)
{
sigma = (x - mean) /
fwhm;
clearFit();
setChanged();
}
public double getY()
{
return max / 2.0;
}
public double getX()
{
return mean +
sigma*fwhm;
}
};
return result;
}
You will want to implement this interface if your function has
specific options which the user cannot change any other way. The interface
jas.hist.FunctionAdvancedOptions contains only one method:
public void openAdvancedDialog(Frame f, JASHist hist)
This method is called when the user clicks on the 'Advanced Options'
button or selects 'Advanced Options' from one of the menus. It passes as an argument
a reference to the java.awt.Frame object that you should use as the parent frame for the
dialog box. It also receives a reference to the current plot. In many cases, you
will not need this.
In most cases, your method implementation will create a new instance of
a private internal class. For example, the order of the polynomial functions can be
changed from its default (2) in the dialog generated by the class
jas.hist.test.PolynomialFunction$PolynomialFunctionAdvancedDialog, and the functions to
include in a sum of functions can be set in the dialog from the class
jas.hist.test.SumOfFunctions$SumOfFunctionsAdvancedDialog. The implementation of
this method in jas.hist.test.SumOfFunctions$SumOfFunctionsFunctionAdvancedDialog is:
public void openAdvancedDialog(Frame f, JASHist hist)
{
new SumOfFunctionsAdvancedDialog(f);
}
Page maintained by Jonas Gifford. Last updated 01/14/04.