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