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.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 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,
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.
188 data = compbio.data.sequence.RNAStructReader
189 .newEmptyScore(AlifoldResult.consensusAlignment);
191 if (descriptionData == null)
192 descriptionData = data;
194 String[] typenameAndDescription = constructTypenameAndDescription(descriptionData
196 String typename = typenameAndDescription[0];
197 String description = typenameAndDescription[1];
199 AlignmentAnnotation annotation = alignViewport.getAlignment()
200 .findOrCreateAnnotation(typename, calcId, false, null, null);
202 constructAnnotationFromScoreHolder(annotation, struct, data);
205 * update annotation description with the free Energy, frequency in ensemble
206 * or other data where appropriate.
208 * Doesnt deal with AlifoldResult.ensembleValues, the free energy of
209 * ensemble and frequency of mfe structure in ensemble. How to deal with
212 annotation.description = description;
214 annotation.belowAlignment = false;
215 // annotation.showAllColLabels = true;
217 alignViewport.getAlignment().validateAnnotation(annotation);
218 af.setMenusForViewport();
220 ourAnnot.add(annotation);
223 private AlignmentAnnotation constructAnnotationFromScoreHolder(
224 AlignmentAnnotation annotation, String struct, TreeSet<Score> data)
226 Annotation[] anns = new Annotation[gapMap != null ? gapMap.length + 1
231 && data.first().getMethod()
232 .equals(AlifoldResult.contactProbabilities.toString()))
235 // The base pair probabilities are stored in a set in scoreholder. we want
237 LinkedHashMap<Range, Float> basePairs = new LinkedHashMap<Range, Float>();
238 for (Score score : data)
240 // The Score objects contain a set of size one containing the range and
241 // an ArrayList<float> of size one containing the probabilty
242 basePairs.put(score.getRanges().first(), new Float(score
243 .getScores().get(0)));
246 for (int i = 0, ri = 0, iEnd = struct.length(); i < iEnd; i++, ri++)
250 // skip any gapped columns in the input data
256 // Return all the contacts associated with position i
257 LinkedHashMap<Range, Float> contacts = isContact(basePairs, i + 1);
259 String description = "";
262 if (contacts.size() == 0)
264 description = "No Data";
268 for (Range contact : contacts.keySet())
270 float t = contacts.get(contact);
273 description += Integer.toString(contact.from) + "->"
274 + Integer.toString(contact.to) + ": "
275 + Float.toString(t) + "% | ";
279 anns[ri] = new Annotation(struct.substring(i, i + 1), description,
280 isSS(struct.charAt(i)), prob);
283 else if (data == null || data.size() == 1)
285 for (int i = 0, ri = 0, iEnd = struct.length(); i < iEnd; i++, ri++)
289 // skip any gapped columns in the input data
290 while (!gapMap[ri] && ri < gapMap.length)
294 if (ri == gapMap.length)
299 anns[ri] = new Annotation(struct.substring(i, i + 1), "",
300 isSS(struct.charAt(i)), Float.NaN);
303 annotation.graph = 0; // No graph
306 annotation.annotations = anns;
311 private String[] constructTypenameAndDescription(Score score)
313 String description = "";
314 String typename = "";
315 String datatype = score.getMethod();
317 // Look up java switch syntax and use one here
318 if (datatype.equals(AlifoldResult.mfeStructure.toString()))
321 description = MessageFormat.format(
322 "Minimum Free Energy Structure. Energy: {0} = {1} + {2}",
323 score.getScores().get(0), score.getScores().get(1), score
324 .getScores().get(2));
325 typename = "MFE Structure";
327 else if (datatype.equals(AlifoldResult.contactProbabilityStructure
330 description = MessageFormat
331 .format("Base Pair Contact Probabilities. "
332 + "Energy of Ensemble: {0} Frequency of Ensemble: {1}",
333 score.getScores().get(0), score.getScores().get(1));
334 typename = "Contact Probabilities";
336 else if (datatype.equals(AlifoldResult.centroidStructure.toString()))
338 description = MessageFormat.format(
339 "Centroid Structure. Energy: {0} = {1} + {2}", score
340 .getScores().get(0), score.getScores().get(1), score
341 .getScores().get(2));
342 typename = "Centroid Structure";
344 else if (datatype.equals(AlifoldResult.stochBTStructure.toString()))
346 if (score.getScores().size() > 0)
348 description = MessageFormat.format("Probability: {0} Energy: {1}",
349 score.getScores().get(0), score.getScores().get(1));
352 description = "Stochastic Backtrack Structure";
354 else if (datatype.equals(AlifoldResult.MEAStucture.toString()))
356 description = MessageFormat.format(
357 "Maximum Expected Accuracy Values: '{' {0} MEA={1} '}", score
358 .getScores().get(0), score.getScores().get(1));
359 typename = "MEA Structure";
361 else if (datatype.equals(AlifoldResult.consensusAlignment.toString()))
363 typename = "RNAalifold Consensus";
364 description = "Consensus Alignment Produced by RNAalifold";
369 description = typename;
373 { typename, description };
376 // Check whether, at position i there is a base contact and return all the
377 // contacts at this position. Should be in order of descending probability.
378 private LinkedHashMap<Range, Float> isContact(
379 LinkedHashMap<Range, Float> basePairs, int i)
381 LinkedHashMap<Range, Float> contacts = new LinkedHashMap<Range, Float>();
383 for (Range contact : basePairs.keySet())
385 // finds the contacts associtated with position i ordered by the natural
386 // ordering of the Scores TreeSet in ScoreManager which is, descending
388 if (contact.from == i || contact.to == i)
389 contacts.put(contact, basePairs.get(contact));
395 private char isSS(char chr)
397 String regex = "\\(|\\)|\\{|\\}|\\[|\\]";
398 char ss = (Pattern.matches(regex, Character.toString(chr))) ? 'S' : ' ';