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.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 JabawsAlignCalcWorker implements
60 // keeps track of whether the RNAalifold result includes base contact
64 public RNAalifoldClient(Jws2Instance sh, AlignFrame alignFrame,
65 WsParamSetI preset, List<Argument> paramset)
67 super(sh, alignFrame, preset, paramset);
69 // if (arguments == null)
70 // arguments = new ArrayList<Argument>();
73 methodName = sh.serviceType;
76 nucleotidesAllowed = true;
77 proteinAllowed = false;
81 public String getCalcId()
86 private static String CALC_ID = "jalview.ws.jws2.RNAalifoldClient";
88 public static AlignAnalysisUIText getAlignAnalysisUITest()
90 return new AlignAnalysisUIText(
91 compbio.ws.client.Services.RNAalifoldWS.toString(),
92 jalview.ws.jws2.RNAalifoldClient.class,
97 "RNAAliFold Prediction",
98 "When checked, RNA secondary structure predictions will be calculated for the alignment, and updated when edits are made.",
99 "Change RNAAliFold settings...",
100 "Modify settings for the RNAAliFold prediction. Use this to hide or show different results of the RNA calculation, and change RNA folding parameters");
105 public String getServiceActionText()
107 return "Submitting RNA alignment for Secondary Structure prediction using "
108 + "RNAalifold Service";
112 public void updateResultAnnotation(boolean immediate)
115 if (immediate || !calcMan.isWorking(this) && scoremanager != null)
118 List<AlignmentAnnotation> ourAnnot = new ArrayList<AlignmentAnnotation>();
120 // Unpack the ScoreManager
121 List<String> structs = ((RNAStructScoreManager) scoremanager)
123 List<TreeSet<Score>> data = ((RNAStructScoreManager) scoremanager)
126 // test to see if this data object contains base pair contacts
127 Score fscore = data.get(0).first();
128 this.bpScores = (fscore.getMethod()
129 .equals(AlifoldResult.contactProbabilities.toString()));
131 // add annotation for the consensus sequence alignment
132 createAnnotationRowforScoreHolder(ourAnnot, getCalcId(),
133 structs.get(0), null, null);
135 // Add annotations for the mfe Structure
136 createAnnotationRowforScoreHolder(ourAnnot, getCalcId(),
137 structs.get(1), data.get(1), null);
139 // decide whether to add base pair contact probability histogram
143 createAnnotationRowforScoreHolder(ourAnnot, getCalcId(),
144 structs.get(2), data.get(0), data.get(2));
148 // Now loop for the rest of the Annotations (if there it isn't stochastic
150 // only the centroid and MEA structures remain anyway)
151 for (int i = count; i < structs.size(); i++)
153 // The ensemble values should be displayed in the description of the
154 // first (or all?) Stochastic Backtrack Structures.
155 if (!data.get(i).first().getMethod()
156 .equals(AlifoldResult.ensembleValues.toString()))
159 createAnnotationRowforScoreHolder(ourAnnot, getCalcId(),
160 structs.get(i), data.get(i), null);
164 if (ourAnnot.size() > 0)
167 updateOurAnnots(ourAnnot);
168 ap.adjustAnnotationHeight();
173 protected void createAnnotationRowforScoreHolder(
174 List<AlignmentAnnotation> ourAnnot, String calcId, String struct,
175 TreeSet<Score> data, TreeSet<Score> descriptionData)
178 * If contactProbability information is returned from RNAalifold it is
179 * stored in the first TreeSet<Score> object corresponding to the String Id
180 * which holds the consensus alignment. The method enumeration is then
181 * updated to AlifoldResult.contactProbabilties. This line recreates the
182 * same data object as was overwritten with the contact probabilites data.
185 data = compbio.data.sequence.RNAStructReader
186 .newEmptyScore(AlifoldResult.consensusAlignment);
188 if (descriptionData == null)
189 descriptionData = data;
191 String[] typenameAndDescription = constructTypenameAndDescription(descriptionData
193 String typename = typenameAndDescription[0];
194 String description = typenameAndDescription[1];
196 AlignmentAnnotation annotation = alignViewport.getAlignment()
197 .findOrCreateAnnotation(typename, calcId, false, null, null);
199 constructAnnotationFromScoreHolder(annotation, struct, data);
202 * update annotation description with the free Energy, frequency in ensemble
203 * or other data where appropriate.
205 * Doesnt deal with AlifoldResult.ensembleValues, the free energy of
206 * ensemble and frequency of mfe structure in ensemble. How to deal with
209 annotation.description = description;
211 annotation.belowAlignment = false;
212 // annotation.showAllColLabels = true;
214 alignViewport.getAlignment().validateAnnotation(annotation);
215 af.setMenusForViewport();
217 ourAnnot.add(annotation);
220 private AlignmentAnnotation constructAnnotationFromScoreHolder(
221 AlignmentAnnotation annotation, String struct, TreeSet<Score> data)
223 Annotation[] anns = new Annotation[gapMap != null ? gapMap.length + 1
228 && 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(), new Float(score
240 .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);
270 description += Integer.toString(contact.from) + "->"
271 + Integer.toString(contact.to) + ": "
272 + Float.toString(t) + "% | ";
276 anns[ri] = new Annotation(struct.substring(i, i + 1), description,
277 isSS(struct.charAt(i)), prob);
280 else if (data == null || data.size() == 1)
282 for (int i = 0, ri = 0, iEnd = struct.length(); i < iEnd; i++, ri++)
286 // skip any gapped columns in the input data
287 while (!gapMap[ri] && ri < gapMap.length)
291 if (ri == gapMap.length)
296 anns[ri] = new Annotation(struct.substring(i, i + 1), "",
297 isSS(struct.charAt(i)), Float.NaN);
300 annotation.graph = 0; // No graph
303 annotation.annotations = anns;
308 private String[] constructTypenameAndDescription(Score score)
310 String description = "";
311 String typename = "";
312 String datatype = score.getMethod();
314 // Look up java switch syntax and use one here
315 if (datatype.equals(AlifoldResult.mfeStructure.toString()))
318 description = MessageFormat.format(
319 "Minimum Free Energy Structure. Energy: {0} = {1} + {2}",
320 score.getScores().get(0), score.getScores().get(1), score
321 .getScores().get(2));
322 typename = "MFE Structure";
324 else if (datatype.equals(AlifoldResult.contactProbabilityStructure
327 description = MessageFormat
328 .format("Base Pair Contact Probabilities. "
329 + "Energy of Ensemble: {0} Frequency of Ensemble: {1}",
330 score.getScores().get(0), score.getScores().get(1));
331 typename = "Contact Probabilities";
333 else if (datatype.equals(AlifoldResult.centroidStructure.toString()))
335 description = MessageFormat.format(
336 "Centroid Structure. Energy: {0} = {1} + {2}", score
337 .getScores().get(0), score.getScores().get(1), score
338 .getScores().get(2));
339 typename = "Centroid Structure";
341 else if (datatype.equals(AlifoldResult.stochBTStructure.toString()))
343 if (score.getScores().size() > 0)
345 description = MessageFormat.format("Probability: {0} Energy: {1}",
346 score.getScores().get(0), score.getScores().get(1));
349 description = "Stochastic Backtrack Structure";
351 else if (datatype.equals(AlifoldResult.MEAStucture.toString()))
353 description = MessageFormat.format(
354 "Maximum Expected Accuracy Values: '{' {0} MEA={1} '}", score
355 .getScores().get(0), score.getScores().get(1));
356 typename = "MEA Structure";
358 else if (datatype.equals(AlifoldResult.consensusAlignment.toString()))
360 typename = "RNAalifold Consensus";
361 description = "Consensus Alignment Produced by RNAalifold";
366 description = typename;
370 { typename, description };
373 // Check whether, at position i there is a base contact and return all the
374 // contacts at this position. Should be in order of descending probability.
375 private LinkedHashMap<Range, Float> isContact(
376 LinkedHashMap<Range, Float> basePairs, int i)
378 LinkedHashMap<Range, Float> contacts = new LinkedHashMap<Range, Float>();
380 for (Range contact : basePairs.keySet())
382 // finds the contacts associtated with position i ordered by the natural
383 // ordering of the Scores TreeSet in ScoreManager which is, descending
385 if (contact.from == i || contact.to == i)
386 contacts.put(contact, basePairs.get(contact));
392 private char isSS(char chr)
394 String regex = "\\(|\\)|\\{|\\}|\\[|\\]";
395 char ss = (Pattern.matches(regex, Character.toString(chr))) ? 'S' : ' ';