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[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
269 anns[ri] = new Annotation(struct.substring(i, i + 1), "",
270 isSS(struct.charAt(i)), Float.NaN);
273 annotation.graph = 0; // No graph
276 annotation.annotations = anns;
281 private String[] constructTypenameAndDescription(Score score)
283 String description = "";
284 String typename = "";
285 String datatype = score.getMethod();
287 // Look up java switch syntax and use one here
288 if (datatype.equals(AlifoldResult.mfeStructure.toString()))
291 description = MessageFormat.format(
292 "Minimum Free Energy Structure. Energy: {0} = {1} + {2}",
293 score.getScores().get(0), score.getScores().get(1), score
294 .getScores().get(2));
295 typename = "MFE Structure";
297 else if (datatype.equals(AlifoldResult.contactProbabilityStructure
300 description = MessageFormat
301 .format("Base Pair Contact Probabilities. "
302 + "Energy of Ensemble: {0} Frequency of Ensemble: {1}",
303 score.getScores().get(0), score.getScores().get(1));
304 typename = "Contact Probabilities";
306 else if (datatype.equals(AlifoldResult.centroidStructure.toString()))
308 description = MessageFormat.format(
309 "Centroid Structure. Energy: {0} = {1} + {2}", score
310 .getScores().get(0), score.getScores().get(1), score
311 .getScores().get(2));
312 typename = "Centroid Structure";
314 else if (datatype.equals(AlifoldResult.stochBTStructure.toString()))
316 if (score.getScores().size() > 0)
318 description = MessageFormat.format("Probability: {0} Energy: {1}",
319 score.getScores().get(0), score.getScores().get(1));
322 description = "Stochastic Backtrack Structure";
324 else if (datatype.equals(AlifoldResult.MEAStucture.toString()))
326 description = MessageFormat.format(
327 "Maximum Expected Accuracy Values: '{' {0} MEA={1} '}", score
328 .getScores().get(0), score.getScores().get(1));
329 typename = "MEA Structure";
331 else if (datatype.equals(AlifoldResult.consensusAlignment.toString()))
333 typename = "RNAalifold Consensus";
334 description = "Consensus Alignment Produced by RNAalifold";
339 description = typename;
343 { typename, description };
346 // Check whether, at position i there is a base contact and return all the
347 // contacts at this position. Should be in order of descending probability.
348 private LinkedHashMap<Range, Float> isContact(
349 LinkedHashMap<Range, Float> basePairs, int i)
351 LinkedHashMap<Range, Float> contacts = new LinkedHashMap<Range, Float>();
353 for (Range contact : basePairs.keySet())
355 // finds the contacts associtated with position i ordered by the natural
356 // ordering of the Scores TreeSet in ScoreManager which is, descending
358 if (contact.from == i || contact.to == i)
359 contacts.put(contact, basePairs.get(contact));
365 private char isSS(char chr)
367 String regex = "\\(|\\)|\\{|\\}|\\[|\\]";
368 char ss = (Pattern.matches(regex, Character.toString(chr))) ? 'S' : ' ';