/*
* Copyright (c) 2009 The Jackson Laboratory
*
* This software was developed by Gary Churchill's Lab at The Jackson
* Laboratory (see http://research.jax.org/faculty/churchill).
*
* This 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, either version 3 of the License, or
* (at your option) any later version.
*
* This software 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 software. If not, see <http://www.gnu.org/licenses/>.
*/
package org.jax.qtl.scan;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import org.jax.qtl.cross.Cross;
import org.jax.qtl.cross.GeneticMarker;
import org.jax.qtl.project.QtlDataModel;
import org.jax.r.RUtilities;
import org.jax.r.jriutilities.JRIUtilityFunctions;
import org.jax.r.jriutilities.RInterface;
import org.jax.r.jriutilities.RObject;
import org.jax.r.jriutilities.SilentRCommand;
import org.jax.util.datastructure.SequenceUtilities;
import org.rosuda.JRI.REXP;
/**
* Holds the scantwo results
* @author <A HREF="mailto:keith.sheppard@jax.org">Keith Sheppard</A>
*/
public class ScanTwoResult extends ScanResult implements Comparable<ScanTwoResult>
{
private static final Logger LOG = Logger.getLogger(
ScanTwoResult.class.getName());
/**
* Enum for specifying one of the significance values this scan result
* holds.
*/
public enum ScanTwoSignificanceValueType
{
/**
* the full lod score
*/
FULL_LOD
{
/**
* {@inheritDoc}
*/
@Override
public String toString()
{
return "Full Model";
}
},
/**
* the additive lod score
*/
ADDITIVE_LOD
{
/**
* {@inheritDoc}
*/
@Override
public String toString()
{
return "Additive Model";
}
},
/**
* full vs. additive
*/
FULL_VERSUS_ADDITIVE_LOD
{
/**
* {@inheritDoc}
*/
@Override
public String toString()
{
return "Full vs. Additive";
}
},
/**
* full vs. scanone
*/
FULL_VERSUS_SCANONE_LOD
{
/**
* {@inheritDoc}
*/
@Override
public String toString()
{
return "Full vs. One QTL";
}
},
/**
* additive vs. scanone
*/
ADDITIVE_VERSUS_SCANONE_LOD
{
/**
* {@inheritDoc}
*/
@Override
public String toString()
{
return "Additive vs. One QTL";
}
}
}
/**
* A pairing of marker index values
*/
public static class MarkerIndexPair implements Comparable<MarkerIndexPair>
{
private final int lesserMarkerIndex;
private final int greaterMarkerIndex;
/**
* Constructor. The given lesser index should always be greater
* than the given greater index.
* @param lesserMarkerIndex
* the lesser index
* @param greaterMarkerIndex
* the greater index
* @throws IllegalArgumentException
* if lesserMarkerIndex >= greaterMarkerIndex
*/
public MarkerIndexPair(int lesserMarkerIndex, int greaterMarkerIndex)
throws IllegalArgumentException
{
if(lesserMarkerIndex >= greaterMarkerIndex)
{
throw new IllegalArgumentException(
"the given lesser index (" + lesserMarkerIndex +
") is larger than the given greater index (" +
greaterMarkerIndex + ")");
}
this.lesserMarkerIndex = lesserMarkerIndex;
this.greaterMarkerIndex = greaterMarkerIndex;
}
/**
* Getter for the lesser index
* @return the lesserMarkerIndex
*/
public int getLesserMarkerIndex()
{
return this.lesserMarkerIndex;
}
/**
* Getter for the greater index
* @return the greaterMarkerIndex
*/
public int getGreaterMarkerIndex()
{
return this.greaterMarkerIndex;
}
/**
* {@inheritDoc}
*/
@Override
public boolean equals(Object otherPairObject)
{
if(otherPairObject instanceof MarkerIndexPair)
{
MarkerIndexPair otherPair = (MarkerIndexPair)otherPairObject;
return this.lesserMarkerIndex == otherPair.lesserMarkerIndex &&
this.greaterMarkerIndex == otherPair.greaterMarkerIndex;
}
else
{
return false;
}
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode()
{
int hash = this.lesserMarkerIndex << 16;
hash = hash | this.greaterMarkerIndex;
return hash;
}
/**
* {@inheritDoc}
*/
public int compareTo(MarkerIndexPair otherPair)
{
// major sort on the lesser index
int lesserDifference =
this.lesserMarkerIndex - otherPair.lesserMarkerIndex;
if(lesserDifference != 0)
{
return lesserDifference;
}
else
{
// minor sort on the greater index
return this.greaterMarkerIndex - otherPair.greaterMarkerIndex;
}
}
}
/**
* the R type that a {@link ScanTwoResult} should have
*/
public static final String SCANTWO_RESULT_TYPE_STRING = "scantwo";
private static final String PERMUTATION_RESULT_TYPE_STRING = "scantwoperm";
private static final String LOD_COMPONENT_SUFFIX_STRING = "$lod";
private static final String MAP_COMPONENT_SUFFIX_STRING = "$map";
private static final String SCANONE_X_COMPONENT_SUFFIX_STRING = "$scanoneX";
private final String lodComponentAccessor;
private final String scanoneXComponentAccessor;
private final String mapComponentAccessor;
private final Map<String, double[][]> lodScoreMatrixCache =
new HashMap<String, double[][]>();
private final Map<String, double[]> scanOneXCache =
new HashMap<String, double[]>();
private final Map<Integer, double[]> phenotypeIndexToMaxScanonesCache =
new HashMap<Integer, double[]>();
private List<ScanTwoGeneticMarker> geneticMarkersCache = null;
private String[] scannedChromosomeNamesCache = null;
private final RObject scanPermutationsRObject;
private final boolean singlePhenotypeScanned;
private int[] markerChromosomeIndices;
/**
* Constructor
* @param rInterface
* the r interface
* @param accessorExpressionString
* the accessor expression
* @param parentCross
* the cross that owns this scan result
*/
public ScanTwoResult(
RInterface rInterface,
String accessorExpressionString,
Cross parentCross)
{
super(rInterface, accessorExpressionString, parentCross);
this.lodComponentAccessor =
accessorExpressionString +
LOD_COMPONENT_SUFFIX_STRING;
this.scanoneXComponentAccessor =
accessorExpressionString +
SCANONE_X_COMPONENT_SUFFIX_STRING;
this.mapComponentAccessor =
accessorExpressionString +
MAP_COMPONENT_SUFFIX_STRING;
String accessorStringForPermResult =
this.getAccessorExpressionString() +
ScanCommandBuilder.PERMUTATION_IDENTIFIER_SUFFIX;
this.scanPermutationsRObject = new RObject(
this.getRInterface(),
accessorStringForPermResult);
this.singlePhenotypeScanned =
this.getScannedPhenotypeIndices().length == 1;
}
/**
* This is just a convenience function for using the value type to get to
* the score that we're interested in instead of calling the function
* directly
* @param scannedPhenotypeIndex
* the phenotype index to use. this index represents the order
* that the phenotype is given in the scan, this is probably
* different from the index the phenotype has in the cross
* @param markerIndexPair
* the marker index pair that we're getting a value for
* @param valueType
* the type of value that we're looking for
* @return
* the value
*/
public double getSignificanceValue(
int scannedPhenotypeIndex,
MarkerIndexPair markerIndexPair,
ScanTwoSignificanceValueType valueType)
{
switch(valueType)
{
case ADDITIVE_LOD:
{
return this.getAdditiveLod(scannedPhenotypeIndex, markerIndexPair);
}
case ADDITIVE_VERSUS_SCANONE_LOD:
{
return this.getAdditiveVersusScanOneLod(scannedPhenotypeIndex, markerIndexPair);
}
case FULL_LOD:
{
return this.getFullLod(scannedPhenotypeIndex, markerIndexPair);
}
case FULL_VERSUS_ADDITIVE_LOD:
{
return this.getFullVersusAdditiveLod(scannedPhenotypeIndex, markerIndexPair);
}
case FULL_VERSUS_SCANONE_LOD:
{
return this.getFullVersusScanOneLod(scannedPhenotypeIndex, markerIndexPair);
}
default:
{
throw new IllegalStateException(
"unknown value type: " + valueType.name());
}
}
}
/**
* Get the full lod score for the given markers
* @param scannedPhenotypeIndex
* the phenotype index to use. this index represents the order
* that the phenotype is given in the scan, this is probably
* different from the index the phenotype has in the cross
* @param markerIndexPair
* the index pair
* @return
* the full lod score
*/
public double getFullLod(int scannedPhenotypeIndex, MarkerIndexPair markerIndexPair)
{
// the full model is in the "lower triangle" of the matrix, so
// the row need to be bigger than the column
final int row = markerIndexPair.getGreaterMarkerIndex();
final int column = markerIndexPair.getLesserMarkerIndex();
return this.getLodScoreMatrix(scannedPhenotypeIndex)[row][column];
}
/**
* Get the additive lod score for the given markers
* @param scannedPhenotypeIndex
* the phenotype index to use. this index represents the order
* that the phenotype is given in the scan, this is probably
* different from the index the phenotype has in the cross
* @param markerIndexPair
* the index pair
* @return
* the additive lod score
*/
public double getAdditiveLod(int scannedPhenotypeIndex, MarkerIndexPair markerIndexPair)
{
// the additive model is in the "upper triangle" of the matrix, so
// the row need to be smaller than the column
int row = markerIndexPair.getLesserMarkerIndex();
int column = markerIndexPair.getGreaterMarkerIndex();
return this.getLodScoreMatrix(scannedPhenotypeIndex)[row][column];
}
/**
* Get full sore vs. additive score for the given markers
* (AKA: interaction)
* @param scannedPhenotypeIndex
* the phenotype index to use. this index represents the order
* that the phenotype is given in the scan, this is probably
* different from the index the phenotype has in the cross
* @param markerIndexPair
* the index pair
* @return
* the full vs. additive score
*/
public double getFullVersusAdditiveLod(int scannedPhenotypeIndex, MarkerIndexPair markerIndexPair)
{
return this.getFullLod(scannedPhenotypeIndex, markerIndexPair) -
this.getAdditiveLod(scannedPhenotypeIndex, markerIndexPair);
}
/**
* Get full sore vs. scanone score for the given markers
* (AKA conditional-interactive)
* @param scannedPhenotypeIndex
* the phenotype index to use. this index represents the order
* that the phenotype is given in the scan, this is probably
* different from the index the phenotype has in the cross
* @param markerIndexPair
* the index pair
* @return
* the full vs. scanone score
*/
public double getFullVersusScanOneLod(int scannedPhenotypeIndex, MarkerIndexPair markerIndexPair)
{
double lod =
this.getFullLod(scannedPhenotypeIndex, markerIndexPair) -
this.getMaxScanOneLod(scannedPhenotypeIndex, markerIndexPair);
// floor the lod value at 0
return lod < 0.0 ? 0.0 : lod;
}
/**
* Get the additive vs. scanone score
* (AKA conditional-additive)
* @param scannedPhenotypeIndex
* the phenotype index to use. this index represents the order
* that the phenotype is given in the scan, this is probably
* different from the index the phenotype has in the cross
* @param markerIndexPair
* the index pair
* @return
* the additive vs. scanone score
*/
public double getAdditiveVersusScanOneLod(int scannedPhenotypeIndex, MarkerIndexPair markerIndexPair)
{
double lod =
this.getAdditiveLod(scannedPhenotypeIndex, markerIndexPair) -
this.getMaxScanOneLod(scannedPhenotypeIndex, markerIndexPair);
// floor the lod value at 0
return lod < 0.0 ? 0.0 : lod;
}
/**
* Get the scanone lod score for the given marker index
* @param scannedPhenotypeIndex
* the phenotype index to use. this index represents the order
* that the phenotype is given in the scan, this is probably
* different from the index the phenotype has in the cross
* @param markerIndex
* the marker index to get the scanone score for
* @return
* the scanone lod
*/
public double getScanOneLod(int scannedPhenotypeIndex, int markerIndex)
{
// the scanone values that ignore covariates live along the X
// diagonal
return this.getLodScoreMatrix(scannedPhenotypeIndex)[markerIndex][markerIndex];
}
/**
* Get the scanone score that considers sex and/or cross direction
* covariates
* @param scannedPhenotypeIndex
* the phenotype index to use. this index represents the order
* that the phenotype is given in the scan, this is probably
* different from the index the phenotype has in the cross
* @param markerIndex
* the marker index
* @return
* the scanone LOD which accounts for covariates
*/
public double getScanOneXLod(int scannedPhenotypeIndex, int markerIndex)
{
return this.getScanOneX(scannedPhenotypeIndex)[markerIndex];
}
/**
* Get the "max" scanone. Depending on the chromosome they come from, we
* may use either {@link #getScanOneLod(int, int)} or {@link #getScanOneXLod(int, int)}
* @param scannedPhenotypeIndex
* the phenotype
* @param markerIndexPair
* the index pair
* @return
* the max LOD from either marker
*/
private double getMaxScanOneLod(
int scannedPhenotypeIndex,
MarkerIndexPair markerIndexPair)
{
int lesserIndex = markerIndexPair.getLesserMarkerIndex();
int greaterIndex = markerIndexPair.getGreaterMarkerIndex();
int[] markerChromosomeIndices = this.getMarkerChromosomeIndices();
double[] maxScanones = this.getMaxScanoneLodPerChromosome(scannedPhenotypeIndex);
return Math.max(
maxScanones[markerChromosomeIndices[lesserIndex]],
maxScanones[markerChromosomeIndices[greaterIndex]]);
}
/**
* Getter for the chromosome indices for each marker
* @return
* the chromosome indices
*/
private synchronized int[] getMarkerChromosomeIndices()
{
if(this.markerChromosomeIndices == null)
{
List<List<ScanTwoGeneticMarker>> geneticMarkersPerChromosome =
this.getGeneticMarkersPerChromosome();
int chromoCount = geneticMarkersPerChromosome.size();
List<Integer> markerChromosomeIndicesList = new ArrayList<Integer>();
for(int chromoIndex = 0; chromoIndex < chromoCount; chromoIndex++)
{
List<ScanTwoGeneticMarker> chromoMarkers =
geneticMarkersPerChromosome.get(chromoIndex);
int markerCount = chromoMarkers.size();
for(int markerIndex = 0; markerIndex < markerCount; markerIndex++)
{
markerChromosomeIndicesList.add(chromoIndex);
}
}
this.markerChromosomeIndices = SequenceUtilities.toIntArray(
markerChromosomeIndicesList);
}
return this.markerChromosomeIndices;
}
/**
* Getter for the max scanone LOD values which will be one per chromosome
* @param scannedPhenotypeIndex
* the phenotype index
* @return
* the LOD scores
*/
private synchronized double[] getMaxScanoneLodPerChromosome(
int scannedPhenotypeIndex)
{
double[] maxScanoneLodPerChromosome =
this.phenotypeIndexToMaxScanonesCache.get(scannedPhenotypeIndex);
if(maxScanoneLodPerChromosome == null)
{
double[] scanOneXLods = null;
List<List<ScanTwoGeneticMarker>> geneticMarkersPerChromosome =
this.getGeneticMarkersPerChromosome();
int chromoCount = geneticMarkersPerChromosome.size();
maxScanoneLodPerChromosome = new double[chromoCount];
int markerIndex = 0;
for(int chromoIndex = 0; chromoIndex < chromoCount; chromoIndex++)
{
for(ScanTwoGeneticMarker currMarker: geneticMarkersPerChromosome.get(chromoIndex))
{
double scanoneLod;
if(currMarker.isXChromosome())
{
if(scanOneXLods == null)
{
scanOneXLods = this.getScanOneX(scannedPhenotypeIndex);
}
scanoneLod = scanOneXLods[markerIndex];
}
else
{
scanoneLod = this.getScanOneLod(scannedPhenotypeIndex, markerIndex);
}
if(scanOneXLods == null)
{
scanOneXLods = this.getScanOneX(scannedPhenotypeIndex);
}
if(scanoneLod > maxScanoneLodPerChromosome[chromoIndex])
{
maxScanoneLodPerChromosome[chromoIndex] = scanoneLod;
}
markerIndex++;
}
}
this.phenotypeIndexToMaxScanonesCache.put(
scannedPhenotypeIndex,
maxScanoneLodPerChromosome);
}
return maxScanoneLodPerChromosome;
}
/**
* Getter for the lod score matrix at the given index
* @param scannedPhenotypeIndex
* the index
* @return
* the matrix
*/
public synchronized double[][] getLodScoreMatrix(int scannedPhenotypeIndex)
{
if(this.singlePhenotypeScanned)
{
return this.getLodScoreMatrix(this.lodComponentAccessor);
}
else
{
return this.getLodScoreMatrix(
this.lodComponentAccessor + "[ , , " + (scannedPhenotypeIndex + 1) + "]");
}
}
// /**
// * Getter for the lod score matrix. The outer array is for rows and the
// * inner array is for columns.
// * @return
// * the matrix
// */
// public synchronized double[][] getLodScoreMatrix()
// {
// return this.getLodScoreMatrix(this.lodComponentAccessor);
// }
/**
* Get the LOD score matrix
* @param lodMatrixAccessor
* the R accessor string for the matrix
* @return
* the matrix
*/
private synchronized double[][] getLodScoreMatrix(String lodMatrixAccessor)
{
if(this.lodScoreMatrixCache.containsKey(lodMatrixAccessor))
{
return this.lodScoreMatrixCache.get(lodMatrixAccessor);
}
else
{
RObject lodComponent = new RObject(
this.getRInterface(),
lodMatrixAccessor);
int numRows = JRIUtilityFunctions.getNumberOfRows(lodComponent);
int numCols = JRIUtilityFunctions.getNumberOfColumns(lodComponent);
double[][] lodScoreMatrix;
if(numRows == 0)
{
LOG.warning("scantwo LOD scores are empty");
lodScoreMatrix = new double[0][];
this.lodScoreMatrixCache.put(
lodComponent.getAccessorExpressionString(),
lodScoreMatrix);
}
else if(numRows != numCols)
{
LOG.severe(
"scantwo rows are different than scantwo columns: cols=" +
numCols + ", rows=" + numRows);
lodScoreMatrix = new double[0][];
this.lodScoreMatrixCache.put(
lodComponent.getAccessorExpressionString(),
lodScoreMatrix);
}
else
{
lodScoreMatrix = new double[numRows][];
for(int currRow = 0; currRow < numRows; currRow++)
{
String currRowAccessor = RUtilities.rowIndexExpression(
lodMatrixAccessor,
currRow);
REXP currRowExpression =
this.getRInterface().evaluateCommand(
new SilentRCommand(currRowAccessor));
lodScoreMatrix[currRow] =
currRowExpression.asDoubleArray();
}
this.lodScoreMatrixCache.put(
lodComponent.getAccessorExpressionString(),
lodScoreMatrix);
}
return lodScoreMatrix;
}
}
/**
* Get the scanonex data for the given phenotype index
* @param scannedPhenotypeIndex
* the phenotype index to use. this index represents the order
* that the phenotype is given in the scan, this is probably
* different from the index the phenotype has in the cross
* @return
* the scanoneX lod array
*/
public synchronized double[] getScanOneX(int scannedPhenotypeIndex)
{
if(this.singlePhenotypeScanned)
{
return this.getScanOneX(this.scanoneXComponentAccessor);
}
else
{
return this.getScanOneX(
this.scanoneXComponentAccessor + "[ , " + (scannedPhenotypeIndex + 1) + "]");
}
}
/**
* Getter for the scanone X values
* @return
* the scanone X values
*/
// TODO documentation says:
// The final component is a version of the results of scanone including sex
// and/or cross direction as additive covariates, which is needed for a
// proper calculation of conditional LOD scores.
private synchronized double[] getScanOneX(String scanoneXArrayAccessor)
{
if(this.scanOneXCache.containsKey(scanoneXArrayAccessor))
{
return this.scanOneXCache.get(scanoneXArrayAccessor);
}
else
{
String scanOneXValuesAccessor = RUtilities.columnIndexExpression(
scanoneXArrayAccessor,
0);
REXP scanoneValuesExpression = this.getRInterface().evaluateCommand(
new SilentRCommand(scanOneXValuesAccessor));
double[] scanOneXArray = scanoneValuesExpression.asDoubleArray();
this.scanOneXCache.put(scanoneXArrayAccessor, scanOneXArray);
return scanOneXArray;
}
}
/**
* Get the genetic markers seperated into per-chromosome lists
* @return
* the markers
*/
public List<List<ScanTwoGeneticMarker>> getGeneticMarkersPerChromosome()
{
List<ScanTwoGeneticMarker> allMarkers = this.getGeneticMarkers();
List<List<ScanTwoGeneticMarker>> markersPerChromosome =
new ArrayList<List<ScanTwoGeneticMarker>>();
Map<String, List<ScanTwoGeneticMarker>> markerListCache =
new HashMap<String, List<ScanTwoGeneticMarker>>();
for(ScanTwoGeneticMarker geneticMarker: allMarkers)
{
List<ScanTwoGeneticMarker> currMarkerList =
markerListCache.get(geneticMarker.getChromosomeName());
if(currMarkerList == null)
{
currMarkerList = new ArrayList<ScanTwoGeneticMarker>();
markerListCache.put(
geneticMarker.getChromosomeName(),
currMarkerList);
markersPerChromosome.add(currMarkerList);
}
currMarkerList.add(geneticMarker);
}
return markersPerChromosome;
}
/**
* Organizes the markers returned by {@link #getGeneticMarkers()} into
* a mapping where chromosome name is the key
* @return
* the mapping
*/
public Map<String, List<GeneticMarker>> getChromosomeNameToMarkerMap()
{
Map<String, List<GeneticMarker>> chromoNameToMarkerMap =
new HashMap<String, List<GeneticMarker>>();
List<ScanTwoGeneticMarker> markerList = this.getGeneticMarkers();
for(ScanTwoGeneticMarker currMarker: markerList)
{
List<GeneticMarker> chromoMarkerList = chromoNameToMarkerMap.get(
currMarker.getChromosomeName());
if(chromoMarkerList == null)
{
chromoMarkerList = new ArrayList<GeneticMarker>();
chromoNameToMarkerMap.put(
currMarker.getChromosomeName(),
chromoMarkerList);
}
chromoMarkerList.add(currMarker);
}
return chromoNameToMarkerMap;
}
/**
* Get the 1D marker count
* @return
* the marker count
*/
public int getMarkerCount()
{
return this.getGeneticMarkers().size();
}
/**
* Getter for the genetic markers
* @return
* the markers
*/
public synchronized List<ScanTwoGeneticMarker> getGeneticMarkers()
{
if(this.geneticMarkersCache == null)
{
String[] markerNames =
JRIUtilityFunctions.getRowNames(new RObject(
this.getRInterface(),
this.mapComponentAccessor));
String markerPositionsAccessor =
this.mapComponentAccessor + "$pos";
REXP markerPositionsExpression = this.getRInterface().evaluateCommand(
new SilentRCommand(markerPositionsAccessor));
double[] markerPositions =
markerPositionsExpression.asDoubleArray();
String isXChromosomeAccessor =
this.mapComponentAccessor + "$xchr";
REXP isXChromosomeExpression = this.getRInterface().evaluateCommand(
new SilentRCommand(isXChromosomeAccessor));
boolean[] isXChromosomeValues =
JRIUtilityFunctions.extractBooleanValues(isXChromosomeExpression);
String[] chromosomeNames = this.getMarkerChromosomeNames();
if(markerNames.length != markerPositions.length ||
markerPositions.length != chromosomeNames.length)
{
LOG.severe("marker value arrays have different lengths");
this.geneticMarkersCache = Collections.emptyList();
}
else
{
List<ScanTwoGeneticMarker> markers = new ArrayList<ScanTwoGeneticMarker>(
markerNames.length);
for(int i = 0; i < markerNames.length; i++)
{
ScanTwoGeneticMarker currGeneticMarker = new ScanTwoGeneticMarker(
markerNames[i],
chromosomeNames[i],
markerPositions[i],
isXChromosomeValues[i]);
markers.add(currGeneticMarker);
}
this.geneticMarkersCache = markers;
}
}
return this.geneticMarkersCache;
}
/**
* Getter for the marker chromosome names
* @return
* the marker chromosome names
*/
private String[] getMarkerChromosomeNames()
{
String markerChromosomesAccessor =
this.mapComponentAccessor + "$chr";
REXP markerChromosomeExpression = this.getRInterface().evaluateCommand(
new SilentRCommand(markerChromosomesAccessor));
return JRIUtilityFunctions.extractStringArrayFromFactor(
markerChromosomeExpression);
}
/**
* Getter for the unique chromosome name
* @return
* the unique chromosome names
*/
public synchronized String[] getScannedChromosomeNames()
{
if(this.scannedChromosomeNamesCache == null)
{
ArrayList<String> chromosomeNames = new ArrayList<String>();
for(String currChromoName: this.getMarkerChromosomeNames())
{
if(!chromosomeNames.contains(currChromoName))
{
chromosomeNames.add(currChromoName);
}
}
this.scannedChromosomeNamesCache =
chromosomeNames.toArray(new String[chromosomeNames.size()]);
}
return this.scannedChromosomeNamesCache;
}
/**
* Class for holding the typical marker information plus an X chromosome
* indicator from the scantwo results
*/
public class ScanTwoGeneticMarker extends GeneticMarker
{
private final boolean isXChromosome;
/**
* Constructor
* @param markerName
* the name of the marker
* @param chromosomeName
* the chromosome name
* @param markerPositionCentimorgans
* the marker position
* @param isXChromosome
* specifies whether or not this is for the x chromosome
*/
public ScanTwoGeneticMarker(
String markerName,
String chromosomeName,
double markerPositionCentimorgans,
boolean isXChromosome)
{
super(markerName, chromosomeName, markerPositionCentimorgans);
this.isXChromosome = isXChromosome;
}
/**
* Getter for determining if this is the x chromosome or not
* @return
* true iff this marker is on the X chromosome
*/
public boolean isXChromosome()
{
return this.isXChromosome;
}
}
/**
* {@inheritDoc}
*/
public int compareTo(ScanTwoResult otherScanTwoResults)
{
return this.getAccessorExpressionString().compareTo(
otherScanTwoResults.getAccessorExpressionString());
}
/**
* Determine if there are any scantwo results in the given data model
* @param dataModel
* the data model to check for scantwo results
* @return
* true iff there are any scantwo results
*/
public static boolean anyScanTwoResultsExist(QtlDataModel dataModel)
{
Cross[] crosses = dataModel.getCrosses();
for(Cross cross: crosses)
{
if(!cross.getScanTwoResults().isEmpty())
{
return true;
}
}
return false;
}
/**
* Get the number of chromosomes represented in this scantwo result
* @return
* the number of chromosomes
*/
public int getChromosomeCount()
{
return this.getGeneticMarkersPerChromosome().size();
}
/**
* Get the accessor string for the permutations object. This function
* returns a string whether or not the permutations were actually
* calculated
* @return
* the accessor string for the permutations object
* @see #getPermutationsWereCalculated()
*/
public String getPermutationsObjectAccessorString()
{
return this.scanPermutationsRObject.getAccessorExpressionString();
}
/**
* Determines if permutations based info is available for this result
* @return
* true iff permutations are available
*/
public boolean getPermutationsWereCalculated()
{
if(JRIUtilityFunctions.isTopLevelObject(this.scanPermutationsRObject))
{
if(JRIUtilityFunctions.inheritsRClass(
this.scanPermutationsRObject,
PERMUTATION_RESULT_TYPE_STRING))
{
return true;
}
else
{
LOG.warning(
"R object \"" +
this.scanPermutationsRObject.getAccessorExpressionString() +
"\" exists, but isn't the expected type \"" +
PERMUTATION_RESULT_TYPE_STRING + "\"");
return false;
}
}
else
{
return false;
}
}
}