//===================================================================== // File: SegregatingScore.java // Class: SegregatingScore // Package: AFLPcore // // Author: James J. Benham // Date: August 10, 1998 // Contact: james_benham@hmc.edu // // Genographer v1.0 - Computer assisted scoring of gels. // Copyright (C) 1998 Montana State University // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; version 2 // of the License. // // This program 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 General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // // The GNU General Public License is distributed in the file GPL //===================================================================== package AFLPcore; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; /** * This scores each bin by assigning different labels to the differnet * cutoff regions. A cutoff region is a region between two cutoffs, or * between the cutoff and the zero level. For example, in a bin with * one cutoff, lanes that have a peak above the cutoff might be labeled "A", * and those below "B". For a bin with two cutoffs, those below both may * be "B", those between the two would be "h", and those above both would * be "A". The options can be used to set the number of levels and the * labels. If the number of cutoff levels for a lane does not match the * number expected by this function, an error will be thrown. Also, those * peaks that are above a cutoff are marked, and are then used to * calculate the mean and standard deviation of the values in the bin. * It also will count the number of each label that occur in a bin. * * @see Cutoff * @see Lane * * @author James J. Benham * @version 1.0.0 * @date August 10, 1998 */ public class SegregatingScore extends ScoreFunction { String[] labels; int numLevels; /** * Creates a new segregating score function. The default number of * levels is one. */ public SegregatingScore() { name = "Segregating"; descript = "Score a segregating population with labels like A and B."; helpFile = "segregating.html"; // Assume we start with just one cutoff numLevels = 1; labels = new String[numLevels + 1]; labels[0] = "A"; labels[1] = "B"; } /** * Scores a lane by seeing if any of the peaks cross the highest cutoff, * and then labeling it appropriately. It then sees if anything crosses * the next cutoff, and so on. * * @param cutoff the cutoff used to determine the labels * @param peaks the peaks in a region to compare to the cutoff * * @exception ScoringFailure occurs if the number of levels in the * cutoff do not match the number of levels that the function is * expecting. This number can be changed by setting the options for * this function. * * @see SegregatingScore#getOptions */ public String score(Cutoff cutoff, DataList peaks) { // check to see that we have the correct number of cutoffs if(cutoff.getNumLevels() != numLevels) throw new ScoringFailure("Number of cutoff levels does not match " + "expected value of " + numLevels); Peak pk; // Go through all of the levels for(int i=0; i < numLevels; i++) { // Look for a peak above the level for(int j=0; j < peaks.size(); j++) { pk = (Peak) peaks.dataAt(j); // compare peak height to the cutoff at the peak location if(pk.getHeight() >= cutoff.getCutoff(pk.getLocation(), numLevels - 1 -i)) { // we found a peak, so mark it and set the label pk.setMarkedState(true); return labels[i]; } } } // we didn't find a peak above any of the cutoffs, so return the last // label return labels[numLevels]; } /** * This returns a set of strings that describes the overall scoring of * the bin. It includes the mean of all of the peaks with non-zero * confidences as well as the standard deviation of those peaks. It * tells how many peaks were used to calculate the standard deviation * as well as how many peaks were defined ("used/defined"). It also * returns a count for each of the different types of labels. For example: * *
Mean: 98.38 StdDev: 0.06 #A: 20 #B: 14 from 20/20 peaks
*
* @param tags the label for each lane.
* @param peaks the peaks that were marked by the score method.
*
* @return a string with the information described above.
*/
public String[] getInfo(String[] tags, DataList peaks)
{
String info[] = new String[1];
int count[] = new int[numLevels + 1];
for(int i=0; i < count.length; i++)
count[i] = 0;
// get the counts for each label
for(int i=0; i < tags.length; i++)
{
for(int j=0; j < (numLevels + 1); j++)
if(tags[i].equals(labels[j]))
count[j]++;
}
// find the mean of the peaks
Peak pk;
double sum = 0;
int numUsed = 0;
for(int i=0; i < peaks.size(); i++)
{
pk = (Peak) peaks.dataAt(i);
if(pk.getConfidence() != 0)
{
sum += pk.getLocation();
numUsed++;
}
}
double mean = Math.round(sum/numUsed*100)/100.0;
// find the standard deviation using the formula
// sqrt( sum((mean-peak(i))^2)/(n-1) ), where n is the number of elements.
sum = 0;
double squareValue;
for(int i=0; i < peaks.size(); i++)
{
pk = (Peak) peaks.dataAt(i);
if(pk.getConfidence() != 0)
{
squareValue = mean - pk.getLocation();
sum += squareValue * squareValue;
}
}
double stdDev = Math.round(Math.sqrt(sum/(numUsed - 1))*100)/100.0;
// ==================== assemble the string ===================
info[0] = "Mean: " + mean + " StdDev: " + stdDev;
// add the counts
for(int i=0; i < (numLevels + 1); i++)
info[0] += " #" + labels[i] + ": " + count[i];
// give the number of data points
info[0] += " from " + numUsed + "/" + peaks.size() + " peaks";
return info;
}
/**
* Gives the labels that the scoring function can assign. Only one
* label will be assigned per lane, but this method will return all of
* the possiblities.
*/
public String[] getChoices(int numLevels)
{
return labels;
}
/**
* Gives the options for this scoring. The first option determines
* the number of levels the function should handle, and the other options
* will contain the string for the label of each section. Note that
* if the nubmer of levels is increased, it will be difficult to
* add more fields without setting the options and then getting them
* again. The value that the first option should actually contain is
* the number of labels, which is simply 1 plus the number of levels.
*
* @return a list of options.
*/
public Option[] getOptions()
{
options = new Option[numLevels + 2];
options[0] = new Option("Number of Fields", Option.NUMBER, false, 0);
for(int i = 1; i <= (numLevels + 1); i++)
{
options[i] = new Option("Label " + i, Option.STRING, false, "");
}
return options;
}
/**
* Sets the option to the specified values. The first option should be
* the number of labels, which is simply one more than the number of
* levels. The following options should contain the label for each level.
* If a level is not set, it will have a label of "_" or "?". "_" occurs
* if an option is provided but not set. "?" is the result of more labels
* then options specified.
*
* @param opts the options as described above.
*
* @exception IllegalArgumentException if the number of options does not
* match 1 plus the number of labels. This means that changing the
* number of levels and the labels will require several calls to this
* method.
*/
public void setOptions(Option[] opts)
{
if(opts.length != (numLevels + 2))
throw new IllegalArgumentException("Invalid options for Segregating " +
"Score method. " + (numLevels + 2)
+ " options expected, but " +
opts.length + " were provieded.");
// get the number of levels
int temp = (int) opts[0].getNumValue();
if(temp != -1)
numLevels = temp - 1;
labels = new String[numLevels + 1];
for(int i=0; i <= numLevels; i++)
{
if((i+1) < opts.length)
{
labels[i] = opts[i+1].getStringValue();
if(labels[i] == null)
labels[i] = "_";
}
else
labels[i] = "?";
}
}
/**
* This switches the labels that will be used to there opposite. If
* a peak above the cutoff would have been labeled 'A' and one below 'B',
* it will now be labeled as a 'B.' If there is a third label, so A, H, B,
* invert will switch it to B, H, A.
*/
public void invert()
{
int length = labels.length;
String temp[] = new String[length];
for(int i=0; i < length; i++)
temp[i] = labels[length - 1 - i];
labels = temp;
}
/**
* Gives the name of this segregating score function.
*
* @return the name, which is "Segregating".
*/
public String getName()
{
return name;
}
/**
* Gives a one sentence description of this score function.
*
* @return the description
*/
public String getDescription()
{
return descript;
}
/**
* Gives a file that is the help file for this scoring function
*
* @return a plaintext of html file containing help information
*/
public String getHelpFile()
{
return helpFile;
}
/**
* Writes all of the information this class needs to store in order
* to be recreated. This will be used for things like storing the
* class in a file. Therefore, the write should output enough information
* so that read
can recreate the essential properties of this
* class.
*
* @param out the destination to write the data to.
*
* @exception IOException occurs when a problem is encountered when
* writing to the stream.
*/
public void write(DataOutputStream out) throws IOException
{
out.writeInt(numLevels);
out.writeInt(labels.length);
for(int i=0; i < labels.length; i++)
out.writeUTF(labels[i]);
}
/**
* Reads in the properties of this class from the specified input stream.
* The stream data should have been created by write
. This
* will retrieve this classes state from the input stream. All of the
* current data in this class will be replaced by the data from the
* stream.
*
* @param in the input stream with the data for the class.
*
* @exception IOException occurs when a problem is encountered when
* writing to the stream.
*/
public void read(DataInputStream in) throws IOException
{
numLevels = in.readInt();
int length = in.readInt();
labels = new String[length];
for(int i=0; i < length; i++)
labels[i] = in.readUTF();
}
}