2 * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2)
3 * Copyright (C) 2014 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.dm.AAConSettings;
28 import jalview.ws.jws2.jabaws2.Jws2Instance;
29 import jalview.ws.params.WsParamSetI;
30 import jalview.ws.uimodel.AlignAnalysisUIText;
32 import java.text.MessageFormat;
33 import java.util.ArrayList;
34 import java.util.LinkedHashMap;
35 import java.util.List;
36 import java.util.TreeSet;
37 import java.util.regex.Pattern;
39 import compbio.data.sequence.RNAStructReader.AlifoldResult;
40 import compbio.data.sequence.FastaSequence;
41 import compbio.data.sequence.RNAStructScoreManager;
42 import compbio.data.sequence.Range;
43 import compbio.data.sequence.Score;
44 import compbio.metadata.Argument;
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 // if (arguments == null)
71 // arguments = new ArrayList<Argument>();
74 methodName = sh.serviceType;
77 nucleotidesAllowed = true;
78 proteinAllowed = false;
82 public String getCalcId()
87 private static String CALC_ID = "jalview.ws.jws2.RNAalifoldClient";
89 public static AlignAnalysisUIText getAlignAnalysisUITest()
91 return new AlignAnalysisUIText(
92 compbio.ws.client.Services.RNAalifoldWS.toString(),
93 jalview.ws.jws2.RNAalifoldClient.class,
98 "RNAAliFold Prediction",
99 "When checked, RNA secondary structure predictions will be calculated for the alignment, and updated when edits are made.",
100 "Change RNAAliFold settings...",
101 "Modify settings for the RNAAliFold prediction. Use this to hide or show different results of the RNA calculation, and change RNA folding parameters");
106 public String getServiceActionText()
108 return "Submitting RNA alignment for Secondary Structure prediction using "
109 + "RNAalifold Service";
113 boolean checkValidInputSeqs(boolean dynamic, List<FastaSequence> seqs)
115 return (seqs.size() > 1);
119 public void updateResultAnnotation(boolean immediate)
122 if (immediate || !calcMan.isWorking(this) && scoremanager != null)
125 List<AlignmentAnnotation> ourAnnot = new ArrayList<AlignmentAnnotation>();
127 // Unpack the ScoreManager
128 List<String> structs = ((RNAStructScoreManager) scoremanager)
130 List<TreeSet<Score>> data = ((RNAStructScoreManager) scoremanager)
133 // test to see if this data object contains base pair contacts
134 Score fscore = data.get(0).first();
135 this.bpScores = (fscore.getMethod()
136 .equals(AlifoldResult.contactProbabilities.toString()));
138 // add annotation for the consensus sequence alignment
139 createAnnotationRowforScoreHolder(ourAnnot, getCalcId(),
140 structs.get(0), null, null);
142 // Add annotations for the mfe Structure
143 createAnnotationRowforScoreHolder(ourAnnot, getCalcId(),
144 structs.get(1), data.get(1), null);
146 // decide whether to add base pair contact probability histogram
150 createAnnotationRowforScoreHolder(ourAnnot, getCalcId(),
151 structs.get(2), data.get(0), data.get(2));
155 // Now loop for the rest of the Annotations (if there it isn't stochastic
157 // only the centroid and MEA structures remain anyway)
158 for (int i = count; i < structs.size(); i++)
160 // The ensemble values should be displayed in the description of the
161 // first (or all?) Stochastic Backtrack Structures.
162 if (!data.get(i).first().getMethod()
163 .equals(AlifoldResult.ensembleValues.toString()))
166 createAnnotationRowforScoreHolder(ourAnnot, getCalcId(),
167 structs.get(i), data.get(i), null);
171 if (ourAnnot.size() > 0)
174 updateOurAnnots(ourAnnot);
175 ap.adjustAnnotationHeight();
180 protected void createAnnotationRowforScoreHolder(
181 List<AlignmentAnnotation> ourAnnot, String calcId, String struct,
182 TreeSet<Score> data, TreeSet<Score> descriptionData)
185 * If contactProbability information is returned from RNAalifold it is
186 * stored in the first TreeSet<Score> object corresponding to the String Id
187 * which holds the consensus alignment. The method enumeration is then
188 * updated to AlifoldResult.contactProbabilties. This line recreates the
189 * same data object as was overwritten with the contact probabilites data.
192 data = compbio.data.sequence.RNAStructReader
193 .newEmptyScore(AlifoldResult.consensusAlignment);
195 if (descriptionData == null)
196 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);
277 description += Integer.toString(contact.from) + "->"
278 + Integer.toString(contact.to) + ": "
279 + Float.toString(t) + "% | ";
283 anns[ri] = new Annotation(struct.substring(i, i + 1), description,
284 isSS(struct.charAt(i)), prob);
287 else if (data == null || data.size() == 1)
289 for (int i = 0, ri = 0, iEnd = struct.length(); i < iEnd; i++, ri++)
293 // skip any gapped columns in the input data
294 while (!gapMap[ri] && ri < gapMap.length)
298 if (ri == gapMap.length)
303 anns[ri] = new Annotation(struct.substring(i, i + 1), "",
304 isSS(struct.charAt(i)), Float.NaN);
307 annotation.graph = 0; // No graph
310 annotation.annotations = anns;
315 private String[] constructTypenameAndDescription(Score score)
317 String description = "";
318 String typename = "";
319 String datatype = score.getMethod();
321 // Look up java switch syntax and use one here
322 if (datatype.equals(AlifoldResult.mfeStructure.toString()))
325 description = MessageFormat.format(
326 "Minimum Free Energy Structure. Energy: {0} = {1} + {2}",
327 score.getScores().get(0), score.getScores().get(1), score
328 .getScores().get(2));
329 typename = "MFE Structure";
331 else if (datatype.equals(AlifoldResult.contactProbabilityStructure
334 description = MessageFormat
335 .format("Base Pair Contact Probabilities. "
336 + "Energy of Ensemble: {0} Frequency of Ensemble: {1}",
337 score.getScores().get(0), score.getScores().get(1));
338 typename = "Contact Probabilities";
340 else if (datatype.equals(AlifoldResult.centroidStructure.toString()))
342 description = MessageFormat.format(
343 "Centroid Structure. Energy: {0} = {1} + {2}", score
344 .getScores().get(0), score.getScores().get(1), score
345 .getScores().get(2));
346 typename = "Centroid Structure";
348 else if (datatype.equals(AlifoldResult.stochBTStructure.toString()))
350 if (score.getScores().size() > 0)
352 description = MessageFormat.format("Probability: {0} Energy: {1}",
353 score.getScores().get(0), score.getScores().get(1));
356 description = "Stochastic Backtrack Structure";
358 else if (datatype.equals(AlifoldResult.MEAStucture.toString()))
360 description = MessageFormat.format(
361 "Maximum Expected Accuracy Values: '{' {0} MEA={1} '}", score
362 .getScores().get(0), score.getScores().get(1));
363 typename = "MEA Structure";
365 else if (datatype.equals(AlifoldResult.consensusAlignment.toString()))
367 typename = "RNAalifold Consensus";
368 description = "Consensus Alignment Produced by RNAalifold";
373 description = typename;
377 { typename, description };
380 // Check whether, at position i there is a base contact and return all the
381 // contacts at this position. Should be in order of descending probability.
382 private LinkedHashMap<Range, Float> isContact(
383 LinkedHashMap<Range, Float> basePairs, int i)
385 LinkedHashMap<Range, Float> contacts = new LinkedHashMap<Range, Float>();
387 for (Range contact : basePairs.keySet())
389 // finds the contacts associtated with position i ordered by the natural
390 // ordering of the Scores TreeSet in ScoreManager which is, descending
392 if (contact.from == i || contact.to == i)
393 contacts.put(contact, basePairs.get(contact));
399 private char isSS(char chr)
401 String regex = "\\(|\\)|\\{|\\}|\\[|\\]";
402 char ss = (Pattern.matches(regex, Character.toString(chr))) ? 'S' : ' ';