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.util.MessageManager;
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.FastaSequence;
40 import compbio.data.sequence.RNAStructReader.AlifoldResult;
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 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 compbio.ws.client.Services.RNAalifoldWS.toString(),
89 jalview.ws.jws2.RNAalifoldClient.class, CALC_ID, true, false,
90 true, MessageManager.getString("label.rnalifold_calculations"),
91 MessageManager.getString("tooltip.rnalifold_calculations"),
92 MessageManager.getString("label.rnalifold_settings"),
93 MessageManager.getString("tooltip.rnalifold_settings"));
97 public String getServiceActionText()
99 return "Submitting RNA alignment for Secondary Structure prediction using "
100 + "RNAalifold Service";
104 boolean checkValidInputSeqs(boolean dynamic, List<FastaSequence> seqs)
106 return (seqs.size() > 1);
110 public void updateResultAnnotation(boolean immediate)
113 if (immediate || !calcMan.isWorking(this) && scoremanager != null)
116 List<AlignmentAnnotation> ourAnnot = new ArrayList<AlignmentAnnotation>();
118 // Unpack the ScoreManager
119 List<String> structs = ((RNAStructScoreManager) scoremanager)
121 List<TreeSet<Score>> data = ((RNAStructScoreManager) scoremanager)
124 // test to see if this data object contains base pair contacts
125 Score fscore = data.get(0).first();
126 this.bpScores = (fscore.getMethod()
127 .equals(AlifoldResult.contactProbabilities.toString()));
129 // add annotation for the consensus sequence alignment
130 createAnnotationRowforScoreHolder(ourAnnot, getCalcId(),
131 structs.get(0), null, null);
133 // Add annotations for the mfe Structure
134 createAnnotationRowforScoreHolder(ourAnnot, getCalcId(),
135 structs.get(1), data.get(1), null);
137 // decide whether to add base pair contact probability histogram
141 createAnnotationRowforScoreHolder(ourAnnot, getCalcId(),
142 structs.get(2), data.get(0), data.get(2));
146 // Now loop for the rest of the Annotations (if there it isn't stochastic
148 // only the centroid and MEA structures remain anyway)
149 for (int i = count; i < structs.size(); i++)
151 // The ensemble values should be displayed in the description of the
152 // first (or all?) Stochastic Backtrack Structures.
153 if (!data.get(i).first().getMethod()
154 .equals(AlifoldResult.ensembleValues.toString()))
157 createAnnotationRowforScoreHolder(ourAnnot, getCalcId(),
158 structs.get(i), data.get(i), null);
162 if (ourAnnot.size() > 0)
165 updateOurAnnots(ourAnnot);
166 ap.adjustAnnotationHeight();
171 protected void createAnnotationRowforScoreHolder(
172 List<AlignmentAnnotation> ourAnnot, String calcId, String struct,
173 TreeSet<Score> data, TreeSet<Score> descriptionData)
176 * If contactProbability information is returned from RNAalifold it is
177 * stored in the first TreeSet<Score> object corresponding to the String Id
178 * which holds the consensus alignment. The method enumeration is then
179 * updated to AlifoldResult.contactProbabilties. This line recreates the
180 * same data object as was overwritten with the contact probabilites data.
184 data = compbio.data.sequence.RNAStructReader
185 .newEmptyScore(AlifoldResult.consensusAlignment);
188 if (descriptionData == null)
190 descriptionData = data;
193 String[] typenameAndDescription = constructTypenameAndDescription(descriptionData
195 String typename = typenameAndDescription[0];
196 String description = typenameAndDescription[1];
198 AlignmentAnnotation annotation = alignViewport.getAlignment()
199 .findOrCreateAnnotation(typename, calcId, false, null, null);
201 constructAnnotationFromScoreHolder(annotation, struct, data);
204 * update annotation description with the free Energy, frequency in ensemble
205 * or other data where appropriate.
207 * Doesnt deal with AlifoldResult.ensembleValues, the free energy of
208 * ensemble and frequency of mfe structure in ensemble. How to deal with
211 annotation.description = description;
213 annotation.belowAlignment = false;
214 // annotation.showAllColLabels = true;
216 alignViewport.getAlignment().validateAnnotation(annotation);
217 af.setMenusForViewport();
219 ourAnnot.add(annotation);
222 private AlignmentAnnotation constructAnnotationFromScoreHolder(
223 AlignmentAnnotation annotation, String struct, TreeSet<Score> data)
225 Annotation[] anns = new Annotation[gapMap != null ? gapMap.length + 1
230 && data.first().getMethod()
231 .equals(AlifoldResult.contactProbabilities.toString()))
234 // The base pair probabilities are stored in a set in scoreholder. we want
236 LinkedHashMap<Range, Float> basePairs = new LinkedHashMap<Range, Float>();
237 for (Score score : data)
239 // The Score objects contain a set of size one containing the range and
240 // an ArrayList<float> of size one containing the probabilty
241 basePairs.put(score.getRanges().first(), new Float(score
242 .getScores().get(0)));
245 for (int i = 0, ri = 0, iEnd = struct.length(); i < iEnd; i++, ri++)
249 // skip any gapped columns in the input data
255 // Return all the contacts associated with position i
256 LinkedHashMap<Range, Float> contacts = isContact(basePairs, i + 1);
258 String description = "";
261 if (contacts.size() == 0)
263 description = "No Data";
267 for (Range contact : contacts.keySet())
269 float t = contacts.get(contact);
274 description += Integer.toString(contact.from) + "->"
275 + Integer.toString(contact.to) + ": "
276 + Float.toString(t) + "% | ";
280 anns[ri] = new Annotation(struct.substring(i, i + 1), description,
281 isSS(struct.charAt(i)), prob);
284 else if (data == null || data.size() == 1)
286 for (int i = 0, ri = 0, iEnd = struct.length(); i < iEnd; i++, ri++)
290 // skip any gapped columns in the input data
291 while (!gapMap[ri] && ri < gapMap.length)
295 if (ri == gapMap.length)
300 anns[ri] = new Annotation(struct.substring(i, i + 1), "",
301 isSS(struct.charAt(i)), Float.NaN);
304 annotation.graph = 0; // No graph
307 annotation.annotations = anns;
312 private String[] constructTypenameAndDescription(Score score)
314 String description = "";
315 String typename = "";
316 String datatype = score.getMethod();
318 // Look up java switch syntax and use one here
319 if (datatype.equals(AlifoldResult.mfeStructure.toString()))
322 description = MessageFormat.format(
323 "Minimum Free Energy Structure. Energy: {0} = {1} + {2}",
324 score.getScores().get(0), score.getScores().get(1), score
325 .getScores().get(2));
326 typename = "MFE Structure";
328 else if (datatype.equals(AlifoldResult.contactProbabilityStructure
331 description = MessageFormat
332 .format("Base Pair Contact Probabilities. "
333 + "Energy of Ensemble: {0} Frequency of Ensemble: {1}",
334 score.getScores().get(0), score.getScores().get(1));
335 typename = "Contact Probabilities";
337 else if (datatype.equals(AlifoldResult.centroidStructure.toString()))
339 description = MessageFormat.format(
340 "Centroid Structure. Energy: {0} = {1} + {2}", score
341 .getScores().get(0), score.getScores().get(1), score
342 .getScores().get(2));
343 typename = "Centroid Structure";
345 else if (datatype.equals(AlifoldResult.stochBTStructure.toString()))
347 if (score.getScores().size() > 0)
349 description = MessageFormat.format("Probability: {0} Energy: {1}",
350 score.getScores().get(0), score.getScores().get(1));
354 description = "Stochastic Backtrack Structure";
357 else if (datatype.equals(AlifoldResult.MEAStucture.toString()))
359 description = MessageFormat.format(
360 "Maximum Expected Accuracy Values: '{' {0} MEA={1} '}", score
361 .getScores().get(0), score.getScores().get(1));
362 typename = "MEA Structure";
364 else if (datatype.equals(AlifoldResult.consensusAlignment.toString()))
366 typename = "RNAalifold Consensus";
367 description = "Consensus Alignment Produced by RNAalifold";
372 description = typename;
375 return new String[] { typename, description };
378 // Check whether, at position i there is a base contact and return all the
379 // contacts at this position. Should be in order of descending probability.
380 private LinkedHashMap<Range, Float> isContact(
381 LinkedHashMap<Range, Float> basePairs, int i)
383 LinkedHashMap<Range, Float> contacts = new LinkedHashMap<Range, Float>();
385 for (Range contact : basePairs.keySet())
387 // finds the contacts associtated with position i ordered by the natural
388 // ordering of the Scores TreeSet in ScoreManager which is, descending
390 if (contact.from == i || contact.to == i)
392 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' : ' ';