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.datamodel.AlignmentAnnotation;
24 import jalview.datamodel.Annotation;
25 import jalview.gui.AlignFrame;
26 import jalview.util.MessageManager;
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;
46 * Client for the JABA RNA Alifold Service
48 * @author daluke - Daniel Barton
52 public class RNAalifoldClient extends JabawsCalcWorker
59 // keeps track of whether the RNAalifold result includes base contact
63 public RNAalifoldClient(Jws2Instance sh, AlignFrame alignFrame,
64 WsParamSetI preset, List<Argument> paramset)
66 super(sh, alignFrame, preset, paramset);
68 methodName = sh.serviceType;
71 nucleotidesAllowed = true;
72 proteinAllowed = false;
77 public String getCalcId()
82 private static String CALC_ID = "jalview.ws.jws2.RNAalifoldClient";
84 public static AlignAnalysisUIText getAlignAnalysisUITest()
86 return new AlignAnalysisUIText(
87 compbio.ws.client.Services.RNAalifoldWS.toString(),
88 jalview.ws.jws2.RNAalifoldClient.class, CALC_ID, true, false,
89 true, MessageManager.getString("label.rnalifold_calculations"),
90 MessageManager.getString("tooltip.rnalifold_calculations"),
91 MessageManager.getString("label.rnalifold_settings"),
92 MessageManager.getString("tooltip.rnalifold_settings"));
96 public String getServiceActionText()
98 return "Submitting RNA alignment for Secondary Structure prediction using "
99 + "RNAalifold Service";
103 boolean checkValidInputSeqs(boolean dynamic, List<FastaSequence> seqs)
105 return (seqs.size() > 1);
109 public void updateResultAnnotation(boolean immediate)
112 if (immediate || !calcMan.isWorking(this) && scoremanager != null)
115 List<AlignmentAnnotation> ourAnnot = new ArrayList<AlignmentAnnotation>();
117 // Unpack the ScoreManager
118 List<String> structs = ((RNAStructScoreManager) scoremanager)
120 List<TreeSet<Score>> data = ((RNAStructScoreManager) scoremanager)
123 // test to see if this data object contains base pair contacts
124 Score fscore = data.get(0).first();
125 this.bpScores = (fscore.getMethod()
126 .equals(AlifoldResult.contactProbabilities.toString()));
128 // add annotation for the consensus sequence alignment
129 createAnnotationRowforScoreHolder(ourAnnot, getCalcId(),
130 structs.get(0), null, null);
132 // Add annotations for the mfe Structure
133 createAnnotationRowforScoreHolder(ourAnnot, getCalcId(),
134 structs.get(1), data.get(1), null);
136 // decide whether to add base pair contact probability histogram
140 createAnnotationRowforScoreHolder(ourAnnot, getCalcId(),
141 structs.get(2), data.get(0), data.get(2));
145 // Now loop for the rest of the Annotations (if there it isn't stochastic
147 // only the centroid and MEA structures remain anyway)
148 for (int i = count; i < structs.size(); i++)
150 // The ensemble values should be displayed in the description of the
151 // first (or all?) Stochastic Backtrack Structures.
152 if (!data.get(i).first().getMethod()
153 .equals(AlifoldResult.ensembleValues.toString()))
156 createAnnotationRowforScoreHolder(ourAnnot, getCalcId(),
157 structs.get(i), data.get(i), null);
161 if (ourAnnot.size() > 0)
164 updateOurAnnots(ourAnnot);
165 ap.adjustAnnotationHeight();
170 protected void createAnnotationRowforScoreHolder(
171 List<AlignmentAnnotation> ourAnnot, String calcId, String struct,
172 TreeSet<Score> data, TreeSet<Score> descriptionData)
175 * If contactProbability information is returned from RNAalifold it is
176 * stored in the first TreeSet<Score> object corresponding to the String Id
177 * which holds the consensus alignment. The method enumeration is then
178 * updated to AlifoldResult.contactProbabilties. This line recreates the
179 * same data object as was overwritten with the contact probabilites data.
183 data = compbio.data.sequence.RNAStructReader
184 .newEmptyScore(AlifoldResult.consensusAlignment);
187 if (descriptionData == null)
189 descriptionData = data;
192 String[] typenameAndDescription = constructTypenameAndDescription(
193 descriptionData.first());
194 String typename = typenameAndDescription[0];
195 String description = typenameAndDescription[1];
197 AlignmentAnnotation annotation = alignViewport.getAlignment()
198 .findOrCreateAnnotation(typename, calcId, false, null, null);
200 constructAnnotationFromScoreHolder(annotation, struct, data);
203 * update annotation description with the free Energy, frequency in ensemble
204 * or other data where appropriate.
206 * Doesnt deal with AlifoldResult.ensembleValues, the free energy of
207 * ensemble and frequency of mfe structure in ensemble. How to deal with
210 annotation.description = description;
212 annotation.belowAlignment = false;
213 // annotation.showAllColLabels = true;
215 alignViewport.getAlignment().validateAnnotation(annotation);
216 af.setMenusForViewport();
218 ourAnnot.add(annotation);
221 private AlignmentAnnotation constructAnnotationFromScoreHolder(
222 AlignmentAnnotation annotation, String struct,
225 Annotation[] anns = new Annotation[gapMap != null ? gapMap.length + 1
228 if (data != null && data.size() > 1 && data.first().getMethod()
229 .equals(AlifoldResult.contactProbabilities.toString()))
232 // The base pair probabilities are stored in a set in scoreholder. we want
234 LinkedHashMap<Range, Float> basePairs = new LinkedHashMap<Range, Float>();
235 for (Score score : data)
237 // The Score objects contain a set of size one containing the range and
238 // an ArrayList<float> of size one containing the probabilty
239 basePairs.put(score.getRanges().first(),
240 new Float(score.getScores().get(0)));
243 for (int i = 0, ri = 0, iEnd = struct.length(); i < iEnd; i++, ri++)
247 // skip any gapped columns in the input data
253 // Return all the contacts associated with position i
254 LinkedHashMap<Range, Float> contacts = isContact(basePairs, i + 1);
256 String description = "";
259 if (contacts.size() == 0)
261 description = "No Data";
265 for (Range contact : contacts.keySet())
267 float t = contacts.get(contact);
272 description += Integer.toString(contact.from) + "->"
273 + Integer.toString(contact.to) + ": "
274 + Float.toString(t) + "% | ";
278 anns[ri] = new Annotation(struct.substring(i, i + 1), description,
279 isSS(struct.charAt(i)), prob);
282 else if (data == null || data.size() == 1)
284 for (int i = 0, ri = 0, iEnd = struct.length(); i < iEnd; i++, ri++)
288 // skip any gapped columns in the input data
289 while (!gapMap[ri] && ri < gapMap.length)
293 if (ri == gapMap.length)
298 anns[ri] = new Annotation(struct.substring(i, i + 1), "",
299 isSS(struct.charAt(i)), Float.NaN);
302 annotation.graph = 0; // No graph
305 annotation.annotations = anns;
310 private String[] constructTypenameAndDescription(Score score)
312 String description = "";
313 String typename = "";
314 String datatype = score.getMethod();
316 // Look up java switch syntax and use one here
317 if (datatype.equals(AlifoldResult.mfeStructure.toString()))
320 description = MessageFormat.format(
321 "Minimum Free Energy Structure. Energy: {0} = {1} + {2}",
322 score.getScores().get(0), score.getScores().get(1),
323 score.getScores().get(2));
324 typename = "MFE Structure";
327 .equals(AlifoldResult.contactProbabilityStructure.toString()))
329 description = MessageFormat.format("Base Pair Contact Probabilities. "
330 + "Energy of Ensemble: {0} Frequency of Ensemble: {1}",
331 score.getScores().get(0), score.getScores().get(1));
332 typename = "Contact Probabilities";
334 else if (datatype.equals(AlifoldResult.centroidStructure.toString()))
336 description = MessageFormat.format(
337 "Centroid Structure. Energy: {0} = {1} + {2}",
338 score.getScores().get(0), score.getScores().get(1),
339 score.getScores().get(2));
340 typename = "Centroid Structure";
342 else if (datatype.equals(AlifoldResult.stochBTStructure.toString()))
344 if (score.getScores().size() > 0)
346 description = MessageFormat.format("Probability: {0} Energy: {1}",
347 score.getScores().get(0), score.getScores().get(1));
351 description = "Stochastic Backtrack Structure";
354 else if (datatype.equals(AlifoldResult.MEAStucture.toString()))
356 description = MessageFormat.format(
357 "Maximum Expected Accuracy Values: '{' {0} MEA={1} '}",
358 score.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;
372 return new String[] { typename, description };
375 // Check whether, at position i there is a base contact and return all the
376 // contacts at this position. Should be in order of descending probability.
377 private LinkedHashMap<Range, Float> isContact(
378 LinkedHashMap<Range, Float> basePairs, int i)
380 LinkedHashMap<Range, Float> contacts = new LinkedHashMap<Range, Float>();
382 for (Range contact : basePairs.keySet())
384 // finds the contacts associtated with position i ordered by the natural
385 // ordering of the Scores TreeSet in ScoreManager which is, descending
387 if (contact.from == i || contact.to == i)
389 contacts.put(contact, basePairs.get(contact));
396 private char isSS(char chr)
398 String regex = "\\(|\\)|\\{|\\}|\\[|\\]";
399 char ss = (Pattern.matches(regex, Character.toString(chr))) ? 'S' : ' ';