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
47 * @author daluke - Daniel Barton
51 public class RNAalifoldClient extends JabawsAlignCalcWorker implements
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 //if (arguments == null)
69 // arguments = new ArrayList<Argument>();
72 methodName = sh.serviceType;
75 nucleotidesAllowed = true;
76 proteinAllowed = false;
80 public String getCalcId()
84 private static String CALC_ID="jalview.ws.jws2.RNAalifoldClient";
86 public static AlignAnalysisUIText getAlignAnalysisUITest()
88 return new AlignAnalysisUIText(
89 compbio.ws.client.Services.RNAalifoldWS.toString(),
90 jalview.ws.jws2.RNAalifoldClient.class,
95 "RNAAliFold Prediction",
96 "When checked, RNA secondary structure predictions will be calculated for the alignment, and updated when edits are made.",
97 "Change RNAAliFold settings...",
98 "Modify settings for the RNAAliFold prediction. Use this to hide or show different results of the RNA calculation, and change RNA folding parameters");
103 public String getServiceActionText()
105 return "Submitting RNA alignment for Secondary Structure prediction using "
106 + "RNAalifold Service";
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.
183 data = compbio.data.sequence.RNAStructReader
184 .newEmptyScore(AlifoldResult.consensusAlignment);
186 if (descriptionData == null)
187 descriptionData = data;
189 String[] typenameAndDescription = constructTypenameAndDescription(descriptionData
191 String typename = typenameAndDescription[0];
192 String description = typenameAndDescription[1];
194 AlignmentAnnotation annotation = alignViewport.getAlignment()
195 .findOrCreateAnnotation(typename, calcId, false, null, null);
197 constructAnnotationFromScoreHolder(annotation, struct, data);
200 * update annotation description with the free Energy, frequency in ensemble
201 * or other data where appropriate.
203 * Doesnt deal with AlifoldResult.ensembleValues, the free energy of
204 * ensemble and frequency of mfe structure in ensemble. How to deal with
207 annotation.description = description;
209 annotation.belowAlignment = false;
210 // annotation.showAllColLabels = true;
212 alignViewport.getAlignment().validateAnnotation(annotation);
213 af.setMenusForViewport();
215 ourAnnot.add(annotation);
218 private AlignmentAnnotation constructAnnotationFromScoreHolder(
219 AlignmentAnnotation annotation, String struct, TreeSet<Score> data)
221 Annotation[] anns = new Annotation[gapMap!= null ? gapMap.length+1 : struct.length()];
225 && data.first().getMethod()
226 .equals(AlifoldResult.contactProbabilities.toString()))
229 // The base pair probabilities are stored in a set in scoreholder. we want
231 LinkedHashMap<Range, Float> basePairs = new LinkedHashMap<Range, Float>();
232 for (Score score : data)
234 // The Score objects contain a set of size one containing the range and
235 // an ArrayList<float> of size one containing the probabilty
236 basePairs.put(score.getRanges().first(), new Float(score
237 .getScores().get(0)));
240 for (int i = 0,ri=0,iEnd=struct.length();i<iEnd; i++,ri++)
244 // skip any gapped columns in the input data
250 // Return all the contacts associated with position i
251 LinkedHashMap<Range, Float> contacts = isContact(basePairs, i + 1);
253 String description = "";
256 if (contacts.size() == 0)
258 description = "No Data";
262 for (Range contact : contacts.keySet())
264 float t = contacts.get(contact);
267 description += Integer.toString(contact.from) + "->"
268 + Integer.toString(contact.to) + ": "
269 + Float.toString(t) + "% | ";
273 anns[ri] = new Annotation(struct.substring(i, i + 1), description,
274 isSS(struct.charAt(i)), prob);
277 else if (data == null || data.size() == 1)
279 for (int i = 0,ri=0,iEnd=struct.length();i<iEnd; i++,ri++)
283 // skip any gapped columns in the input data
284 while (!gapMap[ri] && ri<gapMap.length)
288 if (ri==gapMap.length)
293 anns[ri] = new Annotation(struct.substring(i, i + 1), "",
294 isSS(struct.charAt(i)), Float.NaN);
297 annotation.graph = 0; // No graph
300 annotation.annotations = anns;
305 private String[] constructTypenameAndDescription(Score score)
307 String description = "";
308 String typename = "";
309 String datatype = score.getMethod();
311 // Look up java switch syntax and use one here
312 if (datatype.equals(AlifoldResult.mfeStructure.toString()))
315 description = MessageFormat.format(
316 "Minimum Free Energy Structure. Energy: {0} = {1} + {2}",
317 score.getScores().get(0), score.getScores().get(1), score
318 .getScores().get(2));
319 typename = "MFE Structure";
321 else if (datatype.equals(AlifoldResult.contactProbabilityStructure
324 description = MessageFormat
325 .format("Base Pair Contact Probabilities. "
326 + "Energy of Ensemble: {0} Frequency of Ensemble: {1}",
327 score.getScores().get(0), score.getScores().get(1));
328 typename = "Contact Probabilities";
330 else if (datatype.equals(AlifoldResult.centroidStructure.toString()))
332 description = MessageFormat.format(
333 "Centroid Structure. Energy: {0} = {1} + {2}", score
334 .getScores().get(0), score.getScores().get(1), score
335 .getScores().get(2));
336 typename = "Centroid Structure";
338 else if (datatype.equals(AlifoldResult.stochBTStructure.toString()))
340 if (score.getScores().size() > 0)
342 description = MessageFormat.format("Probability: {0} Energy: {1}",
343 score.getScores().get(0), score.getScores().get(1));
346 description = "Stochastic Backtrack Structure";
348 else if (datatype.equals(AlifoldResult.MEAStucture.toString()))
350 description = MessageFormat.format(
351 "Maximum Expected Accuracy Values: '{' {0} MEA={1} '}", score
352 .getScores().get(0), score.getScores().get(1));
353 typename = "MEA Structure";
355 else if (datatype.equals(AlifoldResult.consensusAlignment.toString()))
357 typename = "RNAalifold Consensus";
358 description = "Consensus Alignment Produced by RNAalifold";
363 description = typename;
367 { typename, description };
370 // Check whether, at position i there is a base contact and return all the
371 // contacts at this position. Should be in order of descending probability.
372 private LinkedHashMap<Range, Float> isContact(
373 LinkedHashMap<Range, Float> basePairs, int i)
375 LinkedHashMap<Range, Float> contacts = new LinkedHashMap<Range, Float>();
377 for (Range contact : basePairs.keySet())
379 // finds the contacts associtated with position i ordered by the natural
380 // ordering of the Scores TreeSet in ScoreManager which is, descending
382 if (contact.from == i || contact.to == i)
383 contacts.put(contact, basePairs.get(contact));
389 private char isSS(char chr)
391 String regex = "\\(|\\)|\\{|\\}|\\[|\\]";
392 char ss = (Pattern.matches(regex, Character.toString(chr))) ? 'S' : ' ';