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.TreeMap;
17 import java.util.TreeSet;
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;
25 public class RNAalifoldClient extends JabawsAlignCalcWorker implements
35 // keeps track of whether the RNAalifold result includes base contact probabilities
38 public RNAalifoldClient(Jws2Instance sh, AlignFrame alignFrame,
39 WsParamSetI preset, List<Argument> paramset)
41 super(sh, alignFrame, preset, paramset);
43 if (arguments == null) arguments = new ArrayList<Argument>();
44 arguments.add(sh.getRunnerConfig().getArgumentByOptionName("-p"));
48 methodName = sh.serviceType;
50 // defult false. Which one here?
52 nucleotidesAllowed = true;
53 proteinAllowed = false;
55 arguments.add(sh.getRunnerConfig().getArgumentByOptionName("-p"));
59 public String getServiceActionText()
61 return "Submitting RNA alignment for Secondary Structure prediction using "
62 + "RNAalifold Service";
67 public void updateResultAnnotation(boolean immediate)
70 if (immediate || !calcMan.isWorking(this) && scoremanager != null)
73 List<AlignmentAnnotation> ourAnnot = new ArrayList<AlignmentAnnotation>();
75 // Unpack the ScoreManager
76 List<String> structs = ((RNAStructScoreManager) scoremanager).getStructs();
77 List<TreeSet<Score>> data = ((RNAStructScoreManager) scoremanager).getData();
79 // test to see if this data object contains base pair contacts
80 Score fscore = data.get(0).first();
81 this.bpScores = (fscore.getMethod().equals(
82 AlifoldResult.contactProbabilities.toString()));
84 // Add annotations for the mfe Structure
86 createAnnotationRowforScoreHolder(ourAnnot, getCalcId(), structs.get(1),
87 data.get(0), data.get(1));
89 createAnnotationRowforScoreHolder(ourAnnot, getCalcId(), structs.get(1),
92 // add annotation for the consensus sequence alignment
93 createAnnotationRowforScoreHolder(ourAnnot, getCalcId(), structs.get(0), null);
95 // Not loop for the rest of the Annotations
96 if (structs.size() > 2) {
97 for (int i = 2; i < structs.size(); i++) {
98 // I can't think of a nice way of presenting the ensembleValues data
100 if (!data.get(i).first().getMethod().equals(
101 AlifoldResult.ensembleValues.toString())) {
102 createAnnotationRowforScoreHolder(ourAnnot, getCalcId(), structs.get(i),
109 if (ourAnnot.size() > 0) {
111 // Modify the visible annotation on the alignment viewport with the
112 // new alignment annotation rows created.
113 updateOurAnnots(ourAnnot);
114 // ap.adjustAnnotationHeight();
119 // just for the base pair contact annotation. It uses a second score object.
120 protected void createAnnotationRowforScoreHolder(
121 List<AlignmentAnnotation> ourAnnot, String calcId,
122 String struct, TreeSet<Score> data, TreeSet<Score> descriptionData) {
124 String typename = data.first().getMethod().toString();
126 AlignmentAnnotation annotation = alignViewport.getAlignment()
127 .findOrCreateAnnotation(typename, calcId, false, null, null);
129 constructAnnotationFromContactProbabilities(annotation, struct, data);
131 String description = constructAlignmentAnnotationDescription(descriptionData.first());
132 if (description.length() == 0) description = typename;
133 annotation.description = description;
136 annotation.belowAlignment = false;
138 annotation.validateRangeAndDisplay();
140 ourAnnot.add(annotation);
143 protected void createAnnotationRowforScoreHolder(
144 List<AlignmentAnnotation> ourAnnot, String calcId,
145 String struct, TreeSet<Score> data)
147 /* If contactProbability information is returned from RNAalifold it is stored
148 * in the first TreeSet<Score> object corresponding to the String Id which
149 * holds the consensus alignment. The method enumeration is then updated to
150 * AlifoldResult.contactProbabilties. This line (hack) recreates the same
151 * data object as was overwritten with the contact probabilites data.
153 if (data == null) data = compbio.data.sequence.RNAStructReader
154 .newEmptyScore(AlifoldResult.consensusAlignment);
156 String typename = data.first().getMethod().toString();
158 AlignmentAnnotation annotation = alignViewport.getAlignment()
159 .findOrCreateAnnotation(typename, calcId, false, null, null);
161 // construct annotation from ScoreHolder (unpacked into struct and data)
162 if (bpScores && data.first().getMethod().equals(
163 AlifoldResult.contactProbabilities.toString()))
164 constructAnnotationFromContactProbabilities(annotation, struct, data);
167 // if bpScores is false the TreeSet<Score> data should always contain
168 // a single Score object
169 constructAnnotationFromStructureString(annotation, struct, data.first());
171 /* update annotation description with the free Energy, frequency in ensemble
172 * or other data where appropriate.
174 * Doesnt deal with AlifoldResult.ensembleValues, the free energy of ensemble
175 * and frequency of mfe structure in ensemble. How to deal with these?
177 String description = constructAlignmentAnnotationDescription(data.first());
178 if (description.length() == 0) description = typename;
179 annotation.description = description;
182 annotation.belowAlignment = false;
184 annotation.validateRangeAndDisplay();
186 ourAnnot.add(annotation);
191 private AlignmentAnnotation constructAnnotationFromStructureString(
192 AlignmentAnnotation annotation, String struct, Score score)
195 Annotation[] anns = new Annotation[struct.length()];
197 for (int i = 0; i < struct.length(); i++) {
198 anns[i] = new Annotation(struct.substring(i, i+1), "",
199 struct.charAt(i), Float.NaN);
202 annotation.graph = 0; // No graph
203 annotation.annotations = anns;
210 private String constructAlignmentAnnotationDescription(Score score) {
211 String description = "";
212 String datatype = score.getMethod();
214 if (datatype.equals(AlifoldResult.mfeStructure.toString()) ||
215 datatype.equals(AlifoldResult.centroidStructure.toString())) {
216 description = MessageFormat.format("Energy: {0} = {1} + {2}",
217 score.getScores().get(0), score.getScores().get(1), score.getScores().get(2));
219 else if (datatype.equals(AlifoldResult.contactProbabilityStructure.toString())) {
220 description = MessageFormat.format("Energy: {0} Frequency: {1}",
221 score.getScores().get(0), score.getScores().get(1));
223 else if (datatype.equals(AlifoldResult.stochBTStructure.toString())) {
224 if (score.getScores().size() > 0) {
225 description = MessageFormat.format("Probability: {0} Energy: {1}",
226 score.getScores().get(0), score.getScores().get(1));
228 else description = "Stochastic Backtrack Structure";
230 else if (datatype.equals(AlifoldResult.MEAStucture.toString())) {
231 description = MessageFormat.format("Maximum Expected Accuracy Values: '{' {0} MEA={1} '}",
232 score.getScores().get(0), score.getScores().get(1));
239 private AlignmentAnnotation constructAnnotationFromContactProbabilities(
240 AlignmentAnnotation annotation, String struct, TreeSet<Score> data)
242 Annotation[] anns = new Annotation[struct.length()];
244 TreeMap<Range, Float> basePairs = null;
245 // The base pair probabilities are stored in a set in scoreholder. we want a map
246 basePairs = new TreeMap<Range, Float>();
247 for (Score score : data) {
248 // The Score objects contain a set of size one containing the range and
249 // an ArrayList<float> of size one containing the probabilty
250 basePairs.put(score.getRanges().first(), new Float(score.getScores().get(0)));
252 for (int i = 0; i < struct.length(); i++) {
254 // Return all the contacts associated with position i
255 List<Range> contacts = isContact(basePairs, i+1);
257 if (contacts.size() == 0) {
258 anns[i] = new Annotation(struct.substring(i, i+1), "", struct.charAt(i), 0f);
260 else if (contacts.size() == 1) {
261 // There is only one contact associated with this base
262 float prob = basePairs.get(contacts.get(0));
263 anns[i] = new Annotation(struct.substring(i, i+1), "", struct.charAt(i), prob);
265 else if (contacts.size() > 1) {
266 // For now we will simply deal with alternate contact information by mentioning its
267 // existance in the description
268 float prob = basePairs.get(contacts.get(0));
269 anns[i] = new Annotation(struct.substring(i, i+1), "This base has alternate contacts",
270 struct.charAt(i), prob);
274 annotation.annotations = anns;
280 // Check whether, at position i there is a base contact and return all the
281 // contacts at this position. Should be in order of descending probability.
282 private List<Range> isContact(TreeMap<Range, Float> basePairs, int i) {
284 List<Range> contacts = new ArrayList<Range>();
286 for (Range contact : basePairs.keySet()) {
287 // finds the contacts associtated with position i ordered by the natural
288 // ordering of the Scores TreeSet in ScoreManager which is, descending probability
289 if (contact.from == i || contact.to == i) contacts.add(contact);
296 public String getCalcId()
298 return SequenceAnnotationWSClient.AAConCalcId;