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;
11 import java.text.MessageFormat;
12 import java.util.ArrayList;
13 import java.util.LinkedHashMap;
14 import java.util.List;
15 import java.util.TreeSet;
16 import java.util.regex.Pattern;
18 import compbio.data.sequence.RNAStructReader.AlifoldResult;
19 import compbio.data.sequence.RNAStructScoreManager;
20 import compbio.data.sequence.Range;
21 import compbio.data.sequence.Score;
22 import compbio.metadata.Argument;
24 public class RNAalifoldClient extends JabawsAlignCalcWorker implements
32 // keeps track of whether the RNAalifold result includes base contact probabilities
35 public RNAalifoldClient(Jws2Instance sh, AlignFrame alignFrame,
36 WsParamSetI preset, List<Argument> paramset)
38 super(sh, alignFrame, preset, paramset);
40 if (arguments == null) arguments = new ArrayList<Argument>();
44 methodName = sh.serviceType;
46 nucleotidesAllowed = true;
47 proteinAllowed = false;
51 protected void initViewportParams()
53 ((jalview.gui.AlignViewport) alignViewport).setCalcIdSettingsFor(
55 new AAConSettings(true, service, this.preset,
56 (arguments != null) ? JabaParamStore
57 .getJwsArgsfromJaba(arguments) : null), true);
61 public String getServiceActionText()
63 return "Submitting RNA alignment for Secondary Structure prediction using "
64 + "RNAalifold Service";
69 public void updateResultAnnotation(boolean immediate)
72 if (immediate || !calcMan.isWorking(this) && scoremanager != null)
75 List<AlignmentAnnotation> ourAnnot = new ArrayList<AlignmentAnnotation>();
77 // Unpack the ScoreManager
78 List<String> structs = ((RNAStructScoreManager) scoremanager).getStructs();
79 List<TreeSet<Score>> data = ((RNAStructScoreManager) scoremanager).getData();
81 // test to see if this data object contains base pair contacts
82 Score fscore = data.get(0).first();
83 this.bpScores = (fscore.getMethod().equals(
84 AlifoldResult.contactProbabilities.toString()));
86 // add annotation for the consensus sequence alignment
87 createAnnotationRowforScoreHolder(ourAnnot, getCalcId(), structs.get(0),
90 // Add annotations for the mfe Structure
91 createAnnotationRowforScoreHolder(ourAnnot, getCalcId(), structs.get(1),
94 // decide whether to add base pair contact probability histogram
97 createAnnotationRowforScoreHolder(ourAnnot, getCalcId(), structs.get(2),
98 data.get(0), data.get(2));
103 // Now loop for the rest of the Annotations (if there it isn't stochastic output
104 // only the centroid and MEA structures remain anyway)
105 for (int i = count; i < structs.size(); i++) {
106 // The ensemble values should be displayed in the description of the
107 // first (or all?) Stochastic Backtrack Structures.
108 if (!data.get(i).first().getMethod().equals(
109 AlifoldResult.ensembleValues.toString())) {
111 createAnnotationRowforScoreHolder(ourAnnot, getCalcId(), structs.get(i),
116 if (ourAnnot.size() > 0) {
118 updateOurAnnots(ourAnnot);
119 ap.adjustAnnotationHeight();
124 protected void createAnnotationRowforScoreHolder(
125 List<AlignmentAnnotation> ourAnnot, String calcId,
126 String struct, TreeSet<Score> data, TreeSet<Score> descriptionData)
128 /* If contactProbability information is returned from RNAalifold it is stored
129 * in the first TreeSet<Score> object corresponding to the String Id which
130 * holds the consensus alignment. The method enumeration is then updated to
131 * AlifoldResult.contactProbabilties. This line recreates the same
132 * data object as was overwritten with the contact probabilites data.
134 if (data == null) data = compbio.data.sequence.RNAStructReader
135 .newEmptyScore(AlifoldResult.consensusAlignment);
137 if (descriptionData == null) descriptionData = data;
139 String[] typenameAndDescription = constructTypenameAndDescription(
140 descriptionData.first());
141 String typename = typenameAndDescription[0];
142 String description = typenameAndDescription[1];
145 AlignmentAnnotation annotation = alignViewport.getAlignment()
146 .findOrCreateAnnotation(typename, calcId, false, null, null);
148 constructAnnotationFromScoreHolder(annotation, struct, data);
150 /* update annotation description with the free Energy, frequency in ensemble
151 * or other data where appropriate.
153 * Doesnt deal with AlifoldResult.ensembleValues, the free energy of ensemble
154 * and frequency of mfe structure in ensemble. How to deal with these?
156 annotation.description = description;
158 annotation.belowAlignment = false;
159 // annotation.showAllColLabels = true;
161 alignViewport.getAlignment().validateAnnotation(annotation);
162 af.setMenusForViewport();
164 ourAnnot.add(annotation);
169 private AlignmentAnnotation constructAnnotationFromScoreHolder(
170 AlignmentAnnotation annotation, String struct, TreeSet<Score> data)
172 Annotation[] anns = new Annotation[struct.length()];
174 if (data != null && data.size() > 1 && data.first().getMethod().equals(
175 AlifoldResult.contactProbabilities.toString()))
178 // The base pair probabilities are stored in a set in scoreholder. we want a map
179 LinkedHashMap<Range, Float> basePairs = new LinkedHashMap<Range, Float>();
180 for (Score score : data) {
181 // The Score objects contain a set of size one containing the range and
182 // an ArrayList<float> of size one containing the probabilty
183 basePairs.put(score.getRanges().first(), new Float(score.getScores().get(0)));
185 for (int i = 0; i < struct.length(); i++) {
187 // Return all the contacts associated with position i
188 LinkedHashMap<Range, Float> contacts = isContact(basePairs, i+1);
190 String description = "";
193 if (contacts.size() == 0) {
194 description = "No Data";
197 for (Range contact : contacts.keySet()) {
198 float t = contacts.get(contact);
199 if (t > prob) prob = t;
200 description += Integer.toString(contact.from) + "->"
201 + Integer.toString(contact.to) + ": " + Float.toString(t) + "% | ";
205 anns[i] = new Annotation(struct.substring(i, i+1), description,
206 isSS(struct.charAt(i)), prob);
209 else if (data == null || data.size() == 1) {
210 for (int i = 0; i < struct.length(); i++) {
212 anns[i] = new Annotation(struct.substring(i, i+1), "",
213 isSS(struct.charAt(i)), Float.NaN);
216 annotation.graph = 0; // No graph
219 annotation.annotations = anns;
224 private String[] constructTypenameAndDescription(Score score) {
225 String description = "";
226 String typename = "";
227 String datatype = score.getMethod();
230 // Look up java switch syntax and use one here
231 if (datatype.equals(AlifoldResult.mfeStructure.toString())) {
233 description = MessageFormat.format("Minimum Free Energy Structure. Energy: {0} = {1} + {2}",
234 score.getScores().get(0), score.getScores().get(1), score.getScores().get(2));
235 typename = "MFE Structure";
237 else if (datatype.equals(AlifoldResult.contactProbabilityStructure.toString())) {
238 description = MessageFormat.format("Base Pair Contact Probabilities. "
239 + "Energy of Ensemble: {0} Frequency of Ensemble: {1}",
240 score.getScores().get(0), score.getScores().get(1));
241 typename = "Contact Probabilities";
243 else if (datatype.equals(AlifoldResult.centroidStructure.toString())) {
244 description = MessageFormat.format("Centroid Structure. Energy: {0} = {1} + {2}",
245 score.getScores().get(0), score.getScores().get(1), score.getScores().get(2));
246 typename = "Centroid Structure";
248 else if (datatype.equals(AlifoldResult.stochBTStructure.toString())) {
249 if (score.getScores().size() > 0) {
250 description = MessageFormat.format("Probability: {0} Energy: {1}",
251 score.getScores().get(0), score.getScores().get(1));
253 else description = "Stochastic Backtrack Structure";
255 else if (datatype.equals(AlifoldResult.MEAStucture.toString())) {
256 description = MessageFormat.format("Maximum Expected Accuracy Values: '{' {0} MEA={1} '}",
257 score.getScores().get(0), score.getScores().get(1));
258 typename = "MEA Structure";
260 else if (datatype.equals(AlifoldResult.consensusAlignment.toString())) {
261 typename = "RNAalifold Consensus";
262 description = "Consensus Alignment Produced by RNAalifold";
266 description = typename;
269 return new String[] {typename, description};
272 // Check whether, at position i there is a base contact and return all the
273 // contacts at this position. Should be in order of descending probability.
274 private LinkedHashMap<Range, Float> isContact(LinkedHashMap<Range,
275 Float> basePairs, int i)
277 LinkedHashMap<Range, Float> contacts = new LinkedHashMap<Range, Float>();
279 for (Range contact : basePairs.keySet()) {
280 // finds the contacts associtated with position i ordered by the natural
281 // ordering of the Scores TreeSet in ScoreManager which is, descending probability
282 if (contact.from == i || contact.to == i)
283 contacts.put(contact, basePairs.get(contact));
289 private char isSS (char chr) {
290 String regex = "\\(|\\)|\\{|\\}|\\[|\\]";
291 char ss = (Pattern.matches(regex, Character.toString(chr))) ? 'S': ' ';
295 public String getCalcId()
297 return SequenceAnnotationWSClient.AAConCalcId;