From 1beac3545a78d4c5c3274dbb53296708d693efe0 Mon Sep 17 00:00:00 2001 From: tva Date: Tue, 2 Jul 2019 10:30:46 +0100 Subject: [PATCH] JAL-2629 add simple jackhmmer functionality --- resources/lang/Messages.properties | 7 +- src/jalview/datamodel/HiddenMarkovModel.java | 1 + src/jalview/gui/AlignFrame.java | 31 ++ src/jalview/hmmer/HMMAlign.java | 2 - src/jalview/hmmer/HMMERParamStore.java | 80 +++++ src/jalview/hmmer/HMMSearch.java | 33 +-- src/jalview/hmmer/HmmerCommand.java | 94 ++++++ src/jalview/hmmer/JackHMMER.java | 406 ++++++++++++++++++++++++++ src/jalview/io/StockholmFile.java | 53 ++-- src/jalview/jbgui/GAlignFrame.java | 53 ++++ 10 files changed, 697 insertions(+), 63 deletions(-) create mode 100644 src/jalview/hmmer/JackHMMER.java diff --git a/resources/lang/Messages.properties b/resources/lang/Messages.properties index 33395d2..9fe5615 100644 --- a/resources/lang/Messages.properties +++ b/resources/lang/Messages.properties @@ -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 diff --git a/src/jalview/datamodel/HiddenMarkovModel.java b/src/jalview/datamodel/HiddenMarkovModel.java index d50e66d..6b8b095 100644 --- a/src/jalview/datamodel/HiddenMarkovModel.java +++ b/src/jalview/datamodel/HiddenMarkovModel.java @@ -667,5 +667,6 @@ public class HiddenMarkovModel { return backgroundFrequencies; } + } diff --git a/src/jalview/gui/AlignFrame.java b/src/jalview/gui/AlignFrame.java index 4587368..d1ebdb7 100644 --- a/src/jalview/gui/AlignFrame.java +++ b/src/jalview/gui/AlignFrame.java @@ -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 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 diff --git a/src/jalview/hmmer/HMMAlign.java b/src/jalview/hmmer/HMMAlign.java index 4642034..d66ec33 100644 --- a/src/jalview/hmmer/HMMAlign.java +++ b/src/jalview/hmmer/HMMAlign.java @@ -31,8 +31,6 @@ public class HMMAlign extends HmmerCommand { static final String HMMALIGN = "hmmalign"; - static final String ARG_TRIM = "--trim"; - private final AlignmentI dataset; /** diff --git a/src/jalview/hmmer/HMMERParamStore.java b/src/jalview/hmmer/HMMERParamStore.java index 452097b..f95d738 100644 --- a/src/jalview/hmmer/HMMERParamStore.java +++ b/src/jalview/hmmer/HMMERParamStore.java @@ -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 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 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 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 args) + { + List sequences = viewport.getAlignment().getSequences(); + + List 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 * diff --git a/src/jalview/hmmer/HMMSearch.java b/src/jalview/hmmer/HMMSearch.java index 57786e5..6cbe0c8 100644 --- a/src/jalview/hmmer/HMMSearch.java +++ b/src/jalview/hmmer/HMMSearch.java @@ -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 diff --git a/src/jalview/hmmer/HmmerCommand.java b/src/jalview/hmmer/HmmerCommand.java index 20e0083..85f64bf 100644 --- a/src/jalview/hmmer/HmmerCommand.java +++ b/src/jalview/hmmer/HmmerCommand.java @@ -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 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 index 0000000..85b97f9 --- /dev/null +++ b/src/jalview/hmmer/JackHMMER.java @@ -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 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 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 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); + } + } + +} diff --git a/src/jalview/io/StockholmFile.java b/src/jalview/io/StockholmFile.java index 3afb967..f7a2df2 100644 --- a/src/jalview/io/StockholmFile.java +++ b/src/jalview/io/StockholmFile.java @@ -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") diff --git a/src/jalview/jbgui/GAlignFrame.java b/src/jalview/jbgui/GAlignFrame.java index c228c90..f650707 100755 --- a/src/jalview/jbgui/GAlignFrame.java +++ b/src/jalview/jbgui/GAlignFrame.java @@ -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 { -- 1.7.10.2