Descriptions can be added to annotations
[jalview.git] / src / jalview / io / AnnotationFile.java
1 /*\r
2  * Jalview - A Sequence Alignment Editor and Viewer\r
3  * Copyright (C) 2006 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle\r
4  *\r
5  * This program is free software; you can redistribute it and/or\r
6  * modify it under the terms of the GNU General Public License\r
7  * as published by the Free Software Foundation; either version 2\r
8  * of the License, or (at your option) any later version.\r
9  *\r
10  * This program is distributed in the hope that it will be useful,\r
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
13  * GNU General Public License for more details.\r
14  *\r
15  * You should have received a copy of the GNU General Public License\r
16  * along with this program; if not, write to the Free Software\r
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA\r
18  */\r
19 \r
20 package jalview.io;\r
21 \r
22 import java.io.*;\r
23 import jalview.datamodel.*;\r
24 import java.util.*;\r
25 import jalview.schemes.UserColourScheme;\r
26 import java.net.URL;\r
27 \r
28 \r
29 public class AnnotationFile\r
30 {\r
31 \r
32   public String printAnnotations(AlignmentAnnotation [] annotations)\r
33   {\r
34     StringBuffer text = new StringBuffer(\r
35       "JALVIEW_ANNOTATION\n"\r
36       +"# Created: "\r
37       +new java.util.Date()+"\n\n");\r
38 \r
39     AlignmentAnnotation row;\r
40     String comma;\r
41     SequenceI seqref = null;\r
42 \r
43     StringBuffer colours = new StringBuffer();\r
44     StringBuffer graphLine = new StringBuffer();\r
45 \r
46     Hashtable graphGroup = new Hashtable();\r
47 \r
48     java.awt.Color color;\r
49 \r
50     for(int i=0; i<annotations.length; i++)\r
51     {\r
52       row = annotations[i];\r
53 \r
54       if(!row.visible)\r
55         continue;\r
56 \r
57       color = null;\r
58 \r
59       if( row.sequenceRef == null)\r
60       {\r
61         if(seqref!=null)\r
62           text.append("\nSEQUENCE_REF\tALIGNMENT\n");\r
63 \r
64         seqref = null;\r
65       }\r
66 \r
67       else if (seqref == null || seqref != row.sequenceRef)\r
68       {\r
69         seqref = row.sequenceRef;\r
70         text.append("\nSEQUENCE_REF\t" + seqref.getName() + "\n");\r
71       }\r
72 \r
73 \r
74       if( row.graph == AlignmentAnnotation.NO_GRAPH)\r
75       {\r
76           text.append("NO_GRAPH\t");\r
77       }\r
78       else\r
79       {\r
80         if( row.graph == AlignmentAnnotation.BAR_GRAPH)\r
81           text.append("BAR_GRAPH\t");\r
82         else if(row.graph == AlignmentAnnotation.LINE_GRAPH)\r
83           text.append("LINE_GRAPH\t");\r
84 \r
85         if(row.getThreshold()!=null)\r
86             graphLine.append("GRAPHLINE\t"\r
87                              + row.label + "\t"\r
88                              + row.getThreshold().value + "\t"\r
89                              + row.getThreshold().label + "\t"\r
90                              + jalview.util.Format.getHexString(\r
91                                  row.getThreshold().colour)+"\n"\r
92                 );\r
93 \r
94           if(row.graphGroup>-1)\r
95           {\r
96             String key = String.valueOf(row.graphGroup);\r
97             if(graphGroup.containsKey(key))\r
98               graphGroup.put(key, graphGroup.get(key)\r
99                              +"\t"+row.label);\r
100             else\r
101               graphGroup.put(key, row.label);\r
102           }\r
103       }\r
104 \r
105       text.append(row.label+"\t");\r
106       if(row.description!=null)\r
107         text.append(row.description+"\t");\r
108 \r
109       for(int j=0; j<row.annotations.length; j++)\r
110       {\r
111         if (seqref != null && jalview.util.Comparison.isGap(seqref.getCharAt(j)))\r
112           continue;\r
113 \r
114         if(row.annotations[j]!=null)\r
115         {\r
116           comma = "";\r
117           if (row.annotations[j].secondaryStructure!=' ')\r
118           {\r
119             text.append(comma + row.annotations[j].secondaryStructure);\r
120             comma = ",";\r
121           }\r
122           if (row.annotations[j].displayCharacter.length() > 0\r
123                   && !row.annotations[j].displayCharacter.equals(" "))\r
124               {\r
125                 text.append(comma + row.annotations[j].displayCharacter);\r
126                 comma = ",";\r
127               }\r
128 \r
129           if (row.annotations[j]!=null)\r
130           {\r
131             color = row.annotations[j].colour;\r
132             if (row.annotations[j].value!=0f)\r
133               text.append(comma + row.annotations[j].value);\r
134           }\r
135         }\r
136         text.append("|");\r
137       }\r
138 \r
139       text.append("\n");\r
140 \r
141       if(color!=null && color!=java.awt.Color.black)\r
142       {\r
143         colours.append("COLOUR\t"\r
144                        +row.label+"\t"\r
145                        +jalview.util.Format.getHexString(color)+"\n");\r
146       }\r
147 \r
148     }\r
149 \r
150     text.append("\n");\r
151 \r
152     text.append(colours.toString());\r
153     text.append(graphLine.toString());\r
154     if(graphGroup.size()>0)\r
155     {\r
156       text.append("COMBINE\t");\r
157       Enumeration en = graphGroup.elements();\r
158       while(en.hasMoreElements())\r
159       {\r
160         text.append(en.nextElement()+"\n");\r
161       }\r
162     }\r
163 \r
164     return text.toString();\r
165   }\r
166 \r
167   public boolean readAnnotationFile(AlignmentI al, String file)\r
168   {\r
169     try\r
170     {\r
171       BufferedReader in = null;\r
172       java.io.InputStream is = getClass().getResourceAsStream("/" + file);\r
173       if (is != null)\r
174       {\r
175         in = new BufferedReader(new java.io.InputStreamReader(is));\r
176       }\r
177       else\r
178       {\r
179         try\r
180         {\r
181           URL url = new URL(file);\r
182           in = new BufferedReader(new InputStreamReader(url.openStream()));\r
183         }\r
184         catch (java.net.MalformedURLException ex)\r
185         {\r
186           in = new BufferedReader(new FileReader(file));\r
187         }\r
188       }\r
189 \r
190       String line, label, description, token;\r
191       int graphStyle, index;\r
192       SequenceI refSeq = null;\r
193       int refSeqIndex = 1;\r
194       int existingAnnotations = 0;\r
195       if(al.getAlignmentAnnotation()!=null)\r
196        existingAnnotations = al.getAlignmentAnnotation().length;\r
197 \r
198       int alWidth = al.getWidth();\r
199 \r
200       StringTokenizer st;\r
201       Annotation[] annotations;\r
202       AlignmentAnnotation annotation = null;\r
203 \r
204       // First confirm this is an Annotation file\r
205       boolean jvAnnotationFile = false;\r
206       while ( (line = in.readLine()) != null)\r
207       {\r
208         if (line.indexOf("#") == 0 )\r
209           continue;\r
210 \r
211         if (line.indexOf("JALVIEW_ANNOTATION") > -1)\r
212         {\r
213           jvAnnotationFile = true;\r
214           break;\r
215         }\r
216       }\r
217 \r
218       if(!jvAnnotationFile)\r
219       {\r
220         in.close();\r
221         return false;\r
222       }\r
223 \r
224       while ( (line = in.readLine()) != null)\r
225       {\r
226         if(line.indexOf("#")==0\r
227            || line.indexOf("JALVIEW_ANNOTATION")>-1\r
228            || line.length()==0)\r
229           continue;\r
230 \r
231         st = new StringTokenizer(line, "\t");\r
232         token = st.nextToken();\r
233         if(token.equalsIgnoreCase("COLOUR"))\r
234         {\r
235           colourAnnotations(al, st.nextToken(), st.nextToken());\r
236           continue;\r
237         }\r
238 \r
239         if(token.equalsIgnoreCase("COMBINE") )\r
240         {\r
241           combineAnnotations(al, st);\r
242           continue;\r
243         }\r
244 \r
245         if (token.equalsIgnoreCase("GRAPHLINE"))\r
246         {\r
247           addLine(al, st);\r
248           continue;\r
249         }\r
250 \r
251 \r
252         if(token.equalsIgnoreCase("SEQUENCE_REF") )\r
253         {\r
254           refSeq = al.findName(st.nextToken());\r
255           try{\r
256             refSeqIndex = Integer.parseInt(st.nextToken());\r
257             if(refSeqIndex<1)\r
258             {\r
259               refSeqIndex = 1;\r
260               System.out.println("WARNING: SEQUENCE_REF index must be > 0 in AnnotationFile");\r
261             }\r
262           }\r
263           catch(Exception ex)\r
264           {\r
265             refSeqIndex = 1;\r
266           }\r
267 \r
268           continue;\r
269         }\r
270 \r
271 \r
272         graphStyle = AlignmentAnnotation.getGraphValueFromString(token);\r
273         label = st.nextToken();\r
274 \r
275         if(st.countTokens()>1)\r
276           description = st.nextToken();\r
277         else\r
278           description = null;\r
279 \r
280         line = st.nextToken();\r
281 \r
282         st = new StringTokenizer(line, "|", true);\r
283         annotations = new Annotation[alWidth];\r
284 \r
285         index = 0;\r
286         boolean emptyColumn = true;\r
287 \r
288 \r
289         while (st.hasMoreElements() && index<alWidth)\r
290         {\r
291           token = st.nextToken().trim();\r
292           if(token.equals("|"))\r
293           {\r
294             if(emptyColumn)\r
295               index++;\r
296 \r
297             emptyColumn = true;\r
298           }\r
299           else\r
300           {\r
301             annotations[index++] = parseAnnotation(token);\r
302             emptyColumn = false;\r
303           }\r
304         }\r
305 \r
306        annotation = new AlignmentAnnotation(label,\r
307                                           description,\r
308                                           annotations,\r
309                                           0,\r
310                                           0,\r
311                                           graphStyle);\r
312 \r
313        if(refSeq!=null)\r
314        {\r
315          annotation.createSequenceMapping(refSeq, refSeqIndex, false);\r
316          refSeq.addAlignmentAnnotation(annotation);\r
317        }\r
318 \r
319        al.addAnnotation(annotation);\r
320 \r
321        al.setAnnotationIndex(annotation,  al.getAlignmentAnnotation().length - existingAnnotations-1);\r
322       }\r
323 \r
324     }catch(Exception ex)\r
325     {\r
326       ex.printStackTrace();\r
327       System.out.println("Problem reading annotation file: "+ex);\r
328       return false;\r
329     }\r
330     return true;\r
331   }\r
332 \r
333   Annotation parseAnnotation(String string)\r
334   {\r
335     String desc = null, displayChar="";\r
336     char ss = ' '; // secondaryStructure\r
337     float value = 0;\r
338     boolean parsedValue = false;\r
339     StringTokenizer st = new StringTokenizer(string, ",");\r
340     String token;\r
341     while(st.hasMoreTokens())\r
342     {\r
343       token = st.nextToken().trim();\r
344       if(token.length()==0)\r
345         continue;\r
346 \r
347       if(!parsedValue)\r
348       {\r
349         try{\r
350           displayChar = token;\r
351           value = new Float(token).floatValue();\r
352           parsedValue = true;\r
353           continue;\r
354         }catch(NumberFormatException ex){}\r
355       }\r
356 \r
357       if(token.equals("H") || token.equals("E"))\r
358       {\r
359         // Either this character represents a helix or sheet\r
360         // or an integer which can be displayed\r
361         ss = token.charAt(0);\r
362         if(displayChar.equals(token.substring(0,1)))\r
363           displayChar = "";\r
364       }\r
365       else if(desc==null)\r
366         desc = token;\r
367 \r
368     }\r
369 \r
370     if(desc == null)\r
371       desc = value+"";\r
372 \r
373     if(displayChar.length()>1 && desc.length()==1)\r
374     {\r
375       String tmp = displayChar;\r
376       displayChar = desc;\r
377       desc = tmp;\r
378     }\r
379 \r
380     return new Annotation(displayChar, desc, ss, value);\r
381   }\r
382 \r
383   void colourAnnotations(AlignmentI al, String label, String colour)\r
384   {\r
385     UserColourScheme ucs = new UserColourScheme(colour);\r
386     Annotation[] annotations;\r
387     for(int i=0; i<al.getAlignmentAnnotation().length; i++)\r
388     {\r
389       if(al.getAlignmentAnnotation()[i].label.equalsIgnoreCase(label))\r
390       {\r
391         annotations = al.getAlignmentAnnotation()[i].annotations;\r
392         for(int j=0; j<annotations.length; j++)\r
393         {\r
394           if(annotations[j]!=null)\r
395             annotations[j].colour = ucs.findColour('A');\r
396         }\r
397       }\r
398     }\r
399   }\r
400 \r
401   void combineAnnotations(AlignmentI al, StringTokenizer st)\r
402   {\r
403     int graphGroup = -1;\r
404     String group = st.nextToken();\r
405     //First make sure we are not overwriting the graphIndex\r
406     for(int i=0; i<al.getAlignmentAnnotation().length; i++)\r
407     {\r
408       if(al.getAlignmentAnnotation()[i].label.equalsIgnoreCase(group))\r
409       {\r
410         graphGroup = al.getAlignmentAnnotation()[i].graphGroup +1;\r
411         al.getAlignmentAnnotation()[i].graphGroup = graphGroup;\r
412         break;\r
413       }\r
414     }\r
415 \r
416     //Now update groups\r
417     while(st.hasMoreTokens())\r
418     {\r
419       group = st.nextToken();\r
420       for(int i=0; i<al.getAlignmentAnnotation().length; i++)\r
421       {\r
422         if (al.getAlignmentAnnotation()[i].label.equalsIgnoreCase(group))\r
423         {\r
424           al.getAlignmentAnnotation()[i].graphGroup = graphGroup;\r
425           break;\r
426         }\r
427       }\r
428     }\r
429   }\r
430 \r
431   void addLine(AlignmentI al, StringTokenizer st)\r
432   {\r
433     String group = st.nextToken();\r
434     AlignmentAnnotation annotation = null;\r
435 \r
436     for (int i = 0; i < al.getAlignmentAnnotation().length; i++)\r
437     {\r
438       if (al.getAlignmentAnnotation()[i].label.equalsIgnoreCase(group))\r
439       {\r
440         annotation = al.getAlignmentAnnotation()[i];\r
441         break;\r
442       }\r
443     }\r
444 \r
445     if(annotation==null)\r
446       return;\r
447     float value = new Float(st.nextToken()).floatValue();\r
448     String label = st.hasMoreTokens() ?  st.nextToken() : null;\r
449     java.awt.Color colour = null;\r
450     if(st.hasMoreTokens())\r
451     {\r
452       UserColourScheme ucs = new UserColourScheme(st.nextToken());\r
453       colour = ucs.findColour('A');\r
454     }\r
455 \r
456     annotation.setThreshold(new GraphLine(value, label, colour));\r
457 \r
458   }\r
459 }\r