Merge remote-tracking branch 'origin/tasks/JAL-3070_wsinterfaces' into alpha/JAL...
[jalview.git] / src / jalview / ws / jws2 / jabaws2 / AADisorderClient.java
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.jabaws2;
22
23 import jalview.analysis.AlignmentAnnotationUtils;
24 import jalview.api.FeatureColourI;
25 import jalview.bin.Cache;
26 import jalview.datamodel.AlignmentAnnotation;
27 import jalview.datamodel.AlignmentI;
28 import jalview.datamodel.GraphLine;
29 import jalview.datamodel.SequenceFeature;
30 import jalview.datamodel.SequenceI;
31 import jalview.datamodel.features.FeatureMatcherSetI;
32 import jalview.schemes.FeatureColour;
33 import jalview.util.ColorUtils;
34
35 import java.awt.Color;
36 import java.util.ArrayList;
37 import java.util.HashMap;
38 import java.util.Hashtable;
39 import java.util.Iterator;
40 import java.util.List;
41 import java.util.Map;
42
43 import compbio.data.sequence.Range;
44 import compbio.data.sequence.Score;
45 import compbio.data.sequence.ScoreManager.ScoreHolder;
46
47 public class AADisorderClient extends JabawsAnnotationInstance
48 {
49   // static configuration
50   public static String getServiceActionText()
51   {
52     return "Submitting amino acid sequences for disorder prediction.";
53   }
54
55   // minSeq = 1; protein only, no gaps
56
57   // instance
58   public AADisorderClient(Jws2Instance handle)
59   {
60     super(handle);
61
62   }
63
64   @Override
65   List<AlignmentAnnotation> annotationFromScoreManager(AlignmentI seqs,
66           Map<String, FeatureColourI> featureColours,
67           Map<String, FeatureMatcherSetI> featureFilters)
68   {
69
70     Map<String, String[]> featureTypeMap = featureMap.get(our.getName());
71     Map<String, Map<String, Object>> annotTypeMap = annotMap
72             .get(our.getName());
73     boolean dispFeatures = false;
74     Map<String, SequenceFeature> fc = new Hashtable<>(),
75             fex = new Hashtable();
76     List<AlignmentAnnotation> ourAnnot = new ArrayList<>();
77     int graphGroup = 1, lastAnnot = 0;
78
79     for (SequenceI seq : seqs.getSequences())
80     {
81       String seqId = seq.getName();
82       boolean sameGroup = false;
83       SequenceI dseq, aseq;
84       int base = seq.findPosition(0) - 1;
85       aseq = seq;
86       while ((dseq = seq).getDatasetSequence() != null)
87       {
88         seq = seq.getDatasetSequence();
89       }
90       ScoreHolder scores = null;
91       try
92       {
93         scores = scoremanager.getAnnotationForSequence(seqId);
94       } catch (Exception q)
95       {
96         Cache.log.info("Couldn't recover disorder prediction for sequence "
97                 + seq.getName() + "(Prediction name was " + seqId + ")"
98                 + "\nSee http://issues.jalview.org/browse/JAL-1319 for one possible reason why disorder predictions might fail.",
99                 q);
100       }
101       float last = Float.NaN, val = Float.NaN;
102       if (scores != null && scores.scores != null)
103       {
104         for (Score scr : scores.scores)
105         {
106
107           if (scr.getRanges() != null && scr.getRanges().size() > 0)
108           {
109             Iterator<Float> vals = scr.getScores().iterator();
110             // make features on sequence
111             for (Range rn : scr.getRanges())
112             {
113               // TODO: Create virtual feature settings
114               SequenceFeature sf;
115               String[] type = featureTypeMap.get(scr.getMethod());
116               if (type == null)
117               {
118                 // create a default type for this feature
119                 type = new String[] {
120                     typeName + " (" + scr.getMethod() + ")",
121                     our.getActionText() };
122               }
123               if (vals.hasNext())
124               {
125                 val = vals.next().floatValue();
126                 sf = new SequenceFeature(type[0], type[1], base + rn.from,
127                         base + rn.to, val, methodName);
128               }
129               else
130               {
131                 sf = new SequenceFeature(type[0], type[1], base + rn.from,
132                         base + rn.to, methodName);
133               }
134               dseq.addSequenceFeature(sf);
135               // mark feature as requiring a graduated colourscheme if has
136               // variable scores
137               if (!Float.isNaN(last) && !Float.isNaN(val) && last != val)
138               {
139                 fc.put(sf.getType(), sf);
140               } else 
141               {
142                 fex.put(sf.getType(), sf);
143               }
144               last = val;
145               dispFeatures = true;
146             }
147           }
148           else
149           {
150             if (scr.getScores().size() == 0)
151             {
152               continue;
153             }
154             String typename, calcName;
155             AlignmentAnnotation annot = createAnnotationRowsForScores(
156                     seqs, null, ourAnnot,
157                     typename = our.getName() + " (" + scr.getMethod() + ")",
158                     calcName = our.getNameURI() + "/" + scr.getMethod(),
159                     aseq, base + 1, scr);
160             annot.graph = AlignmentAnnotation.LINE_GRAPH;
161
162             Map<String, Object> styleMap = (annotTypeMap == null) ? null
163                     : annotTypeMap.get(scr.getMethod());
164
165             annot.visible = (styleMap == null
166                     || styleMap.get(INVISIBLE) == null);
167             double[] thrsh = (styleMap == null) ? null
168                     : (double[]) styleMap.get(THRESHOLD);
169             float[] range = (styleMap == null) ? null
170                     : (float[]) styleMap.get(RANGE);
171             if (range != null)
172             {
173               annot.graphMin = range[0];
174               annot.graphMax = range[1];
175             }
176             if (styleMap == null || styleMap.get(DONTCOMBINE) == null)
177             {
178               {
179                 if (!sameGroup)
180                 {
181                   graphGroup++;
182                   sameGroup = true;
183                 }
184
185                 annot.graphGroup = graphGroup;
186               }
187             }
188
189             annot.description = "<html>" + our.getActionText()
190                     + " - raw scores";
191             if (thrsh != null)
192             {
193               String threshNote = (thrsh[0] > 0 ? "Above " : "Below ")
194                       + thrsh[1] + " indicates disorder";
195               annot.threshold = new GraphLine((float) thrsh[1], threshNote,
196                       Color.red);
197               annot.description += "<br/>" + threshNote;
198             }
199             annot.description += "</html>";
200             Color col = ColorUtils
201                     .createColourFromName(typeName + scr.getMethod());
202             for (int p = 0, ps = annot.annotations.length; p < ps; p++)
203             {
204               if (annot.annotations[p] != null)
205               {
206                 annot.annotations[p].colour = col;
207               }
208             }
209             annot._linecolour = col;
210             // finally, update any dataset annotation
211             AlignmentAnnotationUtils.replaceAnnotationOnAlignmentWith(annot,
212                     typename, calcName);
213           }
214         }
215       }
216       if (lastAnnot + 1 == ourAnnot.size())
217       {
218         // remove singleton alignment annotation row
219         ourAnnot.get(lastAnnot).graphGroup = -1;
220       }
221     }
222     {
223       if (dispFeatures)
224       {
225         // TODO: virtual feature settings
226         // feature colours need to merged with current viewport's colours
227         // simple feature colours promoted to colour-by-score ranges using
228         // currently assigned or created feature colour
229         for (String ft : fex.keySet())
230         {
231           Color col = ColorUtils.createColourFromName(ft);
232           // set graduated color as fading to white for minimum, and
233           // autoscaling to values on alignment
234           
235           FeatureColourI ggc;
236           if (fc.get(ft) != null)
237           {
238             ggc = new FeatureColour(col, Color.white, col,
239
240                   Color.white, Float.MIN_VALUE, Float.MAX_VALUE);
241             ggc.setAutoScaled(true);
242           }
243           else
244           {
245             ggc = new FeatureColour(col);
246           }
247           featureColours.put(ft, ggc);
248         }
249
250       }
251       return ourAnnot;
252     }
253   }
254
255   private static final String THRESHOLD = "THRESHOLD";
256
257   private static final String RANGE = "RANGE";
258
259   String typeName;
260
261   String methodName;
262
263   String groupName;
264
265   private static Map<String, Map<String, String[]>> featureMap;
266
267   private static Map<String, Map<String, Map<String, Object>>> annotMap;
268
269   private static String DONTCOMBINE = "DONTCOMBINE";
270
271   private static String INVISIBLE = "INVISIBLE";
272   static
273   {
274     // TODO: turn this into some kind of configuration file that's a bit easier
275     // to edit
276     featureMap = new HashMap<>();
277     Map<String, String[]> fmap;
278     featureMap.put(compbio.ws.client.Services.IUPredWS.toString(),
279             fmap = new HashMap<>());
280     fmap.put("Glob",
281             new String[]
282             { "Globular Domain", "Predicted globular domain" });
283     featureMap.put(compbio.ws.client.Services.JronnWS.toString(),
284             fmap = new HashMap<>());
285     featureMap.put(compbio.ws.client.Services.DisemblWS.toString(),
286             fmap = new HashMap<>());
287     fmap.put("REM465", new String[] { "REM465", "Missing density" });
288     fmap.put("HOTLOOPS", new String[] { "HOTLOOPS", "Flexible loops" });
289     fmap.put("COILS", new String[] { "COILS", "Random coil" });
290     featureMap.put(compbio.ws.client.Services.GlobPlotWS.toString(),
291             fmap = new HashMap<>());
292     fmap.put("GlobDoms",
293             new String[]
294             { "Globular Domain", "Predicted globular domain" });
295     fmap.put("Disorder",
296             new String[]
297             { "Protein Disorder", "Probable unstructured peptide region" });
298     Map<String, Map<String, Object>> amap;
299     annotMap = new HashMap<>();
300     annotMap.put(compbio.ws.client.Services.GlobPlotWS.toString(),
301             amap = new HashMap<>());
302     amap.put("Dydx", new HashMap<String, Object>());
303     amap.get("Dydx").put(DONTCOMBINE, DONTCOMBINE);
304     amap.get("Dydx").put(THRESHOLD, new double[] { 1, 0 });
305     amap.get("Dydx").put(RANGE, new float[] { -1, +1 });
306
307     amap.put("SmoothedScore", new HashMap<String, Object>());
308     amap.get("SmoothedScore").put(INVISIBLE, INVISIBLE);
309     amap.put("RawScore", new HashMap<String, Object>());
310     amap.get("RawScore").put(INVISIBLE, INVISIBLE);
311     annotMap.put(compbio.ws.client.Services.DisemblWS.toString(),
312             amap = new HashMap<>());
313     amap.put("COILS", new HashMap<String, Object>());
314     amap.put("HOTLOOPS", new HashMap<String, Object>());
315     amap.put("REM465", new HashMap<String, Object>());
316     amap.get("COILS").put(THRESHOLD, new double[] { 1, 0.516 });
317     amap.get("COILS").put(RANGE, new float[] { 0, 1 });
318
319     amap.get("HOTLOOPS").put(THRESHOLD, new double[] { 1, 0.6 });
320     amap.get("HOTLOOPS").put(RANGE, new float[] { 0, 1 });
321     amap.get("REM465").put(THRESHOLD, new double[] { 1, 0.1204 });
322     amap.get("REM465").put(RANGE, new float[] { 0, 1 });
323
324     annotMap.put(compbio.ws.client.Services.IUPredWS.toString(),
325             amap = new HashMap<>());
326     amap.put("Long", new HashMap<String, Object>());
327     amap.put("Short", new HashMap<String, Object>());
328     amap.get("Long").put(THRESHOLD, new double[] { 1, 0.5 });
329     amap.get("Long").put(RANGE, new float[] { 0, 1 });
330     amap.get("Short").put(THRESHOLD, new double[] { 1, 0.5 });
331     amap.get("Short").put(RANGE, new float[] { 0, 1 });
332     annotMap.put(compbio.ws.client.Services.JronnWS.toString(),
333             amap = new HashMap<>());
334     amap.put("JRonn", new HashMap<String, Object>());
335     amap.get("JRonn").put(THRESHOLD, new double[] { 1, 0.5 });
336     amap.get("JRonn").put(RANGE, new float[] { 0, 1 });
337   }
338
339 }