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.jabaws2.Jws2Instance;
8 import jalview.ws.params.WsParamSetI;
10 import java.text.MessageFormat;
11 import java.util.ArrayList;
12 import java.util.Arrays;
13 import java.util.HashMap;
14 import java.util.List;
16 import java.util.LinkedHashMap;
17 import java.util.TreeSet;
18 import java.util.regex.Pattern;
20 import compbio.data.sequence.RNAStructReader.AlifoldResult;
21 import compbio.data.sequence.RNAStructScoreManager;
22 import compbio.data.sequence.Range;
23 import compbio.data.sequence.Score;
24 import compbio.metadata.Argument;
26 public class RNAalifoldClient extends JabawsAlignCalcWorker implements
34 // keeps track of whether the RNAalifold result includes base contact probabilities
37 public RNAalifoldClient(Jws2Instance sh, AlignFrame alignFrame,
38 WsParamSetI preset, List<Argument> paramset)
40 super(sh, alignFrame, preset, paramset);
42 if (arguments == null) arguments = new ArrayList<Argument>();
46 methodName = sh.serviceType;
48 nucleotidesAllowed = true;
49 proteinAllowed = false;
54 public String getServiceActionText()
56 return "Submitting RNA alignment for Secondary Structure prediction using "
57 + "RNAalifold Service";
62 public void updateResultAnnotation(boolean immediate)
65 if (immediate || !calcMan.isWorking(this) && scoremanager != null)
68 List<AlignmentAnnotation> ourAnnot = new ArrayList<AlignmentAnnotation>();
70 // Unpack the ScoreManager
71 List<String> structs = ((RNAStructScoreManager) scoremanager).getStructs();
72 List<TreeSet<Score>> data = ((RNAStructScoreManager) scoremanager).getData();
74 System.out.println("Length of RNAStructScoreManager is: " + structs.size());
76 // test to see if this data object contains base pair contacts
77 Score fscore = data.get(0).first();
78 this.bpScores = (fscore.getMethod().equals(
79 AlifoldResult.contactProbabilities.toString()));
81 // add annotation for the consensus sequence alignment
82 createAnnotationRowforScoreHolder(ourAnnot, getCalcId(), structs.get(0),
85 // Add annotations for the mfe Structure
86 createAnnotationRowforScoreHolder(ourAnnot, getCalcId(), structs.get(1),
89 // decide whether to add base pair contact probability histogram
92 createAnnotationRowforScoreHolder(ourAnnot, getCalcId(), structs.get(2),
93 data.get(0), data.get(2));
98 // Now loop for the rest of the Annotations (if there it isn't stochastic output
99 // only the centroid and MEA structures remain anyway)
100 for (int i = count; i < structs.size(); i++) {
101 // The ensemble values should be displayed in the description of the
102 // first (or all?) Stochastic Backtrack Structures.
103 if (!data.get(i).first().getMethod().equals(
104 AlifoldResult.ensembleValues.toString())) {
106 createAnnotationRowforScoreHolder(ourAnnot, getCalcId(), structs.get(i),
111 if (ourAnnot.size() > 0) {
113 updateOurAnnots(ourAnnot);
114 ap.adjustAnnotationHeight();
119 protected void createAnnotationRowforScoreHolder(
120 List<AlignmentAnnotation> ourAnnot, String calcId,
121 String struct, TreeSet<Score> data, TreeSet<Score> descriptionData)
123 /* If contactProbability information is returned from RNAalifold it is stored
124 * in the first TreeSet<Score> object corresponding to the String Id which
125 * holds the consensus alignment. The method enumeration is then updated to
126 * AlifoldResult.contactProbabilties. This line recreates the same
127 * data object as was overwritten with the contact probabilites data.
129 if (data == null) data = compbio.data.sequence.RNAStructReader
130 .newEmptyScore(AlifoldResult.consensusAlignment);
132 if (descriptionData == null) descriptionData = data;
134 String[] typenameAndDescription = constructTypenameAndDescription(
135 descriptionData.first());
136 String typename = typenameAndDescription[0];
137 String description = typenameAndDescription[1];
140 AlignmentAnnotation annotation = alignViewport.getAlignment()
141 .findOrCreateAnnotation(typename, calcId, false, null, null);
143 constructAnnotationFromScoreHolder(annotation, struct, data);
145 /* update annotation description with the free Energy, frequency in ensemble
146 * or other data where appropriate.
148 * Doesnt deal with AlifoldResult.ensembleValues, the free energy of ensemble
149 * and frequency of mfe structure in ensemble. How to deal with these?
151 annotation.description = description;
153 annotation.belowAlignment = false;
154 // annotation.showAllColLabels = true;
156 annotation.validateRangeAndDisplay();
158 ourAnnot.add(annotation);
163 private AlignmentAnnotation constructAnnotationFromScoreHolder(
164 AlignmentAnnotation annotation, String struct, TreeSet<Score> data)
166 Annotation[] anns = new Annotation[struct.length()];
168 if (data != null && data.size() > 1 && data.first().getMethod().equals(
169 AlifoldResult.contactProbabilities.toString()))
172 // The base pair probabilities are stored in a set in scoreholder. we want a map
173 LinkedHashMap<Range, Float> basePairs = new LinkedHashMap<Range, Float>();
174 for (Score score : data) {
175 // The Score objects contain a set of size one containing the range and
176 // an ArrayList<float> of size one containing the probabilty
177 basePairs.put(score.getRanges().first(), new Float(score.getScores().get(0)));
179 for (int i = 0; i < struct.length(); i++) {
181 // Return all the contacts associated with position i
182 LinkedHashMap<Range, Float> contacts = isContact(basePairs, i+1);
184 String description = "";
187 if (contacts.size() == 0) {
188 description = "No Data";
191 for (Range contact : contacts.keySet()) {
192 float t = contacts.get(contact);
193 if (t > prob) prob = t;
194 description += Integer.toString(contact.from) + "->"
195 + Integer.toString(contact.to) + ": " + Float.toString(t) + "% | ";
199 anns[i] = new Annotation(struct.substring(i, i+1), description,
200 isSS(struct.charAt(i)), prob);
203 else if (data == null || data.size() == 1) {
204 for (int i = 0; i < struct.length(); i++) {
206 anns[i] = new Annotation(struct.substring(i, i+1), "",
207 isSS(struct.charAt(i)), Float.NaN);
210 annotation.graph = 0; // No graph
213 annotation.annotations = anns;
218 private String[] constructTypenameAndDescription(Score score) {
219 String description = "";
220 String typename = "";
221 String datatype = score.getMethod();
223 if (datatype.equals(AlifoldResult.mfeStructure.toString())) {
225 description = MessageFormat.format("Minimum Free Energy Structure. Energy: {0} = {1} + {2}",
226 score.getScores().get(0), score.getScores().get(1), score.getScores().get(2));
227 typename = "MFE Structure";
229 else if (datatype.equals(AlifoldResult.contactProbabilityStructure.toString())) {
230 description = MessageFormat.format("Base Pair Contact Probabilities. "
231 + "Energy of Ensemble: {0} Frequency of Ensemble: {1}",
232 score.getScores().get(0), score.getScores().get(1));
233 typename = "Contact Probabilities";
235 else if (datatype.equals(AlifoldResult.centroidStructure.toString())) {
236 description = MessageFormat.format("Centroid Structure. Energy: {0} = {1} + {2}",
237 score.getScores().get(0), score.getScores().get(1), score.getScores().get(2));
238 typename = "Centroid Structure";
240 else if (datatype.equals(AlifoldResult.stochBTStructure.toString())) {
241 if (score.getScores().size() > 0) {
242 description = MessageFormat.format("Probability: {0} Energy: {1}",
243 score.getScores().get(0), score.getScores().get(1));
245 else description = "Stochastic Backtrack Structure";
247 else if (datatype.equals(AlifoldResult.MEAStucture.toString())) {
248 description = MessageFormat.format("Maximum Expected Accuracy Values: '{' {0} MEA={1} '}",
249 score.getScores().get(0), score.getScores().get(1));
250 typename = "MEA Structure";
252 else if (datatype.equals(AlifoldResult.consensusAlignment.toString())) {
253 typename = "RNAalifold Consensus";
254 description = "Consensus Alignment Produced by RNAalifold";
258 description = typename;
261 return new String[] {typename, description};
264 // Check whether, at position i there is a base contact and return all the
265 // contacts at this position. Should be in order of descending probability.
266 private LinkedHashMap<Range, Float> isContact(LinkedHashMap<Range,
267 Float> basePairs, int i)
269 LinkedHashMap<Range, Float> contacts = new LinkedHashMap<Range, Float>();
271 for (Range contact : basePairs.keySet()) {
272 // finds the contacts associtated with position i ordered by the natural
273 // ordering of the Scores TreeSet in ScoreManager which is, descending probability
274 if (contact.from == i || contact.to == i)
275 contacts.put(contact, basePairs.get(contact));
281 private char isSS (char chr) {
282 String regex = "\\(|\\)|\\{|\\}|\\[|\\]";
283 char ss = (Pattern.matches(regex, Character.toString(chr))) ? 'S': ' ';
287 public String getCalcId()
289 return SequenceAnnotationWSClient.AAConCalcId;