JAL-2629 add simple jackhmmer functionality
authortva <tva@10.205.251.175>
Tue, 2 Jul 2019 09:30:46 +0000 (10:30 +0100)
committertva <tva@10.205.251.175>
Tue, 2 Jul 2019 09:30:46 +0000 (10:30 +0100)
resources/lang/Messages.properties
src/jalview/datamodel/HiddenMarkovModel.java
src/jalview/gui/AlignFrame.java
src/jalview/hmmer/HMMAlign.java
src/jalview/hmmer/HMMERParamStore.java
src/jalview/hmmer/HMMSearch.java
src/jalview/hmmer/HmmerCommand.java
src/jalview/hmmer/JackHMMER.java [new file with mode: 0644]
src/jalview/io/StockholmFile.java
src/jalview/jbgui/GAlignFrame.java

index 33395d2..9fe5615 100644 (file)
@@ -1130,7 +1130,7 @@ status.opening_file_for = opening file for
 status.colouring_chimera = Colouring Chimera
 status.running_hmmbuild = Building Hidden Markov Model
 status.running_hmmalign = Creating alignment with Hidden Markov Model
-status.running_hmmsearch = Searching for matching sequences
+status.running_search = Searching for matching sequences
 label.font_doesnt_have_letters_defined = Font doesn't have letters defined\nso cannot be used\nwith alignment data
 label.font_too_small = Font size is too small
 label.error_loading_file_params = Error loading file {0}
@@ -1348,8 +1348,10 @@ label.cached_structures = Cached Structures
 label.free_text_search = Free Text Search
 label.hmmalign = hmmalign
 label.use_hmm = HMM profile to use
+label.use_sequence = Sequence to use
 label.hmmbuild = hmmbuild
 label.hmmsearch = hmmsearch
+label.jackhmmer = jackhmmer
 label.installation = Installation
 label.hmmer_location = HMMER Binaries Installation Location
 label.cygwin_location = Cygwin Binaries Installation Location (Windows)
@@ -1367,6 +1369,7 @@ label.freq_alignment = Use alignment background frequencies
 label.freq_uniprot = Use Uniprot background frequencies
 label.hmmalign_options = hmmalign options
 label.hmmsearch_options = hmmsearch options
+label.jackhmmer_options = jackhmmer options
 label.executable_not_found = The ''{0}'' executable file was not found
 warn.command_failed = {0} failed
 label.invalid_folder = Invalid Folder
@@ -1401,8 +1404,6 @@ label.groups = All groups
 label.selected_group = Selected group
 label.use_info_for_height = Use Information Content as Letter Height
 action.search = Search
-||||||| merged common ancestors
-=======
 label.backupfiles_confirm_delete = Confirm delete
 label.backupfiles_confirm_delete_old_files = Delete the following older backup files? (see the Backups tab in Preferences for more options)
 label.backupfiles_confirm_save_file = Confirm save file
index d50e66d..6b8b095 100644 (file)
@@ -667,5 +667,6 @@ public class HiddenMarkovModel
   {
     return backgroundFrequencies;
   }
+
 }
 
index 4587368..d1ebdb7 100644 (file)
@@ -69,6 +69,7 @@ import jalview.hmmer.HMMERParamStore;
 import jalview.hmmer.HMMERPreset;
 import jalview.hmmer.HMMSearch;
 import jalview.hmmer.HmmerCommand;
+import jalview.hmmer.JackHMMER;
 import jalview.io.AlignmentProperties;
 import jalview.io.AnnotationFile;
 import jalview.io.BackupFiles;
@@ -1111,6 +1112,36 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     new Thread(new HMMSearch(this, args)).start();
     alignPanel.repaint();
   }
+  
+  @Override
+  public void jackhmmer_actionPerformed(boolean withDefaults)
+  {
+    
+    /*
+     * get default parameters, and (if requested) show 
+     * dialog to allow modification
+     */
+    
+    ParamDatastoreI store = HMMERParamStore.forJackhmmer(viewport);
+    List<ArgumentI> args = store.getServiceParameters();
+
+    if (!withDefaults)
+    {
+      WsParamSetI set = new HMMERPreset();
+      WsJobParameters params = new WsJobParameters(store, set, args);
+      if (params.showRunDialog())
+      {
+        args = params.getJobParams();
+      }
+      else
+      {
+        return; // user cancelled
+      }
+    }
+    new Thread(new JackHMMER(this, args)).start();
+    alignPanel.repaint();
+    
+  }
 
   /**
    * Checks if the alignment has at least one hidden Markov model, if not shows
index 4642034..d66ec33 100644 (file)
@@ -31,8 +31,6 @@ public class HMMAlign extends HmmerCommand
 {
   static final String HMMALIGN = "hmmalign";
 
-  static final String ARG_TRIM = "--trim";
-
   private final AlignmentI dataset;
 
   /**
index 452097b..f95d738 100644 (file)
@@ -32,6 +32,8 @@ public final class HMMERParamStore implements ParamDatastoreI
 
   private static final String HMMSEARCH = "hmmsearch";
 
+  private static final String JACKHMMER = "jackhmmer";
+
   private String name;
 
   private List<WsParamSetI> presets = new ArrayList<>();
@@ -59,6 +61,11 @@ public final class HMMERParamStore implements ParamDatastoreI
     return new HMMERParamStore(HMMSEARCH, viewport);
   }
 
+  public static HMMERParamStore forJackhmmer(AlignmentViewport viewport)
+  {
+    return new HMMERParamStore(JACKHMMER, viewport);
+  }
+
   @Override
   public List<WsParamSetI> getPresets()
   {
@@ -86,6 +93,8 @@ public final class HMMERParamStore implements ParamDatastoreI
     case HMMBUILD:
       getHMMBuildParams(args);
       break;
+    case JACKHMMER:
+      getJackhmmerParams(args);
     default:
     }
 
@@ -162,6 +171,52 @@ public final class HMMERParamStore implements ParamDatastoreI
   }
 
   /**
+   * Answers default parameters for jackhmmer, taking into account any configured
+   * as user preferences
+   * 
+   * @param args
+   */
+  private void getJackhmmerParams(List<ArgumentI> args)
+  {
+
+    /*
+     * 'Parameters'
+     */
+    addChoiceOfSequence(args);
+
+    // addChoiceOfDatabase(args);
+
+    String thisAlignment = MessageManager
+            .getString(JackHMMER.THIS_ALIGNMENT_KEY);
+    String database = MessageManager.getString("label.database");
+    args.add(new RadioChoiceParameter(
+            MessageManager.getString("action.search"), null,
+            Arrays.asList(thisAlignment, database), thisAlignment));
+    args.add(new FileParameter(database, "", false, "", ""));
+    args.add(new RadioChoiceParameter(
+            MessageManager.getString(JackHMMER.REPORTING_CUTOFF_KEY), null,
+            Arrays.asList(JackHMMER.CUTOFF_NONE, JackHMMER.CUTOFF_EVALUE,
+                    JackHMMER.CUTOFF_SCORE),
+            JackHMMER.CUTOFF_EVALUE));
+    args.add(new LogarithmicParameter(
+            MessageManager.getString(JackHMMER.SEQ_EVALUE_KEY),
+            MessageManager.getString("label.seq_e_value_desc"), false, 1D,
+            1E-38, 10D));
+    args.add(new LogarithmicParameter(
+            MessageManager.getString(JackHMMER.DOM_EVALUE_KEY),
+            MessageManager.getString("label.dom_e_value_desc"), false, 1D,
+            1E-38, 10D));
+    args.add(new DoubleParameter(
+            MessageManager.getString(JackHMMER.SEQ_SCORE_KEY),
+            MessageManager.getString("label.seq_score_desc"), false, 0d, 0d,
+            1000d));
+    args.add(new DoubleParameter(
+            MessageManager.getString(JackHMMER.DOM_SCORE_KEY),
+            MessageManager.getString("label.dom_score_desc"), false, 0d, 0d,
+            1000d));
+  }
+
+  /**
    * Constructs a choice parameter for database to search; always includes 'this
    * alignment', and also includes any databases held under user preferences key
    * "HMMSEARCH_DBS" as a comma-delimited list
@@ -254,6 +309,31 @@ public final class HMMERParamStore implements ParamDatastoreI
   }
 
   /**
+   * Adds an argument representing the choice of sequence against which to perform
+   * jackhmmer
+   * 
+   * @param args
+   */
+  protected void addChoiceOfSequence(List<ArgumentI> args)
+  {
+    List<SequenceI> sequences = viewport.getAlignment().getSequences();
+
+    List<String> options = new ArrayList<>();
+
+    for (SequenceI seq : sequences)
+    {
+      options.add(seq.getName());
+    }
+
+    String defseq = options.get(0);
+    ArgumentI arg = new StringParameter(
+            MessageManager.getString("label.use_sequence"), null, true,
+            defseq,
+            defseq, options, null);
+    args.add(arg);
+  }
+
+  /**
    * Answers default parameters for hmmbuild, taking into account any configured
    * as user preferences
    * 
index 57786e5..6cbe0c8 100644 (file)
@@ -34,37 +34,6 @@ public class HMMSearch extends HmmerCommand
 {
   static final String HMMSEARCH = "hmmsearch";
 
-  /*
-   * constants for i18n lookup of passed parameter names
-   */
-  static final String DATABASE_KEY = "label.database";
-
-  static final String THIS_ALIGNMENT_KEY = "label.this_alignment";
-
-  static final String USE_ACCESSIONS_KEY = "label.use_accessions";
-
-  static final String AUTO_ALIGN_SEQS_KEY = "label.auto_align_seqs";
-
-  static final String NUMBER_OF_RESULTS_KEY = "label.number_of_results";
-
-  static final String TRIM_TERMINI_KEY = "label.trim_termini";
-
-  static final String REPORTING_CUTOFF_KEY = "label.reporting_cutoff";
-
-  static final String CUTOFF_NONE = "None";
-
-  static final String CUTOFF_SCORE = "Score";
-
-  static final String CUTOFF_EVALUE = "E-Value";
-
-  static final String SEQ_EVALUE_KEY = "label.seq_evalue";
-
-  static final String DOM_EVALUE_KEY = "label.dom_evalue";
-
-  static final String SEQ_SCORE_KEY = "label.seq_score";
-
-  static final String DOM_SCORE_KEY = "label.dom_score";
-
   boolean realign = false;
 
   boolean trim = false;
@@ -104,7 +73,7 @@ public class HMMSearch extends HmmerCommand
 
     SequenceI hmmSeq = hmm.getConsensusSequence();
     long msgId = System.currentTimeMillis();
-    af.setProgressBar(MessageManager.getString("status.running_hmmsearch"),
+    af.setProgressBar(MessageManager.getString("status.running_search"),
             msgId);
 
     try
index 20e0083..85f64bf 100644 (file)
@@ -12,6 +12,7 @@ import jalview.datamodel.SequenceI;
 import jalview.gui.AlignFrame;
 import jalview.gui.JvOptionPane;
 import jalview.gui.Preferences;
+import jalview.io.FastaFile;
 import jalview.io.HMMFile;
 import jalview.io.StockholmFile;
 import jalview.util.FileUtils;
@@ -21,6 +22,7 @@ import jalview.ws.params.ArgumentI;
 
 import java.io.BufferedReader;
 import java.io.File;
+import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.io.PrintWriter;
@@ -45,6 +47,39 @@ public abstract class HmmerCommand implements Runnable
 
   protected final List<ArgumentI> params;
 
+  /*
+   * constants for i18n lookup of passed parameter names
+   */
+  static final String DATABASE_KEY = "label.database";
+
+  static final String THIS_ALIGNMENT_KEY = "label.this_alignment";
+
+  static final String USE_ACCESSIONS_KEY = "label.use_accessions";
+
+  static final String AUTO_ALIGN_SEQS_KEY = "label.auto_align_seqs";
+
+  static final String NUMBER_OF_RESULTS_KEY = "label.number_of_results";
+
+  static final String TRIM_TERMINI_KEY = "label.trim_termini";
+
+  static final String REPORTING_CUTOFF_KEY = "label.reporting_cutoff";
+
+  static final String CUTOFF_NONE = "None";
+
+  static final String CUTOFF_SCORE = "Score";
+
+  static final String CUTOFF_EVALUE = "E-Value";
+
+  static final String SEQ_EVALUE_KEY = "label.seq_evalue";
+
+  static final String DOM_EVALUE_KEY = "label.dom_evalue";
+
+  static final String SEQ_SCORE_KEY = "label.seq_score";
+
+  static final String DOM_SCORE_KEY = "label.dom_score";
+
+  static final String ARG_TRIM = "--trim";
+
   /**
    * Constructor
    * 
@@ -248,6 +283,23 @@ public abstract class HmmerCommand implements Runnable
     writer.close();
   }
 
+  public void exportFasta(SequenceI[] seqs, File toFile)
+  {
+    FastaFile file = new FastaFile();
+    String output = file.print(seqs, false);
+    PrintWriter writer;
+    try
+    {
+      writer = new PrintWriter(toFile);
+      writer.println(output);
+      writer.close();
+    } catch (FileNotFoundException e)
+    {
+      e.printStackTrace();
+    }
+
+  }
+
   /**
    * Answers the full path to the given hmmer executable, or null if file cannot
    * be found or is not executable
@@ -292,6 +344,25 @@ public abstract class HmmerCommand implements Runnable
     }
   }
 
+  // TODO is needed?
+  /**
+   * Exports a sequence to the specified file
+   * 
+   * @param hmm
+   * @param hmmFile
+   * @throws IOException
+   */
+  public void exportSequence(SequenceI seq, File seqFile) throws IOException
+  {
+    if (seq != null)
+    {
+      FastaFile file = new FastaFile();
+      PrintWriter writer = new PrintWriter(seqFile);
+      writer.print(file.print(new SequenceI[] { seq }, false));
+      writer.close();
+    }
+  }
+
   /**
    * Answers the HMM profile for the profile sequence the user selected (default
    * is just the first HMM sequence in the alignment)
@@ -318,6 +389,29 @@ public abstract class HmmerCommand implements Runnable
   }
 
   /**
+   * Answers the HMM profile for the profile sequence the user selected (default
+   * is just the first HMM sequence in the alignment)
+   * 
+   * @return
+   */
+  protected SequenceI getSequence()
+  {
+    String alignToParamName = MessageManager
+            .getString("label.use_sequence");
+    for (ArgumentI arg : params)
+    {
+      String name = arg.getName();
+      if (name.equals(alignToParamName))
+      {
+        String seqName = arg.getValue();
+        SequenceI seq = alignment.findName(seqName);
+        return seq;
+      }
+    }
+    return null;
+  }
+
+  /**
    * Answers an absolute path to the given file, in a format suitable for
    * processing by a hmmer command. On a Windows platform, the native Windows file
    * path is converted to Cygwin format, by replacing '\'with '/' and drive letter
diff --git a/src/jalview/hmmer/JackHMMER.java b/src/jalview/hmmer/JackHMMER.java
new file mode 100644 (file)
index 0000000..85b97f9
--- /dev/null
@@ -0,0 +1,406 @@
+package jalview.hmmer;
+
+import jalview.bin.Cache;
+import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.SequenceI;
+import jalview.gui.AlignFrame;
+import jalview.gui.Desktop;
+import jalview.gui.JvOptionPane;
+import jalview.io.DataSourceType;
+import jalview.io.FileParse;
+import jalview.io.StockholmFile;
+import jalview.util.FileUtils;
+import jalview.util.MessageManager;
+import jalview.ws.params.ArgumentI;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Scanner;
+
+import javax.swing.JOptionPane;
+
+public class JackHMMER extends HmmerCommand
+{
+  static final String JACKHMMER = "jackhmmer";
+
+  boolean realign = false;
+
+  boolean trim = false;
+
+  int seqsToReturn = Integer.MAX_VALUE;
+
+  SequenceI[] seqs;
+
+  private String databaseName;
+
+  /**
+   * Constructor for the JackhmmerThread
+   * 
+   * @param af
+   */
+  public JackHMMER(AlignFrame af, List<ArgumentI> args)
+  {
+    super(af, args);
+  }
+
+  /**
+   * Runs the JackhmmerThread: the data on the alignment or group is exported,
+   * then the command is executed in the command line and then the data is
+   * imported and displayed in a new frame. Call this method directly to execute
+   * synchronously, or via start() in a new Thread for asynchronously.
+   */
+  @Override
+  public void run()
+  {
+    SequenceI seq = getSequence();
+    if (seq == null)
+    {
+      // shouldn't happen if we got this far
+      Cache.log.error("Error: no sequence for jackhmmer");
+      return;
+    }
+
+    long msgId = System.currentTimeMillis();
+    af.setProgressBar(MessageManager.getString("status.running_search"),
+            msgId);
+
+    try
+    {
+      File seqFile = FileUtils.createTempFile("seq", ".fa");
+      File hitsAlignmentFile = FileUtils.createTempFile("hitAlignment",
+              ".sto");
+      File searchOutputFile = FileUtils.createTempFile("searchOutput",
+              ".txt");
+
+      exportSequence(seq, seqFile.getAbsoluteFile());
+
+      boolean ran = runCommand(searchOutputFile, hitsAlignmentFile,
+              seqFile);
+      if (!ran)
+      {
+        JvOptionPane.showInternalMessageDialog(af, MessageManager
+                .formatMessage("warn.command_failed", "jackhmmer"));
+        return;
+      }
+
+      importData(hitsAlignmentFile, seqFile, searchOutputFile);
+      // TODO make realignment of search results a step at this level
+      // and make it conditional on this.realign
+    } catch (IOException | InterruptedException e)
+    {
+      e.printStackTrace();
+    } finally
+    {
+      af.setProgressBar("", msgId);
+    }
+  }
+
+  /**
+   * Executes an jackhmmer search with the given sequence as input. The database
+   * to be searched is a local file as specified by the 'Database' parameter, or
+   * the current alignment (written to file) if none is specified.
+   * 
+   * @param searchOutputFile
+   * @param hitsAlignmentFile
+   * @param seqFile
+   * 
+   * @return
+   * @throws IOException
+   */
+  private boolean runCommand(File searchOutputFile, File hitsAlignmentFile,
+          File seqFile) throws IOException
+  {
+    String command = getCommandPath(JACKHMMER);
+    if (command == null)
+    {
+      return false;
+    }
+
+    List<String> args = new ArrayList<>();
+    args.add(command);
+    buildArguments(args, searchOutputFile, hitsAlignmentFile, seqFile);
+
+    return runCommand(args);
+  }
+
+  /**
+   * Appends command line arguments to the given list, to specify input and output
+   * files for the search, and any additional options that may have been passed
+   * from the parameters dialog
+   * 
+   * @param args
+   * @param searchOutputFile
+   * @param hitsAlignmentFile
+   * @param seqFile
+   * @throws IOException
+   */
+  protected void buildArguments(List<String> args, File searchOutputFile,
+          File hitsAlignmentFile, File seqFile) throws IOException
+  {
+    args.add("-o");
+    args.add(getFilePath(searchOutputFile, true));
+    args.add("-A");
+    args.add(getFilePath(hitsAlignmentFile, true));
+
+    boolean dbFound = false;
+    String dbPath = "";
+    File databaseFile = null;
+
+    boolean useEvalueCutoff = false;
+    boolean useScoreCutoff = false;
+    String seqEvalueCutoff = null;
+    String domEvalueCutoff = null;
+    String seqScoreCutoff = null;
+    String domScoreCutoff = null;
+    databaseName = "Alignment";
+    boolean searchAlignment = false;
+
+    if (params != null)
+    {
+      for (ArgumentI arg : params)
+      {
+        String name = arg.getName();
+
+        if (MessageManager.getString("action.search").equals(name))
+        {
+          searchAlignment = arg.getValue().equals(
+                  MessageManager.getString(JackHMMER.THIS_ALIGNMENT_KEY));
+        }
+        else if (MessageManager.getString(DATABASE_KEY).equals(name))
+        {
+          dbPath = arg.getValue();
+          int pos = dbPath.lastIndexOf(File.separator);
+          databaseName = dbPath.substring(pos + 1);
+          databaseFile = new File(dbPath);
+        }
+        else if (MessageManager.getString(REPORTING_CUTOFF_KEY)
+                .equals(name))
+        {
+          if (CUTOFF_EVALUE.equals(arg.getValue()))
+          {
+            useEvalueCutoff = true;
+          }
+          else if (CUTOFF_SCORE.equals(arg.getValue()))
+          {
+            useScoreCutoff = true;
+          }
+        }
+        else if (MessageManager.getString(SEQ_EVALUE_KEY).equals(name))
+        {
+          seqEvalueCutoff = arg.getValue();
+        }
+        else if (MessageManager.getString(SEQ_SCORE_KEY).equals(name))
+        {
+          seqScoreCutoff = arg.getValue();
+        }
+        else if (MessageManager.getString(DOM_EVALUE_KEY).equals(name))
+        {
+          domEvalueCutoff = arg.getValue();
+        }
+        else if (MessageManager.getString(DOM_SCORE_KEY).equals(name))
+        {
+          domScoreCutoff = arg.getValue();
+        }
+        else if (MessageManager.getString(DATABASE_KEY).equals(name))
+        {
+          dbFound = true;
+          dbPath = arg.getValue();
+          if (!MessageManager.getString(THIS_ALIGNMENT_KEY).equals(dbPath))
+          {
+            int pos = dbPath.lastIndexOf(File.separator);
+            databaseName = dbPath.substring(pos + 1);
+            databaseFile = new File(dbPath);
+          }
+        }
+      }
+    }
+
+    if (useEvalueCutoff)
+    {
+      args.add("-E");
+      args.add(seqEvalueCutoff);
+      args.add("--domE");
+      args.add(domEvalueCutoff);
+    }
+    else if (useScoreCutoff)
+    {
+      args.add("-T");
+      args.add(seqScoreCutoff);
+      args.add("--domT");
+      args.add(domScoreCutoff);
+    }
+
+    // if (!dbFound || MessageManager.getString(THIS_ALIGNMENT_KEY)
+    // .equals(dbPath))
+    if (searchAlignment)
+    {
+      /*
+       * no external database specified for search, so
+       * export current alignment as 'database' to search
+       */
+      databaseFile = FileUtils.createTempFile("database", ".fa");
+      AlignmentI al = af.getViewport().getAlignment();
+      exportFasta(al.getSequencesArray(), databaseFile);
+    }
+
+    args.add(getFilePath(seqFile, true));
+    args.add(getFilePath(databaseFile, true));
+  }
+
+  /**
+   * Imports the data from the temporary file to which the output of jackhmmer was
+   * directed.
+   */
+  private void importData(File inputAlignmentTemp, File seqTemp,
+          File searchOutputFile) throws IOException, InterruptedException
+  {
+    BufferedReader br = new BufferedReader(
+            new FileReader(inputAlignmentTemp));
+    try
+    {
+      if (br.readLine() == null)
+      {
+        JOptionPane.showMessageDialog(af,
+                MessageManager.getString("label.no_sequences_found"));
+        return;
+      }
+      StockholmFile file = new StockholmFile(new FileParse(
+              inputAlignmentTemp.getAbsolutePath(), DataSourceType.FILE));
+      seqs = file.getSeqsAsArray();
+
+      readTable(searchOutputFile);
+
+      int seqCount = Math.min(seqs.length, seqsToReturn);
+
+      AlignmentI al = new Alignment(seqs);
+
+      AlignFrame alignFrame = new AlignFrame(al, AlignFrame.DEFAULT_WIDTH,
+              AlignFrame.DEFAULT_HEIGHT);
+      String ttl = "jackhmmer search of " + databaseName + " using "
+              + seqs[0].getName();
+      Desktop.addInternalFrame(alignFrame, ttl, AlignFrame.DEFAULT_WIDTH,
+              AlignFrame.DEFAULT_HEIGHT);
+
+      seqTemp.delete();
+      inputAlignmentTemp.delete();
+      searchOutputFile.delete();
+    } finally
+    {
+      if (br != null)
+      {
+        br.close();
+      }
+    }
+  }
+
+  /**
+   * Reads in the scores table output by jackhmmer and adds annotation to
+   * sequences for E-value and bit score
+   * 
+   * @param inputTableTemp
+   * @throws IOException
+   */
+  void readTable(File inputTableTemp) throws IOException
+  {
+    BufferedReader br = new BufferedReader(new FileReader(inputTableTemp));
+    String line = "";
+    while (!line.startsWith("Query:"))
+    {
+      line = br.readLine();
+    }
+    while (!line.contains("-------"))
+    {
+      line = br.readLine();
+    }
+    line = br.readLine();
+
+    int index = 0;
+    while (!"  ------ inclusion threshold ------".equals(line)
+            && !"".equals(line))
+    {
+      SequenceI seq = seqs[index];
+      AlignmentAnnotation pp = null;
+      if (seq.getAlignmentAnnotations("", "Posterior Probability")
+              .size() != 0)
+      {
+        pp = seq.getAlignmentAnnotations("", "Posterior Probability")
+                .get(0);
+      }
+      Scanner scanner = new Scanner(line);
+      String str = scanner.next();
+      str = scanner.next();
+      addScoreAnnotation(str, seq, "jackhmmer E-value",
+              "Full sequence E-value", pp);
+      str = scanner.next();
+      addScoreAnnotation(str, seq, "jackhmmer Score",
+              "Full sequence bit score", pp);
+      seq.removeAlignmentAnnotation(pp);
+      scanner.close();
+      line = br.readLine();
+      index++;
+    }
+
+    br.close();
+  }
+
+  /**
+   * A helper method that adds one score-only (non-positional) annotation to a
+   * sequence
+   * 
+   * @param value
+   * @param seq
+   * @param label
+   * @param description
+   */
+  protected void addScoreAnnotation(String value, SequenceI seq,
+          String label, String description)
+  {
+    addScoreAnnotation(value, seq, label, description, null);
+  }
+
+  /**
+   * A helper method that adds one score-only (non-positional) annotation to a
+   * sequence
+   * 
+   * @param value
+   * @param seq
+   * @param label
+   * @param description
+   * @param pp
+   *                      existing posterior probability annotation - values
+   *                      copied to new annotation row
+   */
+  protected void addScoreAnnotation(String value, SequenceI seq,
+          String label, String description, AlignmentAnnotation pp)
+  {
+    try
+    {
+      AlignmentAnnotation annot = null;
+      if (pp == null)
+      {
+        annot = new AlignmentAnnotation(label, description, null);
+      }
+      else
+      {
+        annot = new AlignmentAnnotation(pp);
+        annot.label = label;
+        annot.description = description;
+      }
+      annot.setCalcId(JACKHMMER);
+      double eValue = Double.parseDouble(value);
+      annot.setScore(eValue);
+      annot.setSequenceRef(seq);
+      seq.addAlignmentAnnotation(annot);
+    } catch (NumberFormatException e)
+    {
+      System.err.println("Error parsing " + label + " from " + value);
+    }
+  }
+
+}
index 3afb967..f7a2df2 100644 (file)
@@ -28,7 +28,6 @@ import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.Annotation;
 import jalview.datamodel.DBRefEntry;
-import jalview.datamodel.DBRefSource;
 import jalview.datamodel.Mapping;
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceFeature;
@@ -43,12 +42,10 @@ import java.io.FileReader;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Enumeration;
-import java.util.HashMap;
 import java.util.Hashtable;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.Map.Entry;
 import java.util.Vector;
 
 import com.stevesoft.pat.Regex;
@@ -1029,36 +1026,40 @@ public class StockholmFile extends AlignFile
       if (alAnot != null)
       {
         Annotation[] ann;
+
         for (int j = 0; j < alAnot.length; j++)
         {
-
-          String key = type2id(alAnot[j].label);
-          boolean isrna = alAnot[j].isValidStruc();
-
-          if (isrna)
-          {
-            // hardwire to secondary structure if there is RNA secondary
-            // structure on the annotation
-            key = "SS";
-          }
-          if (key == null)
+          if (alAnot[j].annotations != null)
           {
+            String key = type2id(alAnot[j].label);
+            boolean isrna = alAnot[j].isValidStruc();
 
-            continue;
-          }
+            if (isrna)
+            {
+              // hardwire to secondary structure if there is RNA secondary
+              // structure on the annotation
+              key = "SS";
+            }
+            if (key == null)
+            {
 
-          // out.append("#=GR ");
-          out.append(new Format("%-" + maxid + "s").form(
-                  "#=GR " + printId(s[i], jvSuffix) + " " + key + " "));
-          ann = alAnot[j].annotations;
-          String seq = "";
-          for (int k = 0; k < ann.length; k++)
-          {
-            seq += outputCharacter(key, k, isrna, ann, s[i]);
+              continue;
+            }
+
+            // out.append("#=GR ");
+            out.append(new Format("%-" + maxid + "s").form(
+                    "#=GR " + printId(s[i], jvSuffix) + " " + key + " "));
+            ann = alAnot[j].annotations;
+            String seq = "";
+            for (int k = 0; k < ann.length; k++)
+            {
+              seq += outputCharacter(key, k, isrna, ann, s[i]);
+            }
+            out.append(seq);
+            out.append(newline);
           }
-          out.append(seq);
-          out.append(newline);
         }
+
       }
 
       out.append(new Format("%-" + maxid + "s")
index c228c90..f650707 100755 (executable)
@@ -2031,6 +2031,54 @@ public class GAlignFrame extends JInternalFrame
     // hmmSearch.add(addDatabase);
 
     /*
+     * jackhmmer
+     */
+    JMenu jackhmmer = new JMenu(
+            MessageManager.getString("label.jackhmmer"));
+    JMenuItem jackhmmerSettings = new JMenuItem(
+            MessageManager.getString("label.edit_settings_and_run"));
+    jackhmmerSettings.addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        jackhmmer_actionPerformed(false);
+      }
+    });
+    JMenuItem jackhmmerRun = new JMenuItem(MessageManager.formatMessage(
+            "label.action_with_default_settings", "jackhmmer"));
+    jackhmmerRun.addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        jackhmmer_actionPerformed(true);
+      }
+
+    });
+    /*
+    JMenuItem addDatabase = new JMenuItem(
+            MessageManager.getString("label.add_database"));
+    addDatabase.addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        try
+        {
+          addDatabase_actionPerformed();
+        } catch (IOException e1)
+        {
+          e1.printStackTrace();
+        }
+      }
+    });
+    */
+    jackhmmer.add(jackhmmerRun);
+    jackhmmer.add(jackhmmerSettings);
+    // hmmSearch.add(addDatabase);
+
+    /*
      * top level menu
      */
     hmmerMenu.setText(MessageManager.getString("action.hmmer"));
@@ -2038,6 +2086,7 @@ public class GAlignFrame extends JInternalFrame
     hmmerMenu.add(hmmBuild);
     hmmerMenu.add(hmmAlign);
     hmmerMenu.add(hmmSearch);
+    hmmerMenu.add(jackhmmer);
 
   }
 
@@ -2538,6 +2587,10 @@ public class GAlignFrame extends JInternalFrame
   {
   }
 
+  protected void jackhmmer_actionPerformed(boolean b)
+  {
+  }
+
   protected void addDatabase_actionPerformed()
           throws FileFormatException, IOException
   {