JAL-3070 detect presence of existing JABA RNAAliFold client
[jalview.git] / src / jalview / ws / ebi / HmmerJSONProcessor.java
index 4d30b3b..428c498 100644 (file)
@@ -2,10 +2,18 @@ package jalview.ws.ebi;
 
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
+import jalview.datamodel.Annotation;
+import jalview.datamodel.SequenceFeature;
+import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
 import jalview.io.FileParse;
+import jalview.viewmodel.AlignmentViewport;
 
 import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
 import org.json.simple.JSONArray;
 import org.json.simple.JSONObject;
@@ -13,8 +21,16 @@ import org.json.simple.parser.JSONParser;
 
 public class HmmerJSONProcessor
 {
+  /**
+   * result to be annotated. may not be null
+   */
   AlignmentI resultAl;
 
+  /**
+   * viewport on the alignment. may be null at construction time
+   */
+  AlignmentViewport viewAl = null;
+
   public HmmerJSONProcessor(AlignmentI searchResult)
   {
     resultAl = searchResult;
@@ -123,30 +139,193 @@ public class HmmerJSONProcessor
     double evalue = Double.valueOf("" + hmmrhit.get("evalue"));
     for (Object domainhit : ((JSONArray) hmmrhit.get("domains")))
     {
-      JSONObject dhit=(JSONObject) domainhit;
+      JSONObject dhit = (JSONObject) domainhit;
       // dhit.get(key)
 
       // alihmmfrom,alihmmto alimodel
+      long alihmmfrom = (long) dhit.get("alihmmfrom"), alihmmto = (long) dhit
+              .get("alihmmto"), alisqfrom = (long) dhit.get("alisqfrom"), alisqto = (long) dhit
+              .get("alisqto");
+
       // alisqfrom,alisqto,aliaseq
+
       // alippline
-      // 
+      String aliaseq = (String) dhit.get("aliaseq"), alimodel = (String) dhit
+              .get("alimodel"), ppline = (String) dhit.get("alippline");
+      //
+      int found = 0;
+      SequenceI firsthit = null;
       for (SequenceI hitseq : hits)
       {
         // match alisqfrom,alisqto,seq
-        // overlay ppline as seqannotation
-        // ievalue
-        // cevalue
-        // 
-
-        AlignmentAnnotation pval = new AlignmentAnnotation("p-value",
-                "hmmer3 pvalue", pvalue);
-        AlignmentAnnotation eval = new AlignmentAnnotation("e-value",
-                "hmmer3 evalue", evalue);
-        hitseq.addAlignmentAnnotation(pval);
-        hitseq.addAlignmentAnnotation(eval);
-        
+        if (hitseq.getStart() == alisqfrom && hitseq.getEnd() == alisqto)
+        {
+          if (found == 0)
+          {
+            firsthit = hitseq;
+          }
+          found++; // annotated a sequence
+          AlignmentAnnotation alipp = parsePosteriorProb(ppline);
+          AlignmentAnnotation pval = new AlignmentAnnotation("p-value",
+                  "hmmer3 pvalue", pvalue);
+          AlignmentAnnotation eval = new AlignmentAnnotation("e-value",
+                  "hmmer3 evalue", evalue);
+          pval.setCalcId("HMMER3");
+          eval.setCalcId("HMMER3");
+          alipp.setCalcId("HMMER3");
+          hitseq.addAlignmentAnnotation(pval);
+          hitseq.addAlignmentAnnotation(eval);
+          alipp.createSequenceMapping(hitseq, hitseq.getStart(), false);
+          hitseq.addAlignmentAnnotation(alipp);
+          String arch;
+          hitseq.addSequenceFeature(new SequenceFeature(
+                  "Pfam Domain Architecture", (hmmrhit.get("archindex"))
+                          + " " + (arch = (String) hmmrhit.get("arch")), 0,
+                  0,
+                  (hmmrhit.get("archScore") != null ? Integer
+                          .valueOf((String) hmmrhit.get("archScore")) : 0f),
+                  "HMMER3"));
+          addArchGroup(hitseq, arch);
+          alipp.setScore(Double.valueOf("" + dhit.get("bitscore")));
+          alipp.adjustForAlignment();
+          resultAl.addAnnotation(pval);
+          resultAl.addAnnotation(eval);
+          resultAl.addAnnotation(alipp);
+          alipp.validateRangeAndDisplay();
+        }
+      }
+      // look for other sequences represented by this hit and create rep groups
+      // could be in "pdbs", or ..
+      addRedundantSeqGroup(firsthit, alisqfrom, alisqto,
+              (JSONArray) hmmrhit.get("seqs"), true);
+    }
+  }
+
+  /**
+   * series of operations to perform for the viewpanel associated with the
+   * alignment
+   */
+  private List<Runnable> viewOps = new ArrayList<Runnable>();
+
+  public void updateView(AlignmentViewport view)
+  {
+    viewAl = view;
+    for (Runnable op : viewOps)
+    {
+      op.run();
+    }
+  }
+
+  private void addRedundantSeqGroup(final SequenceI firsthit,
+          long alisqfrom, long alisqto, JSONArray others, boolean justDelete)
+  {
+    if (others != null)
+    {
+      final SequenceGroup repgroup = new SequenceGroup();
+      repgroup.setSeqrep(firsthit);
+      repgroup.addOrRemove(firsthit, false);
+      repgroup.setStartRes(0);
+      repgroup.setEndRes(resultAl.getWidth() - 1);
+      for (Object otherseq : others.toArray(new JSONObject[0]))
+      {
+        String repseq = (String) ((JSONObject) otherseq).get("dn");
+        SequenceI[] other = resultAl.findSequenceMatch(repseq);
+        if (other != null && other.length > 0)
+        {
+          if (justDelete)
+          {
+            for (SequenceI oth : other)
+            {
+              resultAl.deleteSequence(oth);
+            }
+            ;
+          }
+          else
+          {
+            int ofound = 0;
+            for (SequenceI oth : other)
+            {
+              if (oth.getStart() == alisqfrom && oth.getEnd() == alisqto)
+              {
+                ofound++;
+                repgroup.addSequence(oth, false);
+              }
+            }
+            if (ofound == 0)
+            {
+              System.err.println("Warn - no match for redundant hit "
+                      + repseq + "/" + alisqfrom + "-" + alisqto);
+            }
+            if (ofound > 1)
+            {
+              System.err
+                      .println("Warn - multiple matches for redundant hit "
+                              + repseq + "/" + alisqfrom + "-" + alisqto);
+            }
+          }
+        }
+      }
+      if (repgroup.getSequences().size() > 1)
+      {
+        // queue a hide operation
+        final HmmerJSONProcessor me = this;
+        viewOps.add(new Runnable()
+        {
+          @Override
+          public void run()
+          {
+            me.viewAl.hideRepSequences(firsthit, repgroup);
+          }
+        });
+      }
+    }
+  }
+
+  Map<String, SequenceGroup> groups = new HashMap<String, SequenceGroup>();
+
+  private void addArchGroup(SequenceI seqToAdd, String groupNam)
+  {
+    SequenceGroup sg = groups.get(groupNam);
+    if (sg == null)
+    {
+      sg = new SequenceGroup();
+      sg.setName(groupNam);
+      sg.addSequence(seqToAdd, false);
+      sg.setStartRes(0);
+      sg.setEndRes(resultAl.getWidth() - 1);
+      groups.put(groupNam, sg);
+      resultAl.addGroup(sg);
+    }
+    else
+    {
+      sg.addSequence(seqToAdd, false);
+    }
+  }
 
+  private AlignmentAnnotation parsePosteriorProb(String ppline)
+  {
+    Annotation[] ae = new Annotation[ppline.length()];
+    int spos = 0;
+    for (int i = 0, iSize = ppline.length(); i < iSize; i++)
+    {
+      char pp = ppline.charAt(i);
+      if (pp == '*')
+      {
+        ae[spos++] = new Annotation(10f);
+      }
+      else
+      {
+        if (pp >= '0' && pp <= '9')
+        {
+          ae[spos++] = new Annotation(Integer.valueOf("" + pp));
+        }
       }
     }
+    AlignmentAnnotation pprob = new AlignmentAnnotation(
+            "Posterior Probability",
+            "Likelihood of HMM fit at each hit position.", ae);
+    pprob.graph = AlignmentAnnotation.BAR_GRAPH;
+    pprob.visible = false;
+    return pprob;
   }
 }