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)));
219 for (int i = 0; i < struct.length(); i++)
222 // Return all the contacts associated with position i
223 LinkedHashMap<Range, Float> contacts = isContact(basePairs, i + 1);
225 String description = "";
228 if (contacts.size() == 0)
230 description = "No Data";
234 for (Range contact : contacts.keySet())
236 float t = contacts.get(contact);
239 description += Integer.toString(contact.from) + "->"
240 + Integer.toString(contact.to) + ": "
241 + Float.toString(t) + "% | ";
245 anns[i] = new Annotation(struct.substring(i, i + 1), description,
246 isSS(struct.charAt(i)), prob);
249 else if (data == null || data.size() == 1)
251 for (int i = 0; i < struct.length(); i++)
254 anns[i] = new Annotation(struct.substring(i, i + 1), "",
255 isSS(struct.charAt(i)), Float.NaN);
258 annotation.graph = 0; // No graph
261 annotation.annotations = anns;
266 private String[] constructTypenameAndDescription(Score score)
268 String description = "";
269 String typename = "";
270 String datatype = score.getMethod();
272 // Look up java switch syntax and use one here
273 if (datatype.equals(AlifoldResult.mfeStructure.toString()))
276 description = MessageFormat.format(
277 "Minimum Free Energy Structure. Energy: {0} = {1} + {2}",
278 score.getScores().get(0), score.getScores().get(1), score
279 .getScores().get(2));
280 typename = "MFE Structure";
282 else if (datatype.equals(AlifoldResult.contactProbabilityStructure
285 description = MessageFormat
286 .format("Base Pair Contact Probabilities. "
287 + "Energy of Ensemble: {0} Frequency of Ensemble: {1}",
288 score.getScores().get(0), score.getScores().get(1));
289 typename = "Contact Probabilities";
291 else if (datatype.equals(AlifoldResult.centroidStructure.toString()))
293 description = MessageFormat.format(
294 "Centroid Structure. Energy: {0} = {1} + {2}", score
295 .getScores().get(0), score.getScores().get(1), score
296 .getScores().get(2));
297 typename = "Centroid Structure";
299 else if (datatype.equals(AlifoldResult.stochBTStructure.toString()))
301 if (score.getScores().size() > 0)
303 description = MessageFormat.format("Probability: {0} Energy: {1}",
304 score.getScores().get(0), score.getScores().get(1));
307 description = "Stochastic Backtrack Structure";
309 else if (datatype.equals(AlifoldResult.MEAStucture.toString()))
311 description = MessageFormat.format(
312 "Maximum Expected Accuracy Values: '{' {0} MEA={1} '}", score
313 .getScores().get(0), score.getScores().get(1));
314 typename = "MEA Structure";
316 else if (datatype.equals(AlifoldResult.consensusAlignment.toString()))
318 typename = "RNAalifold Consensus";
319 description = "Consensus Alignment Produced by RNAalifold";
324 description = typename;
328 { typename, description };
331 // Check whether, at position i there is a base contact and return all the
332 // contacts at this position. Should be in order of descending probability.
333 private LinkedHashMap<Range, Float> isContact(
334 LinkedHashMap<Range, Float> basePairs, int i)
336 LinkedHashMap<Range, Float> contacts = new LinkedHashMap<Range, Float>();
338 for (Range contact : basePairs.keySet())
340 // finds the contacts associtated with position i ordered by the natural
341 // ordering of the Scores TreeSet in ScoreManager which is, descending
343 if (contact.from == i || contact.to == i)
344 contacts.put(contact, basePairs.get(contact));
350 private char isSS(char chr)
352 String regex = "\\(|\\)|\\{|\\}|\\[|\\]";
353 char ss = (Pattern.matches(regex, Character.toString(chr))) ? 'S' : ' ';