From ea115fc4decf24137e52aaeee36713e9d5f3a743 Mon Sep 17 00:00:00 2001 From: TZVanaalten Date: Thu, 10 Aug 2017 16:24:22 +0100 Subject: [PATCH] JAL-2629 hmmalign now correctly creates a new frame --- src/jalview/analysis/SeqsetUtils.java | 13 +- src/jalview/datamodel/AlignmentOrder.java | 4 +- src/jalview/datamodel/Sequence.java | 8 +- src/jalview/gui/AlignFrame.java | 12 +- src/jalview/gui/AlignViewport.java | 2 + src/jalview/hmmer/HMMAlignThread.java | 266 ++++++++++++++++++++++---- src/jalview/hmmer/HMMBuildThread.java | 6 +- src/jalview/hmmer/HMMERCommands.java | 28 +-- src/jalview/viewmodel/AlignmentViewport.java | 35 ++-- src/jalview/ws/jws2/MsaWSThread.java | 10 +- 10 files changed, 295 insertions(+), 89 deletions(-) diff --git a/src/jalview/analysis/SeqsetUtils.java b/src/jalview/analysis/SeqsetUtils.java index 21ad1cc..329cbd8 100755 --- a/src/jalview/analysis/SeqsetUtils.java +++ b/src/jalview/analysis/SeqsetUtils.java @@ -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 pdbid = (Vector) 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; } diff --git a/src/jalview/datamodel/AlignmentOrder.java b/src/jalview/datamodel/AlignmentOrder.java index ccc9bfa..1ec7dd0 100755 --- a/src/jalview/datamodel/AlignmentOrder.java +++ b/src/jalview/datamodel/AlignmentOrder.java @@ -80,7 +80,7 @@ public class AlignmentOrder */ public AlignmentOrder(AlignmentI orderFrom) { - Order = new ArrayList(); + Order = new ArrayList<>(); for (SequenceI seq : orderFrom.getSequences()) { @@ -96,7 +96,7 @@ public class AlignmentOrder */ public AlignmentOrder(SequenceI[] orderFrom) { - Order = new ArrayList(Arrays.asList(orderFrom)); + Order = new ArrayList<>(Arrays.asList(orderFrom)); } /** diff --git a/src/jalview/datamodel/Sequence.java b/src/jalview/datamodel/Sequence.java index 130af40..54fa3b0 100755 --- a/src/jalview/datamodel/Sequence.java +++ b/src/jalview/datamodel/Sequence.java @@ -59,7 +59,7 @@ public class Sequence extends ASequence implements SequenceI HiddenMarkovModel hmm; - boolean isHMMConsensusSequence; + boolean isHMMConsensusSequence = false; Vector 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 diff --git a/src/jalview/gui/AlignFrame.java b/src/jalview/gui/AlignFrame.java index 91529de..39dad15 100644 --- a/src/jalview/gui/AlignFrame.java +++ b/src/jalview/gui/AlignFrame.java @@ -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(); - } } } } diff --git a/src/jalview/gui/AlignViewport.java b/src/jalview/gui/AlignViewport.java index 6397ba9..3be48d6 100644 --- a/src/jalview/gui/AlignViewport.java +++ b/src/jalview/gui/AlignViewport.java @@ -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); diff --git a/src/jalview/hmmer/HMMAlignThread.java b/src/jalview/hmmer/HMMAlignThread.java index 4513dfe..2674c8c 100644 --- a/src/jalview/hmmer/HMMAlignThread.java +++ b/src/jalview/hmmer/HMMAlignThread.java @@ -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 orders; + + AlignmentView msa; + HiddenMarkovModel hmm; boolean newFrame; @@ -41,12 +59,21 @@ public class HMMAlignThread implements Runnable File inputTemp = null; + List 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 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 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 alorders) + { + // update orders + if (alorders.size() == 1) + { + af.addSortByOrderMenuItem("hmmalign" + " Ordering", alorders.get(0)); + } + else + { + // construct a non-redundant ordering set + List 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)); + } + } + } + } diff --git a/src/jalview/hmmer/HMMBuildThread.java b/src/jalview/hmmer/HMMBuildThread.java index 2876893..c5e1816 100644 --- a/src/jalview/hmmer/HMMBuildThread.java +++ b/src/jalview/hmmer/HMMBuildThread.java @@ -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 diff --git a/src/jalview/hmmer/HMMERCommands.java b/src/jalview/hmmer/HMMERCommands.java index 8de3fe1..daa61cb 100644 --- a/src/jalview/hmmer/HMMERCommands.java +++ b/src/jalview/hmmer/HMMERCommands.java @@ -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 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); diff --git a/src/jalview/viewmodel/AlignmentViewport.java b/src/jalview/viewmodel/AlignmentViewport.java index 96a35f9..ee129db 100644 --- a/src/jalview/viewmodel/AlignmentViewport.java +++ b/src/jalview/viewmodel/AlignmentViewport.java @@ -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 diff --git a/src/jalview/ws/jws2/MsaWSThread.java b/src/jalview/ws/jws2/MsaWSThread.java index 2187f46..e88a135 100644 --- a/src/jalview/ws/jws2/MsaWSThread.java +++ b/src/jalview/ws/jws2/MsaWSThread.java @@ -75,7 +75,7 @@ class MsaWSThread extends AWS2Thread implements WSClientI /** * input */ - ArrayList seqs = new ArrayList(); + ArrayList 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 getJabaArguments() { - List newargs = new ArrayList(); + List 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 alorders = new ArrayList(); + List 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 names = new ArrayList(); + List names = new ArrayList<>(); for (int i = 0, l = alorders.size(); i < l; i++) { String orderName = " Region " + i; -- 1.7.10.2