//===================================================================== // 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(); } }