Clover icon

Coverage Report

  1. Project Clover database Mon Sep 2 2024 17:57:51 BST
  2. Package jalview.ws.jws2

File RNAalifoldClient.java

 

Coverage histogram

../../../img/srcFileCovDistChart1.png
56% of files have more coverage

Code metrics

56
108
11
1
402
282
46
0.43
9.82
11
4.18

Classes

Class Line # Actions
RNAalifoldClient 52 108 46
0.0114285711.1%
 

Contributing tests

This file is covered by 3 tests. .

Source view

1    /*
2    * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3    * Copyright (C) $$Year-Rel$$ The Jalview Authors
4    *
5    * This file is part of Jalview.
6    *
7    * Jalview is free software: you can redistribute it and/or
8    * modify it under the terms of the GNU General Public License
9    * as published by the Free Software Foundation, either version 3
10    * of the License, or (at your option) any later version.
11    *
12    * Jalview is distributed in the hope that it will be useful, but
13    * WITHOUT ANY WARRANTY; without even the implied warranty
14    * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15    * PURPOSE. See the GNU General Public License for more details.
16    *
17    * You should have received a copy of the GNU General Public License
18    * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19    * The Jalview Authors are detailed in the 'AUTHORS' file.
20    */
21    package jalview.ws.jws2;
22   
23    import jalview.datamodel.AlignmentAnnotation;
24    import jalview.datamodel.Annotation;
25    import jalview.gui.AlignFrame;
26    import jalview.util.MessageManager;
27    import jalview.ws.jws2.jabaws2.Jws2Instance;
28    import jalview.ws.params.WsParamSetI;
29    import jalview.ws.uimodel.AlignAnalysisUIText;
30   
31    import java.text.MessageFormat;
32    import java.util.ArrayList;
33    import java.util.LinkedHashMap;
34    import java.util.List;
35    import java.util.TreeSet;
36    import java.util.regex.Pattern;
37   
38    import compbio.data.sequence.FastaSequence;
39    import compbio.data.sequence.RNAStructReader.AlifoldResult;
40    import compbio.data.sequence.RNAStructScoreManager;
41    import compbio.data.sequence.Range;
42    import compbio.data.sequence.Score;
43    import compbio.metadata.Argument;
44   
45    /**
46    * Client for the JABA RNA Alifold Service
47    *
48    * @author daluke - Daniel Barton
49    *
50    */
51   
 
52    public class RNAalifoldClient extends JabawsCalcWorker
53    {
54   
55    String methodName;
56   
57    AlignFrame af;
58   
59    // keeps track of whether the RNAalifold result includes base contact
60    // probabilities
61    boolean bpScores;
62   
 
63  0 toggle public RNAalifoldClient(Jws2Instance sh, AlignFrame alignFrame,
64    WsParamSetI preset, List<Argument> paramset)
65    {
66  0 super(sh, alignFrame, preset, paramset);
67  0 af = alignFrame;
68  0 methodName = sh.serviceType;
69  0 alignedSeqs = true;
70  0 submitGaps = true;
71  0 nucleotidesAllowed = true;
72  0 proteinAllowed = false;
73  0 initViewportParams();
74    }
75   
 
76  0 toggle @Override
77    public String getCalcId()
78    {
79  0 return CALC_ID;
80    }
81   
82    private static String CALC_ID = "jalview.ws.jws2.RNAalifoldClient";
83   
 
84  6 toggle public static AlignAnalysisUIText getAlignAnalysisUITest()
85    {
86  6 return new AlignAnalysisUIText(
87    compbio.ws.client.Services.RNAalifoldWS.toString(),
88    jalview.ws.jws2.RNAalifoldClient.class, CALC_ID, true, false,
89    true, MessageManager.getString("label.rnalifold_calculations"),
90    MessageManager.getString("tooltip.rnalifold_calculations"),
91    MessageManager.getString("label.rnalifold_settings"),
92    MessageManager.getString("tooltip.rnalifold_settings"));
93    }
94   
 
95  0 toggle @Override
96    public String getServiceActionText()
97    {
98  0 return "Submitting RNA alignment for Secondary Structure prediction using "
99    + "RNAalifold Service";
100    }
101   
 
102  0 toggle @Override
103    boolean checkValidInputSeqs(boolean dynamic, List<FastaSequence> seqs)
104    {
105  0 return (seqs.size() > 1);
106    }
107   
 
108  0 toggle @Override
109    public void updateResultAnnotation(boolean immediate)
110    {
111   
112  0 if (immediate || !calcMan.isWorking(this) && scoremanager != null)
113    {
114   
115  0 List<AlignmentAnnotation> ourAnnot = new ArrayList<AlignmentAnnotation>();
116   
117    // Unpack the ScoreManager
118  0 List<String> structs = ((RNAStructScoreManager) scoremanager)
119    .getStructs();
120  0 List<TreeSet<Score>> data = ((RNAStructScoreManager) scoremanager)
121    .getData();
122   
123    // test to see if this data object contains base pair contacts
124  0 Score fscore = data.get(0).first();
125  0 this.bpScores = (fscore.getMethod()
126    .equals(AlifoldResult.contactProbabilities.toString()));
127   
128    // add annotation for the consensus sequence alignment
129  0 createAnnotationRowforScoreHolder(ourAnnot, getCalcId(),
130    structs.get(0), null, null);
131   
132    // Add annotations for the mfe Structure
133  0 createAnnotationRowforScoreHolder(ourAnnot, getCalcId(),
134    structs.get(1), data.get(1), null);
135   
136    // decide whether to add base pair contact probability histogram
137  0 int count = 2;
138  0 if (bpScores)
139    {
140  0 createAnnotationRowforScoreHolder(ourAnnot, getCalcId(),
141    structs.get(2), data.get(0), data.get(2));
142  0 count++;
143    }
144   
145    // Now loop for the rest of the Annotations (if there it isn't stochastic
146    // output
147    // only the centroid and MEA structures remain anyway)
148  0 for (int i = count; i < structs.size(); i++)
149    {
150    // The ensemble values should be displayed in the description of the
151    // first (or all?) Stochastic Backtrack Structures.
152  0 if (!data.get(i).first().getMethod()
153    .equals(AlifoldResult.ensembleValues.toString()))
154    {
155   
156  0 createAnnotationRowforScoreHolder(ourAnnot, getCalcId(),
157    structs.get(i), data.get(i), null);
158    }
159    }
160   
161  0 if (ourAnnot.size() > 0)
162    {
163   
164  0 updateOurAnnots(ourAnnot);
165  0 ap.adjustAnnotationHeight();
166    }
167    }
168    }
169   
 
170  0 toggle protected void createAnnotationRowforScoreHolder(
171    List<AlignmentAnnotation> ourAnnot, String calcId, String struct,
172    TreeSet<Score> data, TreeSet<Score> descriptionData)
173    {
174    /*
175    * If contactProbability information is returned from RNAalifold it is
176    * stored in the first TreeSet<Score> object corresponding to the String Id
177    * which holds the consensus alignment. The method enumeration is then
178    * updated to AlifoldResult.contactProbabilties. This line recreates the
179    * same data object as was overwritten with the contact probabilites data.
180    */
181  0 if (data == null)
182    {
183  0 data = compbio.data.sequence.RNAStructReader
184    .newEmptyScore(AlifoldResult.consensusAlignment);
185    }
186   
187  0 if (descriptionData == null)
188    {
189  0 descriptionData = data;
190    }
191   
192  0 String[] typenameAndDescription = constructTypenameAndDescription(
193    descriptionData.first());
194  0 String typename = typenameAndDescription[0];
195  0 String description = typenameAndDescription[1];
196   
197  0 AlignmentAnnotation annotation = alignViewport.getAlignment()
198    .findOrCreateAnnotation(typename, calcId, false, null, null);
199   
200  0 constructAnnotationFromScoreHolder(annotation, struct, data);
201   
202    /*
203    * update annotation description with the free Energy, frequency in ensemble
204    * or other data where appropriate.
205    *
206    * Doesnt deal with AlifoldResult.ensembleValues, the free energy of
207    * ensemble and frequency of mfe structure in ensemble. How to deal with
208    * these?
209    */
210  0 annotation.description = description;
211   
212  0 annotation.belowAlignment = false;
213    // annotation.showAllColLabels = true;
214   
215  0 alignViewport.getAlignment().validateAnnotation(annotation);
216  0 af.setMenusForViewport();
217   
218  0 ourAnnot.add(annotation);
219    }
220   
 
221  0 toggle private AlignmentAnnotation constructAnnotationFromScoreHolder(
222    AlignmentAnnotation annotation, String struct,
223    TreeSet<Score> data)
224    {
225  0 Annotation[] anns = new Annotation[gapMap != null ? gapMap.length + 1
226    : struct.length()];
227   
228  0 if (data != null && data.size() > 1 && data.first().getMethod()
229    .equals(AlifoldResult.contactProbabilities.toString()))
230    {
231   
232    // The base pair probabilities are stored in a set in scoreholder. we want
233    // a map
234  0 LinkedHashMap<Range, Float> basePairs = new LinkedHashMap<Range, Float>();
235  0 for (Score score : data)
236    {
237    // The Score objects contain a set of size one containing the range and
238    // an ArrayList<float> of size one containing the probabilty
239  0 basePairs.put(score.getRanges().first(),
240    Float.valueOf(score.getScores().get(0)));
241    }
242   
243  0 for (int i = 0, ri = 0, iEnd = struct.length(); i < iEnd; i++, ri++)
244    {
245  0 if (gapMap != null)
246    {
247    // skip any gapped columns in the input data
248  0 while (!gapMap[ri])
249    {
250  0 ri++;
251    }
252    }
253    // Return all the contacts associated with position i
254  0 LinkedHashMap<Range, Float> contacts = isContact(basePairs, i + 1);
255   
256  0 String description = "";
257  0 float prob = 0f;
258   
259  0 if (contacts.size() == 0)
260    {
261  0 description = "No Data";
262    }
263    else
264    {
265  0 for (Range contact : contacts.keySet())
266    {
267  0 float t = contacts.get(contact);
268  0 if (t > prob)
269    {
270  0 prob = t;
271    }
272  0 description += Integer.toString(contact.from) + "->"
273    + Integer.toString(contact.to) + ": "
274    + Float.toString(t) + "% | ";
275    }
276    }
277   
278  0 anns[ri] = new Annotation(struct.substring(i, i + 1), description,
279    isSS(struct.charAt(i)), prob);
280    }
281    }
282  0 else if (data == null || data.size() == 1)
283    {
284  0 for (int i = 0, ri = 0, iEnd = struct.length(); i < iEnd; i++, ri++)
285    {
286  0 if (gapMap != null)
287    {
288    // skip any gapped columns in the input data
289  0 while (!gapMap[ri] && ri < gapMap.length)
290    {
291  0 ri++;
292    }
293  0 if (ri == gapMap.length)
294    {
295  0 break;
296    }
297    }
298  0 anns[ri] = new Annotation(struct.substring(i, i + 1), "",
299    isSS(struct.charAt(i)), Float.NaN);
300    }
301   
302  0 annotation.graph = 0; // No graph
303    }
304   
305  0 annotation.annotations = anns;
306   
307  0 return annotation;
308    }
309   
 
310  0 toggle private String[] constructTypenameAndDescription(Score score)
311    {
312  0 String description = "";
313  0 String typename = "";
314  0 String datatype = score.getMethod();
315   
316    // Look up java switch syntax and use one here
317  0 if (datatype.equals(AlifoldResult.mfeStructure.toString()))
318    {
319   
320  0 description = MessageFormat.format(
321    "Minimum Free Energy Structure. Energy: {0} = {1} + {2}",
322    score.getScores().get(0), score.getScores().get(1),
323    score.getScores().get(2));
324  0 typename = "MFE Structure";
325    }
326  0 else if (datatype
327    .equals(AlifoldResult.contactProbabilityStructure.toString()))
328    {
329  0 description = MessageFormat.format("Base Pair Contact Probabilities. "
330    + "Energy of Ensemble: {0} Frequency of Ensemble: {1}",
331    score.getScores().get(0), score.getScores().get(1));
332  0 typename = "Contact Probabilities";
333    }
334  0 else if (datatype.equals(AlifoldResult.centroidStructure.toString()))
335    {
336  0 description = MessageFormat.format(
337    "Centroid Structure. Energy: {0} = {1} + {2}",
338    score.getScores().get(0), score.getScores().get(1),
339    score.getScores().get(2));
340  0 typename = "Centroid Structure";
341    }
342  0 else if (datatype.equals(AlifoldResult.stochBTStructure.toString()))
343    {
344  0 if (score.getScores().size() > 0)
345    {
346  0 description = MessageFormat.format("Probability: {0} Energy: {1}",
347    score.getScores().get(0), score.getScores().get(1));
348    }
349    else
350    {
351  0 description = "Stochastic Backtrack Structure";
352    }
353    }
354  0 else if (datatype.equals(AlifoldResult.MEAStucture.toString()))
355    {
356  0 description = MessageFormat.format(
357    "Maximum Expected Accuracy Values: '{' {0} MEA={1} '}",
358    score.getScores().get(0), score.getScores().get(1));
359  0 typename = "MEA Structure";
360    }
361  0 else if (datatype.equals(AlifoldResult.consensusAlignment.toString()))
362    {
363  0 typename = "RNAalifold Consensus";
364  0 description = "Consensus Alignment Produced by RNAalifold";
365    }
366    else
367    {
368  0 typename = datatype;
369  0 description = typename;
370    }
371   
372  0 return new String[] { typename, description };
373    }
374   
375    // Check whether, at position i there is a base contact and return all the
376    // contacts at this position. Should be in order of descending probability.
 
377  0 toggle private LinkedHashMap<Range, Float> isContact(
378    LinkedHashMap<Range, Float> basePairs, int i)
379    {
380  0 LinkedHashMap<Range, Float> contacts = new LinkedHashMap<Range, Float>();
381   
382  0 for (Range contact : basePairs.keySet())
383    {
384    // finds the contacts associtated with position i ordered by the natural
385    // ordering of the Scores TreeSet in ScoreManager which is, descending
386    // probability
387  0 if (contact.from == i || contact.to == i)
388    {
389  0 contacts.put(contact, basePairs.get(contact));
390    }
391    }
392   
393  0 return contacts;
394    }
395   
 
396  0 toggle private char isSS(char chr)
397    {
398  0 String regex = "\\(|\\)|\\{|\\}|\\[|\\]";
399  0 char ss = (Pattern.matches(regex, Character.toString(chr))) ? 'S' : ' ';
400  0 return ss;
401    }
402    }