/* Date: February 2, 2010
* Template: PluginScreenJavaTemplateGen.java.ftl
* generator: org.molgenis.generators.ui.PluginScreenJavaTemplateGen 3.3.2-testing
*
* THIS FILE IS A TEMPLATE. PLEASE EDIT :-)
*/
package plugins.qtlfinder2;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import matrix.DataMatrixInstance;
import matrix.general.DataMatrixHandler;
import org.molgenis.data.Data;
import org.molgenis.framework.db.Database;
import org.molgenis.framework.db.DatabaseException;
import org.molgenis.framework.db.QueryRule;
import org.molgenis.framework.db.QueryRule.Operator;
import org.molgenis.framework.ui.PluginModel;
import org.molgenis.framework.ui.ScreenController;
import org.molgenis.framework.ui.ScreenMessage;
import org.molgenis.model.elements.Field;
import org.molgenis.pheno.ObservableFeature;
import org.molgenis.pheno.ObservationElement;
import org.molgenis.pheno.ObservationTarget;
import org.molgenis.util.Entity;
import org.molgenis.util.Tuple;
import org.molgenis.xgap.Chromosome;
import org.molgenis.xgap.Gene;
import org.molgenis.xgap.Locus;
import org.molgenis.xgap.Marker;
import org.molgenis.xgap.Probe;
import plugins.qtlfinder.QTLInfo;
import plugins.qtlfinder.QTLMultiPlotResult;
import plugins.reportbuilder.Report;
import plugins.reportbuilder.ReportBuilder;
import plugins.reportbuilder.Statistics;
import plugins.rplot.MakeRPlot;
import app.JDBCMetaDatabase;
public class QtlFinder2 extends PluginModel<Entity>
{
private static final long serialVersionUID = 1L;
private QtlFinderModel2 model = new QtlFinderModel2();
static String __ALL__DATATYPES__SEARCH__KEY = "__ALL__DATATYPES__SEARCH__KEY";
private int plotWidth = 1024;
private int plotHeight = 768;
public QtlFinderModel2 getMyModel()
{
return model;
}
public QtlFinder2(String name, ScreenController<?> parent)
{
super(name, parent);
}
@Override
public String getViewName()
{
return "QtlFinder2";
}
@Override
public String getViewTemplate()
{
return "plugins/qtlfinder2/QtlFinder2.ftl";
}
public void handleRequest(Database db, Tuple request)
{
if (request.getString("__action") != null)
{
String action = request.getString("__action");
try
{
String query = request.getString("query");
this.model.setQuery(query);
String dataType = request.getString("dataTypeSelect");
this.model.setSelectedAnnotationTypeAndNr(dataType);
if (action.equals("shop"))
{
String shopMeName = request.getString("__shopMeName");
int shopMeId = request.getInt("__shopMeId");
// Entity e = db.findById(ObservationElement.class,
// shopMeId); cannot use this: problem with lists and java
// generics when load()
List<? extends Entity> input = db.find(ObservationElement.class, new QueryRule(
ObservationElement.NAME, Operator.EQUALS, shopMeName));
input = db.load((Class) ObservationElement.class, input);
this.model.getShoppingCart().put(shopMeName, input.get(0));
}
if (action.equals("unshop"))
{
String shopMeName = request.getString("__shopMeName");
this.model.getShoppingCart().remove((shopMeName));
}
if (action.equals("gotoCart"))
{
this.model.setCartView(true);
}
if (action.equals("reset"))
{
this.model.setQuery(null);
this.model.setHits(null);
this.model.setShortenedQuery(null);
this.model.setShoppingCart(null);
this.model.setMultiplot(null);
this.model.setReport(null);
this.model.setQtls(null);
this.model.setCartView(false);
this.model.setProbeToGene(null);
}
if (action.equals("gotoSearch"))
{
this.model.setCartView(false);
this.model.setMultiplot(null);
}
if (action.equals("shopAll"))
{
this.model.getShoppingCart().putAll(this.model.getHits());
}
if (action.equals("plotShoppingCart"))
{
plotFromShoppingCart(db);
StringBuilder permaLink = new StringBuilder();
for (Entity e : this.model.getShoppingCart().values())
{
permaLink.append(e.get(ObservableFeature.ID) + ",");
}
permaLink.deleteCharAt(permaLink.length() - 1);
this.model.setPermaLink(permaLink.toString());
}
if (action.equals("emptyShoppingCart"))
{
this.model.setShoppingCart(null);
}
if (action.startsWith("__entity__report__for__"))
{
this.model.setCartView(false);
String name = action.substring("__entity__report__for__".length());
QueryRule nameQuery = new QueryRule(ObservationElement.NAME, Operator.EQUALS, name);
// we expect 1 hit exactly: ObservationElement names are
// unique, and since they have already been found, it should
// exist (unless deleted in the meantime..)
ObservationElement o = db.find(ObservationElement.class, nameQuery).get(0);
String entityClassString = o.get(Field.TYPE_FIELD).toString();
Class<? extends Entity> entityClass = db.getClassForName(entityClassString);
// now get the properly typed result entity
List<? extends Entity> typedResults = db.find(entityClass, nameQuery);
Report report = ReportBuilder.makeReport(typedResults.get(0), db);
this.model.setReport(report);
List<QTLInfo> qtls = PlotHelper.createQTLReportFor(typedResults.get(0), plotWidth, plotHeight, db);
this.model.setQtls(qtls);
}
if (action.equals("search"))
{
this.model.setCartView(false);
this.model.setShortenedQuery(null);
this.model.setMultiplot(null);
this.model.setReport(null);
this.model.setQtls(null);
if (query == null)
{
throw new Exception("Please enter a search term");
}
if (query.length() > 25)
{
throw new Exception("Queries longer than 25 characters are not allowed");
}
if (query.length() < 2)
{
throw new Exception("Queries shorter than 2 characters are not allowed");
}
Class<? extends Entity> entityClass;
if (dataType.equals(__ALL__DATATYPES__SEARCH__KEY))
{
entityClass = db.getClassForName("ObservationElement"); // more
// broad
// than
// "ObservableFeature",
// but
// OK
}
else
{
entityClass = db.getClassForName(dataType);
}
Map<String, Entity> hits = query(entityClass, db, query, 100);
System.out.println("initial number of hits: " + hits.size());
hits = genesToProbes(db, 100, hits);
System.out.println("after converting genes to probes, number of hits: " + hits.size());
this.model.setHits(hits);
}
}
catch (Exception e)
{
e.printStackTrace();
this.setMessages(new ScreenMessage(e.getMessage() != null ? e.getMessage() : "null", false));
}
}
// special case: no action, but plot from
else
{
String permaLinkIds = request.getString("p");
if (permaLinkIds != null)
{
try
{
Map<String, Entity> hits = new HashMap<String, Entity>();
// special special: WormBaseID is given (only 1 for the
// moment
if (permaLinkIds.length() == "WBGene00000000".length() && permaLinkIds.startsWith("WBGene"))
{
hits = query(db.getClassForName("ObservationElement"), db, permaLinkIds, 100);
hits = genesToProbes(db, 100, hits);
}
else
{
String[] ids = permaLinkIds.split(",");
Class<? extends Entity> entityClass = db.getClassForName("ObservationElement");
List<? extends Entity> findIds = db.find(entityClass, new QueryRule(ObservationElement.ID,
Operator.IN, ids));
findIds = db.load((Class) ObservationElement.class, findIds);
for (Entity e : findIds)
{
hits.put(e.get(ObservationElement.NAME).toString(), e);
}
}
this.model.setShoppingCart(hits);
this.model.setHits(hits);
this.model.setPermaLink(permaLinkIds);
plotFromShoppingCart(db);
}
catch (Exception e)
{
e.printStackTrace();
this.setMessages(new ScreenMessage(e.getMessage() != null ? e.getMessage() : "null", false));
}
}
}
}
private Map<String, Entity> genesToProbes(Database db, int limit, Map<String, Entity> hits)
throws DatabaseException
{
// keep a list of genes for which the probes are shown to make the GO
// term info box
Map<String, Gene> probeToGene = new HashMap<String, Gene>();
// additional: include the Gene objects for the shopping cart view so
// they are not lost on next search action
// (when switching back to the shopping cart view after a new search)
// find out if there is a ProbeToGene list already:
if (this.model.getProbeToGene() != null && this.model.getProbeToGene().size() > 0)
{
// if so, iterate over shopping cart and get a (possible) probe
for (Entity e : this.model.getShoppingCart().values())
{
String probeName = e.get(ObservationElement.NAME).toString();
// if the the ProbeToGene list contains the shopping cart item
// (probe name), add it to the new ProbeToGene list
if (this.model.getProbeToGene().containsKey(probeName))
{
probeToGene.put(probeName, this.model.getProbeToGene().get(probeName));
}
}
}
Map<String, Entity> result = new HashMap<String, Entity>();
int nrOfResults = 0;
outer: for (String name : hits.keySet())
{
Entity e = hits.get(name);
// System.out.println("looking at " +
// e.get(Field.TYPE_FIELD).toString() + " " +
// e.get(ObservationElement.NAME).toString());
if (e.get(Field.TYPE_FIELD).equals("Gene"))
{
QueryRule r = new QueryRule(Probe.REPORTSFOR_NAME, Operator.EQUALS, name);
QueryRule o = new QueryRule(Operator.OR);
QueryRule s = new QueryRule(Probe.SYMBOL, Operator.EQUALS, name);
List<Probe> probes = db.find(Probe.class, r, o, s);
// System.out.println("RESULT WITH JUST REPORTSFOR: "
// +db.find(Probe.class, r).size());
// System.out.println("RESULT WITH JUST SYMBOL: "
// +db.find(Probe.class, s).size());
for (Probe p : probes)
{
result.put(p.getName(), p);
// System.out.println("GENE2PROBE SEARCH HIT: "
// +p.getName());
// store the gene hit that belongs with this probe
probeToGene.put(p.getName(), (Gene) e);
nrOfResults++;
if (nrOfResults == limit)
{
// System.out.println("breaking genesToProbes on adding probes");
break outer;
}
}
}
else
{
result.put(e.get(ObservationElement.NAME).toString(), e);
// System.out.println("GENE2PROBE ADDING ALSO: "
// +e.get(ObservationElement.NAME).toString());
nrOfResults++;
if (nrOfResults == limit)
{
// System.out.println("breaking genesToProbes on other entities");
break outer;
}
}
}
this.model.setProbeToGene(probeToGene);
return result;
}
private Map<String, Entity> query(Class entityClass, Database db, String query, int limit) throws DatabaseException
{
List<? extends Entity> result = db.search(entityClass, query);
result = db.load(entityClass, result);
if (result.size() == 0)
{
boolean noResults = true;
String shortenedQuery = query;
while (noResults && shortenedQuery.length() > 0)
{
result = db.search(entityClass, shortenedQuery);
result = db.load(entityClass, result);
if (result.size() > 0)
{
noResults = false;
this.model.setShortenedQuery(shortenedQuery);
}
shortenedQuery = shortenedQuery.substring(0, shortenedQuery.length() - 1);
}
if (noResults)
{
throw new DatabaseException("No results found");
}
}
int nrOfResults = 0;
Map<String, Entity> hits = new HashMap<String, Entity>();
for (Entity e : result)
{
hits.put(e.get(ObservationElement.NAME).toString(), e);
// System.out.println("REGULAR SEARCH HIT: " +
// e.get(ObservationElement.NAME));
nrOfResults++;
if (nrOfResults == limit)
{
break;
}
}
return hits;
}
private void plotFromShoppingCart(Database db) throws Exception
{
if (this.model.getShoppingCart().size() == 0)
{
throw new Exception("Your shopping cart is empty!");
}
else if (this.model.getShoppingCart().size() > 500)
{
throw new Exception("You cannot plot more than 500 items.");
}
this.model.setCartView(false);
QTLMultiPlotResult res = multiplot(new ArrayList<Entity>(this.model.getShoppingCart().values()), db);
this.model.setReport(null);
this.model.setMultiplot(res);
}
private QTLMultiPlotResult multiplot(List<Entity> entities, Database db) throws Exception
{
HashMap<String, Entity> matches = new HashMap<String, Entity>();
HashMap<String, Entity> datasets = new HashMap<String, Entity>();
int totalAmountOfElementsInPlot = 0;
int overallIndex = 1;
List<Data> allData = db.find(Data.class);
DataMatrixHandler dmh = new DataMatrixHandler(db);
Map<String, Chromosome> usedChromosomes = new HashMap<String, Chromosome>();
// writer for data table
File tmpData = new File(System.getProperty("java.io.tmpdir") + File.separator + "rplot_data_table_"
+ System.nanoTime() + ".txt");
File cytoscapeNetwork = new File(System.getProperty("java.io.tmpdir") + File.separator + "cyto_qtl_network_"
+ System.nanoTime() + ".txt");
File cytoscapeNodes = new File(System.getProperty("java.io.tmpdir") + File.separator + "cyto_node_attr_"
+ System.nanoTime() + ".txt");
BufferedWriter bw = new BufferedWriter(new FileWriter(tmpData));
BufferedWriter bw_network = new BufferedWriter(new FileWriter(cytoscapeNetwork));
BufferedWriter bw_nodes = new BufferedWriter(new FileWriter(cytoscapeNodes));
List<String> nodesInFile = new ArrayList<String>();
for (Data d : allData)
{
if (PlotHelper.isEffectSizeData(db, d))
{
continue;
}
// if something fails with this matrix, don't break the loop
// e.g. backend file is missing
try
{
// loop over Text data (can't be QTL)
if (d.getValueType().equals("Text"))
{
continue;
}
// check if one of the matrix dimensions if of type 'Marker'
// TODO: limited, could also be SNP or another potential
// subclass
if ((d.getTargetType().equals("Marker") || d.getFeatureType().equals("Marker")))
{
// create instance and get name of the row/col we want
DataMatrixInstance instance = dmh.createInstance(d, db);
List<String> rowNames = instance.getRowNames();
List<String> colNames = instance.getColNames();
// get the markers
List<Marker> markers = db.find(Marker.class, new QueryRule(Marker.NAME, Operator.IN, d
.getFeatureType().equals("Marker") ? colNames : rowNames));
HashMap<String, Marker> nameToMarker = new HashMap<String, Marker>();
for (Marker m : markers)
{
nameToMarker.put(m.getName(), m);
}
// for each entity, see if the types match to the matrix
for (Entity e : entities)
{
// skip markers, we are interested in traits here
if (e.get(Field.TYPE_FIELD).equals("Marker"))
{
continue;
}
// matrix may not have the trait type on rows AND
// columns (this is correlation data or so)
if (d.getTargetType().equals(e.get(Field.TYPE_FIELD))
&& d.getFeatureType().equals(e.get(Field.TYPE_FIELD)))
{
continue;
}
// one of the matrix dimensions must match the type of
// the trait
if (d.getTargetType().equals(e.get(Field.TYPE_FIELD))
|| d.getFeatureType().equals(e.get(Field.TYPE_FIELD)))
{
// if so, use this entity to 'query' the matrix and
// store the values
String name = e.get(ObservableFeature.NAME).toString();
// find out if the name is in the row or col names
int rowIndex = rowNames.indexOf(name);
int colIndex = colNames.indexOf(name);
List<String> markerNames = null;
Double[] Dvalues = null;
// if its in row, do row stuff
if (rowIndex != -1)
{
markerNames = colNames;
Dvalues = Statistics.getAsDoubles(instance.getRow(rowIndex));
}
// if its in col, and not in row, do col stuff
else if (rowIndex == -1 && colIndex != -1)
{
markerNames = rowNames;
Dvalues = Statistics.getAsDoubles(instance.getCol(colIndex));
}
else
{
// this trait is not in the matrix.. skip
continue;
}
// add entity and dataset to matches
matches.put(name, e);
datasets.put(d.getName(), d);
totalAmountOfElementsInPlot++;
// get the basepair position of the trait and
// chromosome name, if possible
long locus;
String traitChrName;
if (e instanceof Locus)
{
locus = ((Locus) e).getBpStart();
traitChrName = ((Locus) e).getChromosome_Name();
}
else
{
locus = -10000000;
traitChrName = "-";
}
// rewrite name to include label
name = e.get(ObservableFeature.NAME).toString()
+ (e.get(ObservableFeature.LABEL) != null ? "/"
+ e.get(ObservableFeature.LABEL).toString() : "");
// iterate over the markers and write out input
// files for R / CytoScape
for (int markerIndex = 0; markerIndex < markerNames.size(); markerIndex++)
{
if (nameToMarker.containsKey(markerNames.get(markerIndex)))
{
String chrId = nameToMarker.get(markerNames.get(markerIndex)).getChromosome_Id() != null ? nameToMarker
.get(markerNames.get(markerIndex)).getChromosome_Id().toString()
: "-";
// query and store chromosome objects for
// this name if it's not there yet
String chrName = nameToMarker.get(markerNames.get(markerIndex))
.getChromosome_Name();
if (!usedChromosomes.containsKey(chrName))
{
Chromosome c = db.find(Chromosome.class,
new QueryRule(Chromosome.NAME, Operator.EQUALS, chrName)).get(0);
usedChromosomes.put(chrName, c);
}
// index, marker, chrId, markerLoc, trait,
// traitLoc, LODscore, dataId
bw.write(overallIndex + " \"" + markerNames.get(markerIndex) + "\" " + chrId + " "
+ nameToMarker.get(markerNames.get(markerIndex)).getBpStart() + " \""
+ name + "\" " + locus + " " + Dvalues[markerIndex] + " " + d.getId());
bw.newLine();
if (Dvalues[markerIndex].doubleValue() > 3.5)
{
// trait, "QTL", marker, LODscore
bw_network.write(name + "\t" + "QTL" + "\t" + markerNames.get(markerIndex)
+ "\t" + Dvalues[markerIndex]);
bw_network.newLine();
String marker_chrName = nameToMarker.get(markerNames.get(markerIndex))
.getChromosome_Name() != null ? nameToMarker.get(
markerNames.get(markerIndex)).getChromosome_Name() : "-";
if (!nodesInFile.contains(name))
{
// trait, traitChr, traitLocus,
// dataName
bw_nodes.write(name + "\t" + "trait" + "\t" + traitChrName + "\t" + locus
+ "\t" + d.getName());
bw_nodes.newLine();
nodesInFile.add(name);
}
if (!nodesInFile.contains(markerNames.get(markerIndex)))
{
// marker, markerChr, markerLocus,
// dataName
bw_nodes.write(markerNames.get(markerIndex) + "\t" + "marker" + "\t"
+ marker_chrName + "\t"
+ nameToMarker.get(markerNames.get(markerIndex)).getBpStart()
+ "\t" + d.getName());
bw_nodes.newLine();
nodesInFile.add(markerNames.get(markerIndex));
}
}
overallIndex++;
}
}
}
}
}
}
catch (Exception e)
{
e.printStackTrace();
// too bad, data matrix failed
}
}
bw.close();
bw_network.close();
bw_nodes.close();
int height = 200 + (totalAmountOfElementsInPlot * 20);
// add chromosomes in strict order, starting at 1
ArrayList<Chromosome> chromosomes = new ArrayList<Chromosome>();
for (int orderNrIter = 1; orderNrIter <= usedChromosomes.size(); orderNrIter++)
{
for (Chromosome c : usedChromosomes.values())
{
if (c.getOrderNr().intValue() == orderNrIter)
{
chromosomes.add(c);
continue;
}
}
}
MakeRPlot m = new MakeRPlot();
String plotTitle = "hits"; // this.model.getQuery()
File plot = m.wormqtl_MultiPlot(tmpData, plotWidth, height, plotTitle, chromosomes);
File cisTransplot = m.wormqtl_CisTransPlot(tmpData, plotWidth, plotHeight, plotTitle, chromosomes);
File regularPlot = m.wormqtl_ProfilePlot(tmpData, plotWidth, height, plotTitle, chromosomes);
QTLMultiPlotResult result = new QTLMultiPlotResult();
result.setSrcData(tmpData.getName());
result.setCytoNetwork(cytoscapeNetwork.getName());
result.setCytoNodes(cytoscapeNodes.getName());
result.setPlot(plot.getName());
result.setRegularPlot(regularPlot.getName());
result.setCisTransPlot(cisTransplot.getName());
result.setMatches(matches);
result.setDatasets(datasets);
return result;
}
@Override
public void reload(Database db)
{
try
{
if (model.getShoppingCart() == null)
{
Map<String, Entity> shoppingCart = new HashMap<String, Entity>();
this.model.setShoppingCart(shoppingCart);
}
if (this.model.getCartView() == null)
{
this.model.setCartView(false);
}
if (model.getAnnotationTypeAndNr() == null)
{
int totalAmount = 0;
JDBCMetaDatabase metadb = new JDBCMetaDatabase();
Map<String, Integer> annotationTypeAndNr = new HashMap<String, Integer>();
Vector<org.molgenis.model.elements.Entity> entityList = metadb.getEntities();
// iterate over all entity types
for (org.molgenis.model.elements.Entity entityType : entityList)
{
// get the ancestors for one such entity
for (org.molgenis.model.elements.Entity e : entityType.getAllAncestors())
{
// if one of the ancestors is ObservationElement..
if (e.getName().equals(ObservationElement.class.getSimpleName()))
{
Class<? extends Entity> entityClass = db.getClassForName(entityType.getName());
// and the class is not ObservableFeature or
// ObservationTarget..
if (!entityClass.getSimpleName().equals(ObservableFeature.class.getSimpleName())
&& !entityClass.getSimpleName().equals(ObservationTarget.class.getSimpleName()))
{
// count the number of entities in the database
int count = db.count(entityClass);
if (count > 0)
{
annotationTypeAndNr.put(entityType.getName(), count);
totalAmount += count;
}
}
break;
}
}
}
annotationTypeAndNr.put(__ALL__DATATYPES__SEARCH__KEY, totalAmount);
model.setAnnotationTypeAndNr(annotationTypeAndNr);
}
}
catch (Exception e)
{
e.printStackTrace();
this.setMessages(new ScreenMessage(e.getMessage() != null ? e.getMessage() : "null", false));
}
}
@Override
public String getCustomHtmlHeaders()
{
return "<link rel=\"stylesheet\" style=\"text/css\" href=\"clusterdemo/qtlfinder.css\">" + "\n"
+ "<script type=\"text/javascript\" src=\"etc/js/clear-default-text.js\"></script>";
}
}