1 package jalview.ws.jws2;
3 import jalview.api.AlignCalcWorkerI;
4 import jalview.datamodel.AlignmentAnnotation;
5 import jalview.datamodel.Annotation;
6 import jalview.gui.AlignFrame;
7 import jalview.ws.jws2.dm.AAConSettings;
8 import jalview.ws.jws2.jabaws2.Jws2Instance;
9 import jalview.ws.params.WsParamSetI;
10 import jalview.ws.uimodel.AlignAnalysisUIText;
12 import java.text.MessageFormat;
13 import java.util.ArrayList;
14 import java.util.LinkedHashMap;
15 import java.util.List;
16 import java.util.TreeSet;
17 import java.util.regex.Pattern;
19 import compbio.data.sequence.RNAStructReader.AlifoldResult;
20 import compbio.data.sequence.RNAStructScoreManager;
21 import compbio.data.sequence.Range;
22 import compbio.data.sequence.Score;
23 import compbio.metadata.Argument;
26 * Client for the JABA RNA Alifold Service
27 * @author daluke - Daniel Barton
31 public class RNAalifoldClient extends JabawsAlignCalcWorker implements
39 // keeps track of whether the RNAalifold result includes base contact
43 public RNAalifoldClient(Jws2Instance sh, AlignFrame alignFrame,
44 WsParamSetI preset, List<Argument> paramset)
46 super(sh, alignFrame, preset, paramset);
48 //if (arguments == null)
49 // arguments = new ArrayList<Argument>();
52 methodName = sh.serviceType;
55 nucleotidesAllowed = true;
56 proteinAllowed = false;
60 public String getCalcId()
64 private static String CALC_ID="jalview.ws.jws2.RNAalifoldClient";
66 public static AlignAnalysisUIText getAlignAnalysisUITest()
68 return new AlignAnalysisUIText(
69 compbio.ws.client.Services.RNAalifoldWS.toString(),
70 jalview.ws.jws2.RNAalifoldClient.class,
75 "RNAAliFold Prediction",
76 "When checked, RNA secondary structure predictions will be calculated for the alignment, and updated when edits are made.",
77 "Change RNAAliFold settings...",
78 "Modify settings for the RNAAliFold prediction. Use this to hide or show different results of the RNA calculation, and change RNA folding parameters");
83 public String getServiceActionText()
85 return "Submitting RNA alignment for Secondary Structure prediction using "
86 + "RNAalifold Service";
90 public void updateResultAnnotation(boolean immediate)
93 if (immediate || !calcMan.isWorking(this) && scoremanager != null)
96 List<AlignmentAnnotation> ourAnnot = new ArrayList<AlignmentAnnotation>();
98 // Unpack the ScoreManager
99 List<String> structs = ((RNAStructScoreManager) scoremanager)
101 List<TreeSet<Score>> data = ((RNAStructScoreManager) scoremanager)
104 // test to see if this data object contains base pair contacts
105 Score fscore = data.get(0).first();
106 this.bpScores = (fscore.getMethod()
107 .equals(AlifoldResult.contactProbabilities.toString()));
109 // add annotation for the consensus sequence alignment
110 createAnnotationRowforScoreHolder(ourAnnot, getCalcId(),
111 structs.get(0), null, null);
113 // Add annotations for the mfe Structure
114 createAnnotationRowforScoreHolder(ourAnnot, getCalcId(),
115 structs.get(1), data.get(1), null);
117 // decide whether to add base pair contact probability histogram
121 createAnnotationRowforScoreHolder(ourAnnot, getCalcId(),
122 structs.get(2), data.get(0), data.get(2));
126 // Now loop for the rest of the Annotations (if there it isn't stochastic
128 // only the centroid and MEA structures remain anyway)
129 for (int i = count; i < structs.size(); i++)
131 // The ensemble values should be displayed in the description of the
132 // first (or all?) Stochastic Backtrack Structures.
133 if (!data.get(i).first().getMethod()
134 .equals(AlifoldResult.ensembleValues.toString()))
137 createAnnotationRowforScoreHolder(ourAnnot, getCalcId(),
138 structs.get(i), data.get(i), null);
142 if (ourAnnot.size() > 0)
145 updateOurAnnots(ourAnnot);
146 ap.adjustAnnotationHeight();
151 protected void createAnnotationRowforScoreHolder(
152 List<AlignmentAnnotation> ourAnnot, String calcId, String struct,
153 TreeSet<Score> data, TreeSet<Score> descriptionData)
156 * If contactProbability information is returned from RNAalifold it is
157 * stored in the first TreeSet<Score> object corresponding to the String Id
158 * which holds the consensus alignment. The method enumeration is then
159 * updated to AlifoldResult.contactProbabilties. This line recreates the
160 * same data object as was overwritten with the contact probabilites data.
163 data = compbio.data.sequence.RNAStructReader
164 .newEmptyScore(AlifoldResult.consensusAlignment);
166 if (descriptionData == null)
167 descriptionData = data;
169 String[] typenameAndDescription = constructTypenameAndDescription(descriptionData
171 String typename = typenameAndDescription[0];
172 String description = typenameAndDescription[1];
174 AlignmentAnnotation annotation = alignViewport.getAlignment()
175 .findOrCreateAnnotation(typename, calcId, false, null, null);
177 constructAnnotationFromScoreHolder(annotation, struct, data);
180 * update annotation description with the free Energy, frequency in ensemble
181 * or other data where appropriate.
183 * Doesnt deal with AlifoldResult.ensembleValues, the free energy of
184 * ensemble and frequency of mfe structure in ensemble. How to deal with
187 annotation.description = description;
189 annotation.belowAlignment = false;
190 // annotation.showAllColLabels = true;
192 alignViewport.getAlignment().validateAnnotation(annotation);
193 af.setMenusForViewport();
195 ourAnnot.add(annotation);
198 private AlignmentAnnotation constructAnnotationFromScoreHolder(
199 AlignmentAnnotation annotation, String struct, TreeSet<Score> data)
201 Annotation[] anns = new Annotation[gapMap!= null ? gapMap.length+1 : struct.length()];
205 && data.first().getMethod()
206 .equals(AlifoldResult.contactProbabilities.toString()))
209 // The base pair probabilities are stored in a set in scoreholder. we want
211 LinkedHashMap<Range, Float> basePairs = new LinkedHashMap<Range, Float>();
212 for (Score score : data)
214 // The Score objects contain a set of size one containing the range and
215 // an ArrayList<float> of size one containing the probabilty
216 basePairs.put(score.getRanges().first(), new Float(score
217 .getScores().get(0)));
220 for (int i = 0,ri=0,iEnd=struct.length();i<iEnd; i++,ri++)
224 // skip any gapped columns in the input data
230 // Return all the contacts associated with position i
231 LinkedHashMap<Range, Float> contacts = isContact(basePairs, i + 1);
233 String description = "";
236 if (contacts.size() == 0)
238 description = "No Data";
242 for (Range contact : contacts.keySet())
244 float t = contacts.get(contact);
247 description += Integer.toString(contact.from) + "->"
248 + Integer.toString(contact.to) + ": "
249 + Float.toString(t) + "% | ";
253 anns[ri] = new Annotation(struct.substring(i, i + 1), description,
254 isSS(struct.charAt(i)), prob);
257 else if (data == null || data.size() == 1)
259 for (int i = 0,ri=0,iEnd=struct.length();i<iEnd; i++,ri++)
263 // skip any gapped columns in the input data
264 while (!gapMap[ri] && ri<gapMap.length)
268 if (ri==gapMap.length)
273 anns[ri] = new Annotation(struct.substring(i, i + 1), "",
274 isSS(struct.charAt(i)), Float.NaN);
277 annotation.graph = 0; // No graph
280 annotation.annotations = anns;
285 private String[] constructTypenameAndDescription(Score score)
287 String description = "";
288 String typename = "";
289 String datatype = score.getMethod();
291 // Look up java switch syntax and use one here
292 if (datatype.equals(AlifoldResult.mfeStructure.toString()))
295 description = MessageFormat.format(
296 "Minimum Free Energy Structure. Energy: {0} = {1} + {2}",
297 score.getScores().get(0), score.getScores().get(1), score
298 .getScores().get(2));
299 typename = "MFE Structure";
301 else if (datatype.equals(AlifoldResult.contactProbabilityStructure
304 description = MessageFormat
305 .format("Base Pair Contact Probabilities. "
306 + "Energy of Ensemble: {0} Frequency of Ensemble: {1}",
307 score.getScores().get(0), score.getScores().get(1));
308 typename = "Contact Probabilities";
310 else if (datatype.equals(AlifoldResult.centroidStructure.toString()))
312 description = MessageFormat.format(
313 "Centroid Structure. Energy: {0} = {1} + {2}", score
314 .getScores().get(0), score.getScores().get(1), score
315 .getScores().get(2));
316 typename = "Centroid Structure";
318 else if (datatype.equals(AlifoldResult.stochBTStructure.toString()))
320 if (score.getScores().size() > 0)
322 description = MessageFormat.format("Probability: {0} Energy: {1}",
323 score.getScores().get(0), score.getScores().get(1));
326 description = "Stochastic Backtrack Structure";
328 else if (datatype.equals(AlifoldResult.MEAStucture.toString()))
330 description = MessageFormat.format(
331 "Maximum Expected Accuracy Values: '{' {0} MEA={1} '}", score
332 .getScores().get(0), score.getScores().get(1));
333 typename = "MEA Structure";
335 else if (datatype.equals(AlifoldResult.consensusAlignment.toString()))
337 typename = "RNAalifold Consensus";
338 description = "Consensus Alignment Produced by RNAalifold";
343 description = typename;
347 { typename, description };
350 // Check whether, at position i there is a base contact and return all the
351 // contacts at this position. Should be in order of descending probability.
352 private LinkedHashMap<Range, Float> isContact(
353 LinkedHashMap<Range, Float> basePairs, int i)
355 LinkedHashMap<Range, Float> contacts = new LinkedHashMap<Range, Float>();
357 for (Range contact : basePairs.keySet())
359 // finds the contacts associtated with position i ordered by the natural
360 // ordering of the Scores TreeSet in ScoreManager which is, descending
362 if (contact.from == i || contact.to == i)
363 contacts.put(contact, basePairs.get(contact));
369 private char isSS(char chr)
371 String regex = "\\(|\\)|\\{|\\}|\\[|\\]";
372 char ss = (Pattern.matches(regex, Character.toString(chr))) ? 'S' : ' ';