2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
21 package jalview.ws.jws2;
23 import jalview.api.AlignCalcWorkerI;
24 import jalview.datamodel.AlignmentAnnotation;
25 import jalview.datamodel.Annotation;
26 import jalview.gui.AlignFrame;
27 import jalview.ws.jws2.jabaws2.Jws2Instance;
28 import jalview.ws.params.WsParamSetI;
29 import jalview.ws.uimodel.AlignAnalysisUIText;
31 import java.text.MessageFormat;
32 import java.util.ArrayList;
33 import java.util.LinkedHashMap;
34 import java.util.List;
35 import java.util.TreeSet;
36 import java.util.regex.Pattern;
38 import compbio.data.sequence.FastaSequence;
39 import compbio.data.sequence.RNAStructReader.AlifoldResult;
40 import compbio.data.sequence.RNAStructScoreManager;
41 import compbio.data.sequence.Range;
42 import compbio.data.sequence.Score;
43 import compbio.metadata.Argument;
44 import compbio.ws.client.Services;
47 * Client for the JABA RNA Alifold Service
49 * @author daluke - Daniel Barton
53 public class RNAalifoldClient extends JabawsCalcWorker implements
61 // keeps track of whether the RNAalifold result includes base contact
65 public RNAalifoldClient(Jws2Instance sh, AlignFrame alignFrame,
66 WsParamSetI preset, List<Argument> paramset)
68 super(sh, alignFrame, preset, paramset);
70 methodName = sh.serviceType;
73 nucleotidesAllowed = true;
74 proteinAllowed = false;
78 public String getCalcId()
83 private static String CALC_ID = "jalview.ws.jws2.RNAalifoldClient";
85 public static AlignAnalysisUIText getAlignAnalysisUITest()
87 return new AlignAnalysisUIText(
88 Services.RNAalifoldWS.toString(),
89 RNAalifoldClient.class,
94 "RNAAliFold Prediction",
95 "When checked, RNA secondary structure predictions will be calculated for the alignment, and updated when edits are made.",
96 "Change RNAAliFold settings...",
97 "Modify settings for the RNAAliFold prediction. Use this to hide or show different results of the RNA calculation, and change RNA folding parameters");
102 public String getServiceActionText()
104 return "Submitting RNA alignment for Secondary Structure prediction using "
105 + "RNAalifold Service";
109 boolean checkValidInputSeqs(boolean dynamic, List<FastaSequence> seqs)
111 return (seqs.size() > 1);
115 public void updateResultAnnotation(boolean immediate)
118 if (immediate || !calcMan.isWorking(this) && scoremanager != null)
121 List<AlignmentAnnotation> ourAnnot = new ArrayList<AlignmentAnnotation>();
123 // Unpack the ScoreManager
124 List<String> structs = ((RNAStructScoreManager) scoremanager)
126 List<TreeSet<Score>> data = ((RNAStructScoreManager) scoremanager)
129 // test to see if this data object contains base pair contacts
130 Score fscore = data.get(0).first();
131 this.bpScores = (fscore.getMethod()
132 .equals(AlifoldResult.contactProbabilities.toString()));
134 // add annotation for the consensus sequence alignment
135 createAnnotationRowforScoreHolder(ourAnnot, getCalcId(),
136 structs.get(0), null, null);
138 // Add annotations for the mfe Structure
139 createAnnotationRowforScoreHolder(ourAnnot, getCalcId(),
140 structs.get(1), data.get(1), null);
142 // decide whether to add base pair contact probability histogram
146 createAnnotationRowforScoreHolder(ourAnnot, getCalcId(),
147 structs.get(2), data.get(0), data.get(2));
151 // Now loop for the rest of the Annotations (if there it isn't stochastic
153 // only the centroid and MEA structures remain anyway)
154 for (int i = count; i < structs.size(); i++)
156 // The ensemble values should be displayed in the description of the
157 // first (or all?) Stochastic Backtrack Structures.
158 if (!data.get(i).first().getMethod()
159 .equals(AlifoldResult.ensembleValues.toString()))
162 createAnnotationRowforScoreHolder(ourAnnot, getCalcId(),
163 structs.get(i), data.get(i), null);
167 if (ourAnnot.size() > 0)
170 updateOurAnnots(ourAnnot);
171 ap.adjustAnnotationHeight();
176 protected void createAnnotationRowforScoreHolder(
177 List<AlignmentAnnotation> ourAnnot, String calcId, String struct,
178 TreeSet<Score> data, TreeSet<Score> descriptionData)
181 * If contactProbability information is returned from RNAalifold it is
182 * stored in the first TreeSet<Score> object corresponding to the String Id
183 * which holds the consensus alignment. The method enumeration is then
184 * updated to AlifoldResult.contactProbabilties. This line recreates the
185 * same data object as was overwritten with the contact probabilites data.
189 data = compbio.data.sequence.RNAStructReader
190 .newEmptyScore(AlifoldResult.consensusAlignment);
193 if (descriptionData == null)
195 descriptionData = data;
198 String[] typenameAndDescription = constructTypenameAndDescription(descriptionData
200 String typename = typenameAndDescription[0];
201 String description = typenameAndDescription[1];
203 AlignmentAnnotation annotation = alignViewport.getAlignment()
204 .findOrCreateAnnotation(typename, calcId, false, null, null);
206 constructAnnotationFromScoreHolder(annotation, struct, data);
209 * update annotation description with the free Energy, frequency in ensemble
210 * or other data where appropriate.
212 * Doesnt deal with AlifoldResult.ensembleValues, the free energy of
213 * ensemble and frequency of mfe structure in ensemble. How to deal with
216 annotation.description = description;
218 annotation.belowAlignment = false;
219 // annotation.showAllColLabels = true;
221 alignViewport.getAlignment().validateAnnotation(annotation);
222 af.setMenusForViewport();
224 ourAnnot.add(annotation);
227 private AlignmentAnnotation constructAnnotationFromScoreHolder(
228 AlignmentAnnotation annotation, String struct, TreeSet<Score> data)
230 Annotation[] anns = new Annotation[gapMap != null ? gapMap.length + 1
235 && data.first().getMethod()
236 .equals(AlifoldResult.contactProbabilities.toString()))
239 // The base pair probabilities are stored in a set in scoreholder. we want
241 LinkedHashMap<Range, Float> basePairs = new LinkedHashMap<Range, Float>();
242 for (Score score : data)
244 // The Score objects contain a set of size one containing the range and
245 // an ArrayList<float> of size one containing the probabilty
246 basePairs.put(score.getRanges().first(), new Float(score
247 .getScores().get(0)));
250 for (int i = 0, ri = 0, iEnd = struct.length(); i < iEnd; i++, ri++)
254 // skip any gapped columns in the input data
260 // Return all the contacts associated with position i
261 LinkedHashMap<Range, Float> contacts = isContact(basePairs, i + 1);
263 String description = "";
266 if (contacts.size() == 0)
268 description = "No Data";
272 for (Range contact : contacts.keySet())
274 float t = contacts.get(contact);
279 description += Integer.toString(contact.from) + "->"
280 + Integer.toString(contact.to) + ": "
281 + Float.toString(t) + "% | ";
285 anns[ri] = new Annotation(struct.substring(i, i + 1), description,
286 isSS(struct.charAt(i)), prob);
289 else if (data == null || data.size() == 1)
291 for (int i = 0, ri = 0, iEnd = struct.length(); i < iEnd; i++, ri++)
295 // skip any gapped columns in the input data
296 while (!gapMap[ri] && ri < gapMap.length)
300 if (ri == gapMap.length)
305 anns[ri] = new Annotation(struct.substring(i, i + 1), "",
306 isSS(struct.charAt(i)), Float.NaN);
309 annotation.graph = 0; // No graph
312 annotation.annotations = anns;
317 private String[] constructTypenameAndDescription(Score score)
319 String description = "";
320 String typename = "";
321 String datatype = score.getMethod();
323 // Look up java switch syntax and use one here
324 if (datatype.equals(AlifoldResult.mfeStructure.toString()))
327 description = MessageFormat.format(
328 "Minimum Free Energy Structure. Energy: {0} = {1} + {2}",
329 score.getScores().get(0), score.getScores().get(1), score
330 .getScores().get(2));
331 typename = "MFE Structure";
333 else if (datatype.equals(AlifoldResult.contactProbabilityStructure
336 description = MessageFormat
337 .format("Base Pair Contact Probabilities. "
338 + "Energy of Ensemble: {0} Frequency of Ensemble: {1}",
339 score.getScores().get(0), score.getScores().get(1));
340 typename = "Contact Probabilities";
342 else if (datatype.equals(AlifoldResult.centroidStructure.toString()))
344 description = MessageFormat.format(
345 "Centroid Structure. Energy: {0} = {1} + {2}", score
346 .getScores().get(0), score.getScores().get(1), score
347 .getScores().get(2));
348 typename = "Centroid Structure";
350 else if (datatype.equals(AlifoldResult.stochBTStructure.toString()))
352 if (score.getScores().size() > 0)
354 description = MessageFormat.format("Probability: {0} Energy: {1}",
355 score.getScores().get(0), score.getScores().get(1));
359 description = "Stochastic Backtrack Structure";
362 else if (datatype.equals(AlifoldResult.MEAStucture.toString()))
364 description = MessageFormat.format(
365 "Maximum Expected Accuracy Values: '{' {0} MEA={1} '}", score
366 .getScores().get(0), score.getScores().get(1));
367 typename = "MEA Structure";
369 else if (datatype.equals(AlifoldResult.consensusAlignment.toString()))
371 typename = "RNAalifold Consensus";
372 description = "Consensus Alignment Produced by RNAalifold";
377 description = typename;
381 { typename, description };
384 // Check whether, at position i there is a base contact and return all the
385 // contacts at this position. Should be in order of descending probability.
386 private LinkedHashMap<Range, Float> isContact(
387 LinkedHashMap<Range, Float> basePairs, int i)
389 LinkedHashMap<Range, Float> contacts = new LinkedHashMap<Range, Float>();
391 for (Range contact : basePairs.keySet())
393 // finds the contacts associtated with position i ordered by the natural
394 // ordering of the Scores TreeSet in ScoreManager which is, descending
396 if (contact.from == i || contact.to == i)
398 contacts.put(contact, basePairs.get(contact));
405 private char isSS(char chr)
407 String regex = "\\(|\\)|\\{|\\}|\\[|\\]";
408 char ss = (Pattern.matches(regex, Character.toString(chr))) ? 'S' : ' ';