SequenceGroup parsing added to annotation file
[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 java.net.URL;\r
26 import jalview.schemes.*;\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 \r
168   SequenceI refSeq = null;\r
169   Hashtable annotationsHash = new Hashtable();\r
170   public boolean readAnnotationFile(AlignmentI al,\r
171                                     String file,\r
172                                     String protocol)\r
173   {\r
174     try\r
175     {\r
176       BufferedReader in = null;\r
177       if (protocol.equals(AppletFormatAdapter.FILE))\r
178       {\r
179         in = new BufferedReader(new FileReader(file));\r
180       }\r
181       else if (protocol.equals(AppletFormatAdapter.URL))\r
182       {\r
183         URL url = new URL(file);\r
184         in = new BufferedReader(new InputStreamReader(url.openStream()));\r
185       }\r
186      else if (protocol.equals(AppletFormatAdapter.PASTE))\r
187       {\r
188         in = new BufferedReader(new StringReader(file));\r
189       }\r
190       else if (protocol.equals(AppletFormatAdapter.CLASSLOADER))\r
191       {\r
192         java.io.InputStream is = getClass().getResourceAsStream("/" + file);\r
193         if (is != null)\r
194         {\r
195           in = new BufferedReader(new java.io.InputStreamReader(is));\r
196         }\r
197     }\r
198 \r
199       String line, label, description, token;\r
200       int graphStyle, index;\r
201       int refSeqIndex = 1;\r
202       int existingAnnotations = 0;\r
203       if(al.getAlignmentAnnotation()!=null)\r
204        existingAnnotations = al.getAlignmentAnnotation().length;\r
205 \r
206       int alWidth = al.getWidth();\r
207 \r
208       StringTokenizer st;\r
209       Annotation[] annotations;\r
210       AlignmentAnnotation annotation = null;\r
211 \r
212       // First confirm this is an Annotation file\r
213       boolean jvAnnotationFile = false;\r
214       while ( (line = in.readLine()) != null)\r
215       {\r
216         if (line.indexOf("#") == 0 )\r
217           continue;\r
218 \r
219         if (line.indexOf("JALVIEW_ANNOTATION") > -1)\r
220         {\r
221           jvAnnotationFile = true;\r
222           break;\r
223         }\r
224       }\r
225 \r
226       if(!jvAnnotationFile)\r
227       {\r
228         in.close();\r
229         return false;\r
230       }\r
231 \r
232       while ( (line = in.readLine()) != null)\r
233       {\r
234         if(line.indexOf("#")==0\r
235            || line.indexOf("JALVIEW_ANNOTATION")>-1\r
236            || line.length()==0)\r
237           continue;\r
238 \r
239         st = new StringTokenizer(line, "\t");\r
240         token = st.nextToken();\r
241         if(token.equalsIgnoreCase("COLOUR"))\r
242         {\r
243           colourAnnotations(al, st.nextToken(), st.nextToken());\r
244           continue;\r
245         }\r
246 \r
247         else if(token.equalsIgnoreCase("COMBINE") )\r
248         {\r
249           combineAnnotations(al, st);\r
250           continue;\r
251         }\r
252 \r
253         else if (token.equalsIgnoreCase("GRAPHLINE"))\r
254         {\r
255           addLine(al, st);\r
256           continue;\r
257         }\r
258 \r
259 \r
260         else if(token.equalsIgnoreCase("SEQUENCE_REF") )\r
261         {\r
262           refSeq = al.findName(st.nextToken());\r
263           try{\r
264             refSeqIndex = Integer.parseInt(st.nextToken());\r
265             if(refSeqIndex<1)\r
266             {\r
267               refSeqIndex = 1;\r
268               System.out.println("WARNING: SEQUENCE_REF index must be > 0 in AnnotationFile");\r
269             }\r
270           }\r
271           catch(Exception ex)\r
272           {\r
273             refSeqIndex = 1;\r
274           }\r
275 \r
276           continue;\r
277         }\r
278 \r
279         else if(token.equalsIgnoreCase("SEQUENCE_GROUP"))\r
280         {\r
281           addGroup(al, st);\r
282           continue;\r
283         }\r
284 \r
285         else if(token.equalsIgnoreCase("PROPERTIES"))\r
286         {\r
287           addProperties(al, st);\r
288           continue;\r
289         }\r
290 \r
291 \r
292         graphStyle = AlignmentAnnotation.getGraphValueFromString(token);\r
293         label = st.nextToken();\r
294 \r
295         if(st.countTokens()>1)\r
296           description = st.nextToken();\r
297         else\r
298           description = null;\r
299 \r
300         line = st.nextToken();\r
301 \r
302         st = new StringTokenizer(line, "|", true);\r
303         annotations = new Annotation[alWidth];\r
304 \r
305         index = 0;\r
306         boolean emptyColumn = true;\r
307 \r
308 \r
309         while (st.hasMoreElements() && index<alWidth)\r
310         {\r
311           token = st.nextToken().trim();\r
312           if(token.equals("|"))\r
313           {\r
314             if(emptyColumn)\r
315               index++;\r
316 \r
317             emptyColumn = true;\r
318           }\r
319           else\r
320           {\r
321             annotations[index++] = parseAnnotation(token);\r
322             emptyColumn = false;\r
323           }\r
324         }\r
325 \r
326        annotation = new AlignmentAnnotation(label,\r
327                                           description,\r
328                                           annotations,\r
329                                           0,\r
330                                           0,\r
331                                           graphStyle);\r
332 \r
333        if(refSeq!=null)\r
334        {\r
335          annotation.createSequenceMapping(refSeq, refSeqIndex, false);\r
336          refSeq.addAlignmentAnnotation(annotation);\r
337        }\r
338 \r
339        al.addAnnotation(annotation);\r
340 \r
341        al.setAnnotationIndex(annotation,  al.getAlignmentAnnotation().length - existingAnnotations-1);\r
342       }\r
343 \r
344     }catch(Exception ex)\r
345     {\r
346       ex.printStackTrace();\r
347       System.out.println("Problem reading annotation file: "+ex);\r
348       return false;\r
349     }\r
350     return true;\r
351   }\r
352 \r
353   Annotation parseAnnotation(String string)\r
354   {\r
355     String desc = null, displayChar="";\r
356     char ss = ' '; // secondaryStructure\r
357     float value = 0;\r
358     boolean parsedValue = false;\r
359     StringTokenizer st = new StringTokenizer(string, ",");\r
360     String token;\r
361     while(st.hasMoreTokens())\r
362     {\r
363       token = st.nextToken().trim();\r
364       if(token.length()==0)\r
365         continue;\r
366 \r
367       if(!parsedValue)\r
368       {\r
369         try{\r
370           displayChar = token;\r
371           value = new Float(token).floatValue();\r
372           parsedValue = true;\r
373           continue;\r
374         }catch(NumberFormatException ex){}\r
375       }\r
376 \r
377       if(token.equals("H") || token.equals("E"))\r
378       {\r
379         // Either this character represents a helix or sheet\r
380         // or an integer which can be displayed\r
381         ss = token.charAt(0);\r
382         if(displayChar.equals(token.substring(0,1)))\r
383           displayChar = "";\r
384       }\r
385       else if(desc==null)\r
386         desc = token;\r
387 \r
388     }\r
389 \r
390     if(desc == null)\r
391       desc = value+"";\r
392 \r
393     if(displayChar.length()>1 && desc.length()==1)\r
394     {\r
395       String tmp = displayChar;\r
396       displayChar = desc;\r
397       desc = tmp;\r
398     }\r
399 \r
400     return new Annotation(displayChar, desc, ss, value);\r
401   }\r
402 \r
403   void colourAnnotations(AlignmentI al, String label, String colour)\r
404   {\r
405     UserColourScheme ucs = new UserColourScheme(colour);\r
406     Annotation[] annotations;\r
407     for(int i=0; i<al.getAlignmentAnnotation().length; i++)\r
408     {\r
409       if(al.getAlignmentAnnotation()[i].label.equalsIgnoreCase(label))\r
410       {\r
411         annotations = al.getAlignmentAnnotation()[i].annotations;\r
412         for(int j=0; j<annotations.length; j++)\r
413         {\r
414           if(annotations[j]!=null)\r
415             annotations[j].colour = ucs.findColour('A');\r
416         }\r
417       }\r
418     }\r
419   }\r
420 \r
421   void combineAnnotations(AlignmentI al, StringTokenizer st)\r
422   {\r
423     int graphGroup = -1;\r
424     String group = st.nextToken();\r
425     //First make sure we are not overwriting the graphIndex\r
426     for(int i=0; i<al.getAlignmentAnnotation().length; i++)\r
427     {\r
428       if(al.getAlignmentAnnotation()[i].label.equalsIgnoreCase(group))\r
429       {\r
430         graphGroup = al.getAlignmentAnnotation()[i].graphGroup +1;\r
431         al.getAlignmentAnnotation()[i].graphGroup = graphGroup;\r
432         break;\r
433       }\r
434     }\r
435 \r
436     //Now update groups\r
437     while(st.hasMoreTokens())\r
438     {\r
439       group = st.nextToken();\r
440       for(int i=0; i<al.getAlignmentAnnotation().length; i++)\r
441       {\r
442         if (al.getAlignmentAnnotation()[i].label.equalsIgnoreCase(group))\r
443         {\r
444           al.getAlignmentAnnotation()[i].graphGroup = graphGroup;\r
445           break;\r
446         }\r
447       }\r
448     }\r
449   }\r
450 \r
451   void addLine(AlignmentI al, StringTokenizer st)\r
452   {\r
453     String group = st.nextToken();\r
454     AlignmentAnnotation annotation = null;\r
455 \r
456     for (int i = 0; i < al.getAlignmentAnnotation().length; i++)\r
457     {\r
458       if (al.getAlignmentAnnotation()[i].label.equalsIgnoreCase(group))\r
459       {\r
460         annotation = al.getAlignmentAnnotation()[i];\r
461         break;\r
462       }\r
463     }\r
464 \r
465     if(annotation==null)\r
466       return;\r
467     float value = new Float(st.nextToken()).floatValue();\r
468     String label = st.hasMoreTokens() ?  st.nextToken() : null;\r
469     java.awt.Color colour = null;\r
470     if(st.hasMoreTokens())\r
471     {\r
472       UserColourScheme ucs = new UserColourScheme(st.nextToken());\r
473       colour = ucs.findColour('A');\r
474     }\r
475 \r
476     annotation.setThreshold(new GraphLine(value, label, colour));\r
477   }\r
478 \r
479   void addGroup(AlignmentI al, StringTokenizer st)\r
480   {\r
481     SequenceGroup sg = new SequenceGroup();\r
482     sg.setName(st.nextToken());\r
483     sg.setStartRes(Integer.parseInt(st.nextToken())-1);\r
484     sg.setEndRes(Integer.parseInt(st.nextToken())-1);\r
485 \r
486     String index = st.nextToken();\r
487     if(index.equals("-1"))\r
488     {\r
489       while (st.hasMoreElements())\r
490       {\r
491         sg.addSequence(al.findName(st.nextToken()), false);\r
492       }\r
493     }\r
494     else\r
495     {\r
496       StringTokenizer st2 = new StringTokenizer(index, ",");\r
497 \r
498       while (st2.hasMoreTokens())\r
499       {\r
500         String tmp = st2.nextToken();\r
501         if (tmp.equals("*"))\r
502         {\r
503           for (int i = 0; i < al.getHeight(); i++)\r
504           {\r
505             sg.addSequence(al.getSequenceAt(i), false);\r
506           }\r
507         }\r
508         else if (tmp.indexOf("-") >= 0)\r
509         {\r
510           StringTokenizer st3 = new StringTokenizer(tmp, "-");\r
511 \r
512           int start = (Integer.parseInt(st3.nextToken()));\r
513           int end = (Integer.parseInt(st3.nextToken()));\r
514 \r
515           if (end > start)\r
516             for (int i = start; i <= end; i++)\r
517               sg.addSequence(al.getSequenceAt(i-1), false);\r
518         }\r
519         else\r
520         {\r
521           sg.addSequence(al.getSequenceAt(Integer.parseInt(tmp)-1 ), false);\r
522         }\r
523       }\r
524     }\r
525 \r
526     if(refSeq!=null)\r
527     {\r
528       sg.setStartRes( refSeq.findIndex( sg.getStartRes()+1 )-1 );\r
529       sg.setEndRes(   refSeq.findIndex( sg.getEndRes() +1) -1 );\r
530     }\r
531 \r
532 \r
533     al.addGroup(sg);\r
534     annotationsHash.put(sg.getName(), sg);\r
535   }\r
536 \r
537   void addProperties(AlignmentI al, StringTokenizer st)\r
538   {\r
539 \r
540     //So far we have only added groups to the annotationHash,\r
541     //the idea is in the future properties can be added to\r
542     //alignments, other annotations etc\r
543     SequenceGroup sg = (SequenceGroup)annotationsHash.get(st.nextToken());\r
544 \r
545     if(sg!=null)\r
546     {\r
547       String keyValue, key, value;\r
548       while(st.hasMoreTokens())\r
549       {\r
550         keyValue = st.nextToken();\r
551         key = keyValue.substring(0,keyValue.indexOf("="));\r
552         value=keyValue.substring(keyValue.indexOf("=")+1);\r
553 \r
554         if(key.equalsIgnoreCase("description"))\r
555           sg.setDescription(value);\r
556         else if(key.equalsIgnoreCase("colour"))\r
557           sg.cs = ColourSchemeProperty.getColour(al, value);\r
558         else if (key.equalsIgnoreCase("pidThreshold"))\r
559           sg.cs.setThreshold(Integer.parseInt(value), false);//\r
560         else if (key.equalsIgnoreCase("outlineColour"))\r
561          {\r
562            sg.setOutlineColour(new UserColourScheme(value).findColour('A'));\r
563          }\r
564 \r
565          //Boolean.valueOf(string).booleanValue();\r
566         else if (key.equalsIgnoreCase("displayBoxes"))\r
567          sg.setDisplayBoxes( Boolean.valueOf(value).booleanValue() );\r
568         else if (key.equalsIgnoreCase("displayText"))\r
569          sg.setDisplayText( Boolean.valueOf(value).booleanValue() );\r
570         else if (key.equalsIgnoreCase("colourText"))\r
571          sg.setColourText( Boolean.valueOf(value).booleanValue() );\r
572         else if (key.equalsIgnoreCase("textCol1"))\r
573          {\r
574            sg.textColour = new UserColourScheme(value).findColour('A');\r
575          }\r
576         else if (key.equalsIgnoreCase("textCol2"))\r
577         {\r
578           sg.textColour2 = new UserColourScheme(value).findColour('A');\r
579         }\r
580         else if (key.equalsIgnoreCase("textColThreshold"))\r
581          sg.thresholdTextColour = Integer.parseInt(value);\r
582 \r
583       }\r
584     }\r
585   }\r
586 }\r