/*
* 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.cross;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import org.jax.r.jriutilities.JRIUtilityFunctions;
import org.jax.r.jriutilities.RObject;
import org.jax.r.jriutilities.SilentRCommand;
import org.rosuda.JRI.REXP;
/**
* Holds genetic map information
* @author <A HREF="mailto:keith.sheppard@jax.org">Keith Sheppard</A>
*/
public class GeneticMap
{
/**
* Comparator for sorting markers on based on thier positions
* @see GeneticMarker#getMarkerPositionCentimorgans()
*/
public static final Comparator<GeneticMarker> positionComparator =
new Comparator<GeneticMarker>()
{
/**
* {@inheritDoc}
*/
public int compare(GeneticMarker position1, GeneticMarker position2)
{
return Double.compare(
position1.getMarkerPositionCentimorgans(),
position2.getMarkerPositionCentimorgans());
}
};
/**
* Map type...
*/
public static enum MapType
{
/**
* Doesn't care about sex
*/
SEX_AGNOSTIC,
/**
* specific to males
*/
MALE,
/**
* specific to females
*/
FEMALE
}
private final MapType mapType;
private final RObject backinRMap;
private final String chromosomeName;
/**
* Construct a new map
* @param chromosomeName
* the name of the chromosome that this map is for
* @param mapType
* the type of map to construct
* @param backingRMap
* the R "map" object backing this map
*/
public GeneticMap(
String chromosomeName,
MapType mapType,
RObject backingRMap)
{
this.chromosomeName = chromosomeName;
this.mapType = mapType;
this.backinRMap = backingRMap;
}
/**
* Getter for the chromosome name
* @return
* the chromosome name
*/
public String getChromosomeName()
{
return this.chromosomeName;
}
/**
* Get a list of all of the positions in this map
* @return
* the list of marker positions
*/
public List<GeneticMarker> getMarkerPositions()
{
switch(this.mapType)
{
case SEX_AGNOSTIC:
{
return this.getMarkerPositionsFrom(this.backinRMap);
}
case MALE:
{
RObject backingMaleMap = new RObject(
this.backinRMap.getRInterface(),
this.backinRMap.getAccessorExpressionString() + "[2,]");
return this.getMarkerPositionsFrom(backingMaleMap);
}
case FEMALE:
{
RObject backingMaleMap = new RObject(
this.backinRMap.getRInterface(),
this.backinRMap.getAccessorExpressionString() + "[1,]");
return this.getMarkerPositionsFrom(backingMaleMap);
}
default:
{
throw new IllegalArgumentException("unknown map type");
}
}
}
/**
* Get marker positions using the given r object as the genetic map
* @param backingRMap
* the r object for the genetic map
*/
private List<GeneticMarker> getMarkerPositionsFrom(RObject backingRMap)
{
String[] names = JRIUtilityFunctions.getNames(backingRMap);
SilentRCommand silentCommand = new SilentRCommand(
backingRMap.getAccessorExpressionString());
REXP markerPositionsExpression = backingRMap.getRInterface().evaluateCommand(
silentCommand);
double[] markerPositionsArray = markerPositionsExpression.asDoubleArray();
// the sizes should be the same
if(names.length == markerPositionsArray.length)
{
List<GeneticMarker> markerPositions =
new ArrayList<GeneticMarker>(names.length);
for(int i = 0; i < markerPositionsArray.length; i++)
{
markerPositions.add(new GeneticMarker(
names[i],
this.chromosomeName,
markerPositionsArray[i]));
}
return markerPositions;
}
else
{
throw new IllegalStateException(
"the number of positions don't match the number " +
"of names: " + names.length + " " +
markerPositionsArray.length);
}
}
/**
* Get the total extent of the given list in centimorgans
* @param markerPositions
* the list of marker positions. it is assumed that these all
* come from the same chromosome
* @return
* the total extent in centimorgans
*/
public static double getTotalExtentOfMarkerListInCentimorgans(List<GeneticMarker> markerPositions)
{
if(markerPositions.size() > 1)
{
// double maxMarkerPosition =
// markerPositions.get(0).getMarkerPositionCentimorgans();
// double minMarkerPosition =
// markerPositions.get(0).getMarkerPositionCentimorgans();
//
// for(GeneticMarker markerPosition: markerPositions)
// {
// double currMarkerPosition =
// markerPosition.getMarkerPositionCentimorgans();
// if(currMarkerPosition > maxMarkerPosition)
// {
// maxMarkerPosition = currMarkerPosition;
// }
// else if(currMarkerPosition < minMarkerPosition)
// {
// minMarkerPosition = currMarkerPosition;
// }
// }
//
// return maxMarkerPosition - minMarkerPosition;
// TOOD make sure this is a good assumption
// assuming marker positions are given in order
GeneticMarker initialMarker = markerPositions.get(0);
GeneticMarker finalMarker = markerPositions.get(
markerPositions.size() - 1);
return
finalMarker.getMarkerPositionCentimorgans() -
initialMarker.getMarkerPositionCentimorgans();
}
else
{
return 0.0;
}
}
}