JAL-2629 hmmalign now correctly creates a new frame
authorTZVanaalten <TZVanaalten@LS30916.ad.lifesci.dundee.ac.uk>
Thu, 10 Aug 2017 15:24:22 +0000 (16:24 +0100)
committerTZVanaalten <TZVanaalten@LS30916.ad.lifesci.dundee.ac.uk>
Thu, 10 Aug 2017 15:24:22 +0000 (16:24 +0100)
src/jalview/analysis/SeqsetUtils.java
src/jalview/datamodel/AlignmentOrder.java
src/jalview/datamodel/Sequence.java
src/jalview/gui/AlignFrame.java
src/jalview/gui/AlignViewport.java
src/jalview/hmmer/HMMAlignThread.java
src/jalview/hmmer/HMMBuildThread.java
src/jalview/hmmer/HMMERCommands.java
src/jalview/viewmodel/AlignmentViewport.java
src/jalview/ws/jws2/MsaWSThread.java

index 21ad1cc..329cbd8 100755 (executable)
@@ -20,6 +20,7 @@
  */
 package jalview.analysis;
 
+import jalview.datamodel.HiddenMarkovModel;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceFeature;
@@ -34,7 +35,7 @@ public class SeqsetUtils
 
   /**
    * Store essential properties of a sequence in a hashtable for later recovery
-   * Keys are Name, Start, End, SeqFeatures, PdbId
+   * Keys are Name, Start, End, SeqFeatures, PdbId, HMM
    * 
    * @param seq
    *          SequenceI
@@ -72,6 +73,10 @@ public class SeqsetUtils
               (seq.getDatasetSequence() != null) ? seq.getDatasetSequence()
                       : new Sequence("THISISAPLACEHOLDER", ""));
     }
+    if (seq.isHMMConsensusSequence())
+    {
+      sqinfo.put("HMM", seq.getHMM());
+    }
     return sqinfo;
   }
 
@@ -99,6 +104,7 @@ public class SeqsetUtils
     Vector<PDBEntry> pdbid = (Vector<PDBEntry>) sqinfo.get("PdbId");
     String description = (String) sqinfo.get("Description");
     Sequence seqds = (Sequence) sqinfo.get("datasetSequence");
+    HiddenMarkovModel hmm = (HiddenMarkovModel) sqinfo.get("HMM");
     if (oldname == null)
     {
       namePresent = false;
@@ -143,6 +149,11 @@ public class SeqsetUtils
       sq.setDatasetSequence(seqds);
     }
 
+    if (hmm != null)
+    {
+      sq.setHMM(new HiddenMarkovModel(hmm));
+      sq.setIsHMMConsensusSequence(true);
+    }
     return namePresent;
   }
 
index ccc9bfa..1ec7dd0 100755 (executable)
@@ -80,7 +80,7 @@ public class AlignmentOrder
    */
   public AlignmentOrder(AlignmentI orderFrom)
   {
-    Order = new ArrayList<SequenceI>();
+    Order = new ArrayList<>();
 
     for (SequenceI seq : orderFrom.getSequences())
     {
@@ -96,7 +96,7 @@ public class AlignmentOrder
    */
   public AlignmentOrder(SequenceI[] orderFrom)
   {
-    Order = new ArrayList<SequenceI>(Arrays.asList(orderFrom));
+    Order = new ArrayList<>(Arrays.asList(orderFrom));
   }
 
   /**
index 130af40..54fa3b0 100755 (executable)
@@ -59,7 +59,7 @@ public class Sequence extends ASequence implements SequenceI
 
   HiddenMarkovModel hmm;
 
-  boolean isHMMConsensusSequence;
+  boolean isHMMConsensusSequence = false;
 
   Vector<PDBEntry> pdbIds;
 
@@ -69,8 +69,6 @@ public class Sequence extends ASequence implements SequenceI
 
   RNA rna;
 
-  ProfilesI hinformation;
-
   /**
    * This annotation is displayed below the alignment but the positions are tied
    * to the residues of this sequence
@@ -296,6 +294,10 @@ public class Sequence extends ASequence implements SequenceI
         this.addPDBId(new PDBEntry(pdb));
       }
     }
+    if (seq.getHMM() != null)
+    {
+      this.hmm = new HiddenMarkovModel(seq.getHMM());
+    }
   }
 
   @Override
index 91529de..39dad15 100644 (file)
@@ -168,7 +168,6 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
 
   boolean autoAlignNewSequences;
 
-  boolean recurring;
 
   /*
    * The currently displayed panel (selected tabbed view if more than one)
@@ -340,11 +339,6 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     init();
   }
 
-  public void setIsRecurring(boolean status)
-  {
-    recurring = status;
-  }
-
   /**
    * initalise the alignframe from the underlying viewport data and the
    * configurations
@@ -4743,7 +4737,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
             HMMFile hmmFile = new HMMFile(new FileParse(file, sourceType));
             HiddenMarkovModel hmm = hmmFile.getHMM();
             SequenceI hmmSeq = hmm.initHMMSequence(this, 0);
-            getViewport().initInformation(hmmSeq);
+            getViewport().initInformation();
             getViewport().updateInformation(alignPanel);
             getViewport().alignmentChanged(alignPanel);
             isAnnotation = true;
@@ -4773,10 +4767,6 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
           else
           {
             new FileLoader().LoadFile(viewport, file, sourceType, format);
-            if (autoAlignNewSequences && !recurring)
-            {
-              new Thread(new HMMAlignThread(this, false)).start();
-            }
           }
         }
       }
index 6397ba9..3be48d6 100644 (file)
@@ -285,6 +285,8 @@ public class AlignViewport extends AlignmentViewport implements
       showOccupancy = Cache.getDefault(Preferences.SHOW_OCCUPANCY, true);
     }
     initAutoAnnotation();
+    initInformation();
+
     String colourProperty = alignment.isNucleotide() ? Preferences.DEFAULT_COLOUR_NUC
             : Preferences.DEFAULT_COLOUR_PROT;
     String schemeName = Cache.getProperty(colourProperty);
index 4513dfe..2674c8c 100644 (file)
@@ -3,30 +3,48 @@ package jalview.hmmer;
 import jalview.bin.Cache;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentI;
+import jalview.datamodel.AlignmentOrder;
+import jalview.datamodel.AlignmentView;
+import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.HiddenMarkovModel;
 import jalview.datamodel.SequenceI;
 import jalview.gui.AlignFrame;
 import jalview.gui.Desktop;
 import jalview.gui.Preferences;
+import jalview.gui.SplitFrame;
 import jalview.io.DataSourceType;
-import jalview.io.FileFormat;
-import jalview.io.FileLoader;
+import jalview.io.StockholmFile;
 import jalview.util.MessageManager;
+import jalview.viewmodel.seqfeatures.FeatureRendererSettings;
 
 import java.io.File;
-import java.io.FileNotFoundException;
 import java.io.IOException;
-import java.util.HashMap;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Map;
 
+import javax.swing.JInternalFrame;
+
 public class HMMAlignThread implements Runnable
 {
+
+  /**
+   * feature settings from view that job was associated with
+   */
+  protected FeatureRendererSettings featureSettings = null;
+
   HMMERCommands cmds = new HMMERCommands();
 
   AlignFrame af;
 
   AlignmentI alignment;
 
+  AlignmentI dataset;
+
+  List<AlignmentOrder> orders;
+
+  AlignmentView msa;
+
   HiddenMarkovModel hmm;
 
   boolean newFrame;
@@ -41,12 +59,21 @@ public class HMMAlignThread implements Runnable
 
   File inputTemp = null;
 
+  List<AlignmentOrder> allOrders;
+
+  SequenceI[][] allResults;
+
   public HMMAlignThread(AlignFrame af, boolean createNewFrame)
   {
     this.af = af;
     alignment = af.getViewport().getAlignment();
+    if (alignment.getDataset() != null)
+    {
+      dataset = alignment.getDataset();
+    }
     hmm = alignment.getSequenceAt(0).getHMM();
     newFrame = createNewFrame;
+    featureSettings = af.getFeatureRenderer().getSettings();
   }
 
   @Override
@@ -56,57 +83,67 @@ public class HMMAlignThread implements Runnable
     af.setProgressBar(MessageManager.getString("status.running_hmmbuild"),
             barID);
     cmds.HMMERFOLDER = Cache.getProperty(Preferences.HMMER_PATH);
-    try
-    {
-      hmmTemp = File.createTempFile("hmm", ".hmm");
-      hmmTemp.deleteOnExit();
-      outTemp = File.createTempFile("output", ".sto");
-      outTemp.deleteOnExit();
-      inputTemp = File.createTempFile("input", ".sto");
-      inputTemp.deleteOnExit();
-    } catch (IOException e1)
-    {
-      // TODO Auto-generated catch block
-      e1.printStackTrace();
-    }
 
-    try
+    // if (!alignment.isAligned())
+    // {
+    // alignment.padGaps();
+    // }
+    prepareAlignment();
+    SequenceI[][] subAlignments = msa.getVisibleContigs('-');
+    allOrders = new ArrayList<>();
+    allResults = new SequenceI[subAlignments.length][];
+    int job = 0;
+    for (SequenceI[] seqs : subAlignments)
     {
+      cmds.uniquifySequences(seqs);
       try
       {
-        hmmSeqs = alignment.getHMMConsensusSequences(true);
-        cmds.exportData(alignment, outTemp.getAbsoluteFile(), hmm,
+        createTemporaryFiles();
+      } catch (IOException e2)
+      {
+        e2.printStackTrace();
+      }
+      try
+      {
+        cmds.exportData(seqs, outTemp.getAbsoluteFile(), hmm,
                 hmmTemp.getAbsoluteFile());
-      } catch (FileNotFoundException e)
+      } catch (IOException e1)
       {
-        // TODO Auto-generated catch block
-        e.printStackTrace();
-
+        e1.printStackTrace();
       }
       try
       {
         runCommand();
       } catch (IOException | InterruptedException e)
       {
-        // TODO Auto-generated catch block
         e.printStackTrace();
       }
       try
       {
-        importData();
+        importData(job);
       } catch (IOException | InterruptedException e)
       {
         // TODO Auto-generated catch block
         e.printStackTrace();
       }
-    } catch (Exception e)
-    {
-      e.printStackTrace();
-    } finally
-    {
-      af.setProgressBar(MessageManager.getString("status.running_hmmalign"),
-              barID);
+      job++;
     }
+
+    displayResults(newFrame);
+
+    af.setProgressBar(MessageManager.getString("status.running_hmmalign"),
+            barID);
+
+  }
+
+  private void createTemporaryFiles() throws IOException
+  {
+    hmmTemp = File.createTempFile("hmm", ".hmm");
+    hmmTemp.deleteOnExit();
+    outTemp = File.createTempFile("output", ".sto");
+    outTemp.deleteOnExit();
+    inputTemp = File.createTempFile("input", ".sto");
+    inputTemp.deleteOnExit();
   }
 
   private void runCommand() throws IOException, InterruptedException
@@ -122,8 +159,20 @@ public class HMMAlignThread implements Runnable
     cmds.runCommand(command);
   }
 
-  private void importData() throws IOException, InterruptedException
+  private void importData(int index)
+          throws IOException, InterruptedException
   {
+    StockholmFile file = new StockholmFile(inputTemp.getAbsolutePath(),
+            DataSourceType.FILE);
+    SequenceI[] result = file.getSeqsAsArray();
+    AlignmentOrder msaorder = new AlignmentOrder(result);
+    // always recover the order - makes parseResult()'s life easier.
+    jalview.analysis.AlignmentSorter.recoverOrder(result);
+    jalview.analysis.SeqsetUtils.deuniquify(cmds.hash, result);
+    allOrders.add(msaorder);
+    allResults[index] = result;
+
+    /*
     if (newFrame)
     {
       FileLoader loader = new FileLoader();
@@ -134,12 +183,12 @@ public class HMMAlignThread implements Runnable
       aFrame.setTitle(
               af.getName() + "Aligned to " + hmm.getName() + "'s HMM");
       af.getViewport().setAlignment(null);
-
+    
       aFrame.loadJalviewDataFile(inputTemp.getAbsolutePath(),
               DataSourceType.FILE, FileFormat.Stockholm, null);
-
-
-
+    
+    
+    
       Map<Integer, SequenceI> copy = new HashMap<>(
               hmmSeqs);
       addSeqs(aFrame, copy);
@@ -157,6 +206,7 @@ public class HMMAlignThread implements Runnable
       af.setIsRecurring(false);
       addSeqs(af, hmmSeqs);
     }
+    */
     hmmTemp.delete();
     outTemp.delete();
     inputTemp.delete();
@@ -172,6 +222,146 @@ public class HMMAlignThread implements Runnable
     }
   }
 
+  private void prepareAlignment()
+  {
+    // hmmSeqs = alignment.getHMMConsensusSequences(true);
+    msa = af.gatherSequencesForAlignment();
+  }
+
+  private void displayResults(boolean newFrame)
+  {
+    AlignmentOrder[] arrOrders = allOrders
+            .toArray(new AlignmentOrder[allOrders.size()]);
+    Object[] newview = msa.getUpdatedView(allResults,
+            arrOrders, '-');
+    SequenceI[] alignment = (SequenceI[]) newview[0];
+    HiddenColumns hidden = (HiddenColumns) newview[1];
+    Alignment al = new Alignment(alignment);
+    al.setProperty("Alignment Program", "hmmalign");
+    if (dataset != null)
+    {
+      al.setDataset(dataset);
+    }
+
+    if (newFrame)
+    {
+      displayInNewFrame(al, allOrders, hidden);
+    }
+  }
+
+  private void displayInNewFrame(AlignmentI al,
+          List<AlignmentOrder> alorders, HiddenColumns hidden)
+  {
+    AlignFrame af = new AlignFrame(al, hidden, AlignFrame.DEFAULT_WIDTH,
+            AlignFrame.DEFAULT_HEIGHT);
+
+    // initialise with same renderer settings as in parent alignframe.
+    af.getFeatureRenderer().transferSettings(this.featureSettings);
+
+    if (allOrders.size() > 0)
+    {
+      addSortByMenuItems(af, allOrders);
+    }
+
+    // TODO: refactor retrieve and show as new splitFrame as Desktop method
+
+    /*
+     * If alignment was requested from one half of a SplitFrame, show in a
+     * SplitFrame with the other pane similarly aligned.
+     */
+    AlignFrame requestedBy = this.af;
+    if (requestedBy != null && requestedBy.getSplitViewContainer() != null
+            && requestedBy.getSplitViewContainer()
+                    .getComplement(requestedBy) != null)
+    {
+      AlignmentI complement = requestedBy.getSplitViewContainer()
+              .getComplement(requestedBy);
+      String complementTitle = requestedBy.getSplitViewContainer()
+              .getComplementTitle(requestedBy);
+      // becomes null if the alignment window was closed before the alignment
+      // job finished.
+      AlignmentI copyComplement = new Alignment(complement);
+      // todo should this be done by copy constructor?
+      copyComplement.setGapCharacter(complement.getGapCharacter());
+      // share the same dataset (and the mappings it holds)
+      copyComplement.setDataset(complement.getDataset());
+      copyComplement.alignAs(al);
+      if (copyComplement.getHeight() > 0)
+      {
+        af.setTitle(this.af.getTitle());
+        AlignFrame af2 = new AlignFrame(copyComplement,
+                AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
+        af2.setTitle(complementTitle);
+        String linkedTitle = MessageManager
+                .getString("label.linked_view_title");
+        JInternalFrame splitFrame = new SplitFrame(
+                al.isNucleotide() ? af : af2, al.isNucleotide() ? af2 : af);
+        Desktop.addInternalFrame(splitFrame, linkedTitle, -1, -1);
+        return;
+      }
+    }
+
+    /*
+     * Not from SplitFrame, or failed to created a complementary alignment
+     */
+    Desktop.addInternalFrame(af, af.getTitle(), AlignFrame.DEFAULT_WIDTH,
+            AlignFrame.DEFAULT_HEIGHT);
+  }
+
+  /**
+   * Add sort order options to the AlignFrame menus.
+   * 
+   * @param af
+   * @param alorders
+   */
+  protected void addSortByMenuItems(AlignFrame af,
+          List<AlignmentOrder> alorders)
+  {
+    // update orders
+    if (alorders.size() == 1)
+    {
+      af.addSortByOrderMenuItem("hmmalign" + " Ordering", alorders.get(0));
+    }
+    else
+    {
+      // construct a non-redundant ordering set
+      List<String> names = new ArrayList<>();
+      for (int i = 0, l = alorders.size(); i < l; i++)
+      {
+        String orderName = " Region " + i;
+        int j = i + 1;
+
+        while (j < l)
+        {
+          if (alorders.get(i).equals(alorders.get(j)))
+          {
+            alorders.remove(j);
+            l--;
+            orderName += "," + j;
+          }
+          else
+          {
+            j++;
+          }
+        }
+
+        if (i == 0 && j == 1)
+        {
+          names.add("");
+        }
+        else
+        {
+          names.add(orderName);
+        }
+      }
+      for (int i = 0, l = alorders.size(); i < l; i++)
+      {
+        af.addSortByOrderMenuItem("hmmalign" + (names.get(i)) + " Ordering",
+                alorders.get(i));
+      }
+    }
+  }
+
   }
 
 
index 2876893..c5e1816 100644 (file)
@@ -58,7 +58,11 @@ public class HMMBuildThread implements Runnable
     try
     {
         hmmSeqs = alignment.getHMMConsensusSequences(true);
-        cmds.exportData(alignment, stoTemp, null, null);
+        if (!alignment.isAligned())
+        {
+          alignment.padGaps();
+        }
+        cmds.exportData(alignment.getSequencesArray(), stoTemp, null, null);
     } catch (FileNotFoundException e)
     {
       // TODO Auto-generated catch block
index 8de3fe1..daa61cb 100644 (file)
@@ -13,7 +13,7 @@ import java.io.File;
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.io.PrintWriter;
-import java.util.List;
+import java.util.Hashtable;
 
 public class HMMERCommands
 {
@@ -45,6 +45,17 @@ public class HMMERCommands
 
   public String TRIM = "--trim ";
 
+  Hashtable hash = new Hashtable();
+
+  public void uniquifySequences(SequenceI[] seqs)
+  {
+    hash = jalview.analysis.SeqsetUtils.uniquify(seqs, true);
+  }
+
+  public void recoverSequenceNames(SequenceI[] seqs)
+  {
+    jalview.analysis.SeqsetUtils.deuniquify(hash, seqs);
+  }
 
   /**
    * Runs a command in the terminal.
@@ -89,21 +100,14 @@ public class HMMERCommands
    * @param alignment
    * @throws IOException
    */
-  public void exportData(AlignmentI alignment,
+  public void exportData(SequenceI[] seqs,
           File stoLocation, HiddenMarkovModel hmm, File hmmLocation)
           throws IOException
   {
-    if (alignment != null)
+    if (seqs != null)
     {
-      if (!alignment.isAligned())
-      {
-        alignment.padGaps();
-      }
-      List<SequenceI> list = alignment.getSequences();
-      SequenceI[] array = new SequenceI[list.size()];
-      list.toArray(array);
-      StockholmFile file = new StockholmFile(new Alignment(array));
-      file.setSeqs(array);
+      StockholmFile file = new StockholmFile(new Alignment(seqs));
+      file.setSeqs(seqs);
       String output = file.print();
       PrintWriter writer = new PrintWriter(stoLocation);
       writer.println(output);
index 96a35f9..ee129db 100644 (file)
@@ -2111,21 +2111,26 @@ public abstract class AlignmentViewport
     }
   }
 
-  public void initInformation(SequenceI hmmSequence)
-  {
-    AlignmentAnnotation information;
-    information = new AlignmentAnnotation(hmmSequence.getName(),
-            MessageManager.getString("label.information_description"),
-            new Annotation[1], 0f, 6.52f, AlignmentAnnotation.BAR_GRAPH);
-    information.hasText = true;
-    information.autoCalculated = true;
-    information.hasText = true;
-    information.autoCalculated = false;
-    information.sequenceRef = hmmSequence;
-    information.setCalcId("HMM annotation");
-    this.information.add(information);
-    hinformation.add(new Profiles(new ProfileI[1]));
-    alignment.addAnnotation(information);
+  public void initInformation()
+  {
+    for (SequenceI seq : alignment.getHMMConsensusSequences())
+    {
+      AlignmentAnnotation information;
+      information = new AlignmentAnnotation(seq.getName(),
+              MessageManager.getString("label.information_description"),
+              new Annotation[1], 0f, 6.52f, AlignmentAnnotation.BAR_GRAPH);
+      information.hasText = true;
+      information.autoCalculated = true;
+      information.hasText = true;
+      information.autoCalculated = false;
+      information.sequenceRef = seq;
+      information.setCalcId("HMM annotation");
+      this.information.add(information);
+      hinformation.add(new Profiles(new ProfileI[1]));
+      alignment.addAnnotation(information);
+      seq.updateHMMMapping();
+    }
+
   }
 
   // these should be extracted from the view model - style and settings for
index 2187f46..e88a135 100644 (file)
@@ -75,7 +75,7 @@ class MsaWSThread extends AWS2Thread implements WSClientI
     /**
      * input
      */
-    ArrayList<compbio.data.sequence.FastaSequence> seqs = new ArrayList<compbio.data.sequence.FastaSequence>();
+    ArrayList<compbio.data.sequence.FastaSequence> seqs = new ArrayList<>();
 
     /**
      * output
@@ -140,7 +140,6 @@ class MsaWSThread extends AWS2Thread implements WSClientI
       compbio.data.sequence.FastaSequence seq;
       for (int i = 0, n = 0; i < seqs.length; i++)
       {
-
         String newname = jalview.analysis.SeqsetUtils.unique_name(i); // same
         // for
         // any
@@ -381,7 +380,7 @@ class MsaWSThread extends AWS2Thread implements WSClientI
 
     public List<Argument> getJabaArguments()
     {
-      List<Argument> newargs = new ArrayList<Argument>();
+      List<Argument> newargs = new ArrayList<>();
       if (preset != null && preset instanceof JabaWsParamSet)
       {
         newargs.addAll(((JabaWsParamSet) preset).getjabaArguments());
@@ -930,7 +929,7 @@ class MsaWSThread extends AWS2Thread implements WSClientI
   void displayResults(boolean newFrame)
   {
     // view input or result data for each block
-    List<AlignmentOrder> alorders = new ArrayList<AlignmentOrder>();
+    List<AlignmentOrder> alorders = new ArrayList<>();
     SequenceI[][] results = new SequenceI[jobs.length][];
     AlignmentOrder[] orders = new AlignmentOrder[jobs.length];
     String lastProgram = null;
@@ -980,7 +979,6 @@ class MsaWSThread extends AWS2Thread implements WSClientI
     if (newFrame)
     {
       displayInNewFrame(al, alorders, hidden);
-
     }
     else
     {
@@ -1077,7 +1075,7 @@ class MsaWSThread extends AWS2Thread implements WSClientI
     else
     {
       // construct a non-redundant ordering set
-      List<String> names = new ArrayList<String>();
+      List<String> names = new ArrayList<>();
       for (int i = 0, l = alorders.size(); i < l; i++)
       {
         String orderName = " Region " + i;