/*
* Copyright (c) 2010 The Jackson Laboratory
*
* 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.maanova.madata;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jax.maanova.fit.FitMaanovaResult;
import org.jax.maanova.test.MaanovaTestResult;
import org.jax.r.RAssignmentCommand;
import org.jax.r.RCommand;
import org.jax.r.RCommandParameter;
import org.jax.r.RMethodInvocationCommand;
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.rosuda.JRI.REXP;
/**
* Class representing the underlying "madata" R type
* @author <A HREF="mailto:keith.sheppard@jax.org">Keith Sheppard</A>
*/
public class MicroarrayExperiment extends RObject
{
/**
* This is the name that R/maanova assigns to the underlying R type.
*/
public static final String R_CLASS_STRING = "madata";
/**
* our logger
*/
private static final Logger LOG = Logger.getLogger(
MicroarrayExperiment.class.getName());
private static final String DYE_COUNT_COMPONENT = "$n.dye";
private static final String NUM_ARRAYS_COMPONENT = "$n.array";
private static final String NUM_GENES_COMPONENT = "$n.gene";
private static final String DATA_COMPONENT = "$data";
private static final String PROBESET_ID_COMPONENT = "$probeid";
private static final String GENE_LISTS_COMPONENT = "$gene_lists";
/**
* Constructor
* @param rInterface
* the R interface that this object belongs to
* @param accessorExpressionString
* the accessor expression that you use in R to get
* to the
*/
public MicroarrayExperiment(
RInterface rInterface,
String accessorExpressionString)
{
super(rInterface, accessorExpressionString);
}
/**
* Getter for the number of arrays in the experiment
* @return
* the # of arrays
*/
public int getMicroarrayCount()
{
REXP numArraysRExpression = this.getRInterface().evaluateCommand(
new SilentRCommand(
this.getAccessorExpressionString() +
NUM_ARRAYS_COMPONENT));
return JRIUtilityFunctions.extractIntegerValue(numArraysRExpression);
}
/**
* Getter for the number of genes in the experiment
* @return
* the # of genes
*/
public int getGeneCount()
{
REXP numGenesRExpression = this.getRInterface().evaluateCommand(
new SilentRCommand(
this.getAccessorExpressionString() +
NUM_GENES_COMPONENT));
return JRIUtilityFunctions.extractIntegerValue(numGenesRExpression);
}
/**
* Get all of the top-level R objects whose class is {@value #R_CLASS_STRING}
* @param rInterface
* the R interface to extract the objects from
* @return
* the R objects of type {@value #R_CLASS_STRING}
*/
public static List<RObject> getAllMicroarrayExperimentRObjects(RInterface rInterface)
{
List<RObject> microarrayIdentifiers = JRIUtilityFunctions.getTopLevelObjectsOfType(
rInterface,
R_CLASS_STRING);
if(LOG.isLoggable(Level.FINEST))
{
StringBuffer message = new StringBuffer(
"detected microarray data objects:");
for(RObject currMicroarrayId: microarrayIdentifiers)
{
message.append(" " + currMicroarrayId.getAccessorExpressionString());
}
LOG.finest(message.toString());
}
return microarrayIdentifiers;
}
/**
* Get the gene list names
* @return the gene list names
*/
public List<String> getGeneListNames()
{
RObject geneListsObj = new RObject(
this.getRInterface(),
this.getAccessorExpressionString() + GENE_LISTS_COMPONENT);
if(JRIUtilityFunctions.isNull(geneListsObj))
{
return Collections.emptyList();
}
else
{
String[] names = JRIUtilityFunctions.getNames(geneListsObj);
return new ArrayList<String>(Arrays.asList(names));
}
}
/**
* Getter for the gene list with the given name
* @param listName the gene list name
* @return the gene list for the given name
*/
public String[] getGeneListNamed(String listName)
{
String geneListAccessor =
this.getAccessorExpressionString() + GENE_LISTS_COMPONENT +
'$' + listName;
REXP geneListRExp = this.getRInterface().evaluateCommand(new SilentRCommand(
geneListAccessor));
return geneListRExp.asStringArray();
}
/**
* Getter for the indices for gene list with the given name
* @param listName the name
* @return the indices
*/
public int[] getIndicesForGeneListNamed(String listName)
{
String[] allGenesList = this.getProbesetIds();
Map<String, Integer> geneIndexMap = new HashMap<String, Integer>();
for(int i = 0; i < allGenesList.length; i++)
{
geneIndexMap.put(allGenesList[i], i);
}
String[] geneList = this.getGeneListNamed(listName);
int[] indices = new int[geneList.length];
for(int i = 0; i < geneList.length; i++)
{
indices[i] = geneIndexMap.get(geneList[i]);
}
return indices;
}
/**
* Adds the given gene list to this microarray experiment
* @param listName
* the list name
* @param genes
* the genes in the list
*/
public void putGeneListNamed(String listName, List<String> genes)
{
String geneListsAccessor =
this.getAccessorExpressionString() + GENE_LISTS_COMPONENT;
if(JRIUtilityFunctions.isNull(new RObject(this.getRInterface(), geneListsAccessor)))
{
// there is no slot for the gene lists so we need to make one
this.getRInterface().evaluateCommandNoReturn(new SilentRCommand(
geneListsAccessor + " <- list()"));
}
String currListAccessor = geneListsAccessor + '$' + listName;
String geneVectorStr = RUtilities.stringListToRVector(genes);
this.getRInterface().evaluateCommand(new SilentRCommand(
currListAccessor + " <- " + geneVectorStr));
}
/**
* Add the given genes to a list name
* @param listName the list name to add to
* @param genes the genes
*/
public void addToGeneListNamed(String listName, List<String> genes)
{
Set<String> geneListSet = new HashSet<String>(
Arrays.asList(this.getGeneListNamed(listName)));
geneListSet.addAll(genes);
List<String> newGeneList = new ArrayList<String>(geneListSet);
Collections.sort(newGeneList);
this.putGeneListNamed(listName, newGeneList);
}
/**
* Removes the list with the given name
* @param listName the name
*/
public void removeGeneListNamed(String listName)
{
String geneListsAccessor =
this.getAccessorExpressionString() + GENE_LISTS_COMPONENT;
RCommand assignNullCommand = new SilentRCommand(new RAssignmentCommand(
geneListsAccessor + '$' + listName,
"NULL"));
this.getRInterface().evaluateCommandNoReturn(assignNullCommand);
}
/**
* Getter for the design
* @return the design of this microarray experiment
*/
public MicroarrayExperimentDesign getDesign()
{
return new MicroarrayExperimentDesign(
this.getRInterface(),
this.getAccessorExpressionString() + "$design");
}
/**
* Getter for the data
* @param dyeIndex the 0-based dye index
* @param arrayIndex the 0-based array index
* @return
* the data
*/
public Double[] getData(int dyeIndex, int arrayIndex)
{
int dyeCount = this.getDyeCount();
int colIndex = arrayIndex * dyeCount + dyeIndex;
REXP yHatsExpr = this.getRInterface().evaluateCommand(new SilentRCommand(
RUtilities.columnIndexExpression(
this.getAccessorExpressionString() + DATA_COMPONENT,
colIndex)));
return JRIUtilityFunctions.extractDoubleValues(yHatsExpr);
}
/**
* Getter for the data
* @param probeIndex the 0-based array index
* @return the data
*/
public Double[] getDataRow(int probeIndex)
{
REXP yHatsExpr = this.getRInterface().evaluateCommand(new SilentRCommand(
RUtilities.rowIndexExpression(
this.getAccessorExpressionString() + DATA_COMPONENT,
probeIndex)));
return JRIUtilityFunctions.extractDoubleValues(yHatsExpr);
}
/**
* Getter for the {@link FitMaanovaResult}s that belong to this
* experiment
* @return
* the {@link FitMaanovaResult}s
*/
public Set<FitMaanovaResult> getFitMaanovaResults()
{
List<RObject> fitMaanovaRObjects = FitMaanovaResult.getAllFitRObjects(
this.getRInterface());
this.removeObjectsNotOwnedByThis(fitMaanovaRObjects);
Set<FitMaanovaResult> fitMaanovaResults =
new HashSet<FitMaanovaResult>(fitMaanovaRObjects.size());
for(RObject fitRObject: fitMaanovaRObjects)
{
fitMaanovaResults.add(new FitMaanovaResult(
this,
fitRObject.getAccessorExpressionString()));
}
return fitMaanovaResults;
}
/**
* Getter for the {@link MaanovaTestResult}s that belong to this experiment
* @return
* the {@link MaanovaTestResult}s
*/
public Set<MaanovaTestResult> getMaanovaTestResults()
{
List<RObject> maanovaTestRObjects = MaanovaTestResult.getAllMaanovaTestRObjects(
this.getRInterface());
this.removeObjectsNotOwnedByThis(maanovaTestRObjects);
Set<MaanovaTestResult> maanovaTestResults =
new HashSet<MaanovaTestResult>(maanovaTestRObjects.size());
for(RObject testRObject: maanovaTestRObjects)
{
maanovaTestResults.add(new MaanovaTestResult(
this,
testRObject.getAccessorExpressionString()));
}
return maanovaTestResults;
}
/**
* Getter for the dye count
* @return
* the dye count
*/
public int getDyeCount()
{
String dyeCountAccessor =
this.getAccessorExpressionString() + DYE_COUNT_COMPONENT;
REXP dyeCountExpr = this.getRInterface().evaluateCommand(new SilentRCommand(
dyeCountAccessor));
if(dyeCountExpr.asInt() >= 1)
{
return dyeCountExpr.asInt();
}
else
{
// TODO this should be dyeCountExpr.asInt() but for some reason JRI
// returns 0 here even when the value is 1!! This is a disturbing
// bug and I'm not sure what the root cause is just yet
return (int)dyeCountExpr.asDouble();
}
}
/**
* Get the probeset ID at the given index
* @param probesetIndex
* the index
* @return the probeset ID string
*/
public String getProbesetId(int probesetIndex)
{
SilentRCommand probesetIdCommand = new SilentRCommand(
RUtilities.indexExpression(
this.probesetIdAccessor(),
probesetIndex));
REXP probesetIdExpr = this.getRInterface().evaluateCommand(
probesetIdCommand);
return probesetIdExpr.asString();
}
/**
* Getter for all probeset IDs
* @return the probeset IDs
*/
public String[] getProbesetIds()
{
SilentRCommand probesetIdsCommand = new SilentRCommand(
this.probesetIdAccessor());
REXP probesetIdsExpr = this.getRInterface().evaluateCommand(
probesetIdsCommand);
return probesetIdsExpr.asStringArray();
}
private String probesetIdAccessor()
{
// TODO correct this in R/maanova
// the as.character is necessary because read.madata sometimes
// results in integer rather than string data
return
"as.character(" +
this.getAccessorExpressionString() + PROBESET_ID_COMPONENT +
")";
}
/**
* delete this experiment and all of its children
*/
public void delete()
{
// delete all child objects
for(String listName : this.getGeneListNames())
{
this.removeGeneListNamed(listName);
}
for(MaanovaTestResult test : this.getMaanovaTestResults())
{
test.delete();
}
for(FitMaanovaResult fitResult : this.getFitMaanovaResults())
{
fitResult.delete();
}
// delete this object
RMethodInvocationCommand rmMethod = new RMethodInvocationCommand(
"rm",
new RCommandParameter(this.getAccessorExpressionString()));
this.getRInterface().evaluateCommandNoReturn(rmMethod);
}
}