Output groups in 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 import jalview.analysis.Conservation;\r
28 \r
29 \r
30 public class AnnotationFile\r
31 {\r
32   StringBuffer text = new StringBuffer(\r
33         "JALVIEW_ANNOTATION\n"\r
34         +"# Created: "\r
35       +new java.util.Date()+"\n\n");\r
36 \r
37   public String printAnnotations(AlignmentAnnotation [] annotations,\r
38                                 Vector groups)\r
39   {\r
40     if(annotations!=null)\r
41     {\r
42       AlignmentAnnotation row;\r
43       String comma;\r
44       SequenceI seqref = null;\r
45 \r
46       StringBuffer colours = new StringBuffer();\r
47       StringBuffer graphLine = new StringBuffer();\r
48 \r
49       Hashtable graphGroup = new Hashtable();\r
50 \r
51       java.awt.Color color;\r
52 \r
53       for (int i = 0; i < annotations.length; i++)\r
54       {\r
55         row = annotations[i];\r
56 \r
57         if (!row.visible)\r
58           continue;\r
59 \r
60         color = null;\r
61 \r
62         if (row.sequenceRef == null)\r
63         {\r
64           if (seqref != null)\r
65             text.append("\nSEQUENCE_REF\tALIGNMENT\n");\r
66 \r
67           seqref = null;\r
68         }\r
69 \r
70         else if (seqref == null || seqref != row.sequenceRef)\r
71         {\r
72           seqref = row.sequenceRef;\r
73           text.append("\nSEQUENCE_REF\t" + seqref.getName() + "\n");\r
74         }\r
75 \r
76         if (row.graph == AlignmentAnnotation.NO_GRAPH)\r
77         {\r
78           text.append("NO_GRAPH\t");\r
79         }\r
80         else\r
81         {\r
82           if (row.graph == AlignmentAnnotation.BAR_GRAPH)\r
83             text.append("BAR_GRAPH\t");\r
84           else if (row.graph == AlignmentAnnotation.LINE_GRAPH)\r
85             text.append("LINE_GRAPH\t");\r
86 \r
87           if (row.getThreshold() != null)\r
88             graphLine.append("GRAPHLINE\t"\r
89                              + row.label + "\t"\r
90                              + row.getThreshold().value + "\t"\r
91                              + row.getThreshold().label + "\t"\r
92                              + jalview.util.Format.getHexString(\r
93                                  row.getThreshold().colour) + "\n"\r
94                 );\r
95 \r
96           if (row.graphGroup > -1)\r
97           {\r
98             String key = String.valueOf(row.graphGroup);\r
99             if (graphGroup.containsKey(key))\r
100               graphGroup.put(key, graphGroup.get(key)\r
101                              + "\t" + row.label);\r
102             else\r
103               graphGroup.put(key, row.label);\r
104           }\r
105         }\r
106 \r
107         text.append(row.label + "\t");\r
108         if (row.description != null)\r
109           text.append(row.description + "\t");\r
110 \r
111         for (int j = 0; j < row.annotations.length; j++)\r
112         {\r
113           if (seqref != null &&\r
114               jalview.util.Comparison.isGap(seqref.getCharAt(j)))\r
115             continue;\r
116 \r
117           if (row.annotations[j] != null)\r
118           {\r
119             comma = "";\r
120             if (row.annotations[j].secondaryStructure != ' ')\r
121             {\r
122               text.append(comma + row.annotations[j].secondaryStructure);\r
123               comma = ",";\r
124             }\r
125             if (row.annotations[j].displayCharacter.length() > 0\r
126                 && !row.annotations[j].displayCharacter.equals(" "))\r
127             {\r
128               text.append(comma + row.annotations[j].displayCharacter);\r
129               comma = ",";\r
130             }\r
131 \r
132             if (row.annotations[j] != null)\r
133             {\r
134               color = row.annotations[j].colour;\r
135               if (row.annotations[j].value != 0f)\r
136                 text.append(comma + row.annotations[j].value);\r
137             }\r
138           }\r
139           text.append("|");\r
140         }\r
141 \r
142         text.append("\n");\r
143 \r
144         if (color != null && color != java.awt.Color.black)\r
145         {\r
146           colours.append("COLOUR\t"\r
147                          + row.label + "\t"\r
148                          + jalview.util.Format.getHexString(color) + "\n");\r
149         }\r
150 \r
151       }\r
152 \r
153       text.append("\n");\r
154 \r
155       text.append(colours.toString());\r
156       text.append(graphLine.toString());\r
157       if (graphGroup.size() > 0)\r
158       {\r
159         text.append("COMBINE\t");\r
160         Enumeration en = graphGroup.elements();\r
161         while (en.hasMoreElements())\r
162         {\r
163           text.append(en.nextElement() + "\n");\r
164         }\r
165       }\r
166     }\r
167 \r
168 \r
169     if(groups!=null)\r
170     {\r
171       printGroups(groups);\r
172     }\r
173 \r
174     return text.toString();\r
175   }\r
176 \r
177 \r
178   public void printGroups(Vector sequenceGroups)\r
179   {\r
180     SequenceGroup sg;\r
181     for (int i = 0; i < sequenceGroups.size(); i++)\r
182     {\r
183       sg = (SequenceGroup) sequenceGroups.elementAt(i);\r
184       text.append("SEQUENCE_GROUP\t"\r
185                   + sg.getName() + "\t"\r
186                   + (sg.getStartRes()+1) + "\t"\r
187                   + (sg.getEndRes()+1)  + "\t" + "-1\t");\r
188       for(int s=0; s<sg.getSize(); s++)\r
189       {\r
190         text.append(sg.getSequenceAt(s).getName()+"\t");\r
191       }\r
192 \r
193       text.append("\nPROPERTIES\t"+sg.getName()+"\t");\r
194 \r
195       if(sg.getDescription()!=null)\r
196         text.append("description="+sg.getDescription()+"\t");\r
197       if(sg.cs!=null)\r
198       {\r
199         text.append("colour="+ColourSchemeProperty.getColourName(sg.cs)+"\t");\r
200         if(sg.cs.getThreshold()!=0)\r
201           text.append("pidThreshold="+sg.cs.getThreshold());\r
202         if(sg.cs.conservationApplied())\r
203           text.append("consThreshold="+sg.cs.getConservationInc()+"\t");\r
204       }\r
205       text.append("outlineColour="+\r
206                   jalview.util.Format.getHexString(sg.getOutlineColour())+"\t");\r
207 \r
208       text.append("displayBoxes=" + sg.getDisplayBoxes() + "\t");\r
209       text.append("displayText=" + sg.getDisplayText() + "\t");\r
210       text.append("colourText=" + sg.getColourText() + "\t");\r
211 \r
212       if (sg.textColour != java.awt.Color.black)\r
213         text.append("textCol1=" +\r
214                     jalview.util.Format.getHexString(sg.textColour) + "\t");\r
215       if (sg.textColour2 != java.awt.Color.white)\r
216         text.append("textCol2=" +\r
217                     jalview.util.Format.getHexString(sg.textColour2) + "\t");\r
218       if(sg.thresholdTextColour!=0)\r
219       text.append("textColThreshold="+sg.thresholdTextColour);\r
220 \r
221       text.append("\n\n");\r
222 \r
223     }\r
224   }\r
225 \r
226 \r
227   SequenceI refSeq = null;\r
228   Hashtable annotationsHash = new Hashtable();\r
229   public boolean readAnnotationFile(AlignmentI al,\r
230                                     String file,\r
231                                     String protocol)\r
232   {\r
233     try\r
234     {\r
235       BufferedReader in = null;\r
236       if (protocol.equals(AppletFormatAdapter.FILE))\r
237       {\r
238         in = new BufferedReader(new FileReader(file));\r
239       }\r
240       else if (protocol.equals(AppletFormatAdapter.URL))\r
241       {\r
242         URL url = new URL(file);\r
243         in = new BufferedReader(new InputStreamReader(url.openStream()));\r
244       }\r
245      else if (protocol.equals(AppletFormatAdapter.PASTE))\r
246       {\r
247         in = new BufferedReader(new StringReader(file));\r
248       }\r
249       else if (protocol.equals(AppletFormatAdapter.CLASSLOADER))\r
250       {\r
251         java.io.InputStream is = getClass().getResourceAsStream("/" + file);\r
252         if (is != null)\r
253         {\r
254           in = new BufferedReader(new java.io.InputStreamReader(is));\r
255         }\r
256     }\r
257 \r
258       String line, label, description, token;\r
259       int graphStyle, index;\r
260       int refSeqIndex = 1;\r
261       int existingAnnotations = 0;\r
262       if(al.getAlignmentAnnotation()!=null)\r
263        existingAnnotations = al.getAlignmentAnnotation().length;\r
264 \r
265       int alWidth = al.getWidth();\r
266 \r
267       StringTokenizer st;\r
268       Annotation[] annotations;\r
269       AlignmentAnnotation annotation = null;\r
270 \r
271       // First confirm this is an Annotation file\r
272       boolean jvAnnotationFile = false;\r
273       while ( (line = in.readLine()) != null)\r
274       {\r
275         if (line.indexOf("#") == 0 )\r
276           continue;\r
277 \r
278         if (line.indexOf("JALVIEW_ANNOTATION") > -1)\r
279         {\r
280           jvAnnotationFile = true;\r
281           break;\r
282         }\r
283       }\r
284 \r
285       if(!jvAnnotationFile)\r
286       {\r
287         in.close();\r
288         return false;\r
289       }\r
290 \r
291       while ( (line = in.readLine()) != null)\r
292       {\r
293         if(line.indexOf("#")==0\r
294            || line.indexOf("JALVIEW_ANNOTATION")>-1\r
295            || line.length()==0)\r
296           continue;\r
297 \r
298         st = new StringTokenizer(line, "\t");\r
299         token = st.nextToken();\r
300         if(token.equalsIgnoreCase("COLOUR"))\r
301         {\r
302           colourAnnotations(al, st.nextToken(), st.nextToken());\r
303           continue;\r
304         }\r
305 \r
306         else if(token.equalsIgnoreCase("COMBINE") )\r
307         {\r
308           combineAnnotations(al, st);\r
309           continue;\r
310         }\r
311 \r
312         else if (token.equalsIgnoreCase("GRAPHLINE"))\r
313         {\r
314           addLine(al, st);\r
315           continue;\r
316         }\r
317 \r
318 \r
319         else if(token.equalsIgnoreCase("SEQUENCE_REF") )\r
320         {\r
321           refSeq = al.findName(st.nextToken());\r
322           try{\r
323             refSeqIndex = Integer.parseInt(st.nextToken());\r
324             if(refSeqIndex<1)\r
325             {\r
326               refSeqIndex = 1;\r
327               System.out.println("WARNING: SEQUENCE_REF index must be > 0 in AnnotationFile");\r
328             }\r
329           }\r
330           catch(Exception ex)\r
331           {\r
332             refSeqIndex = 1;\r
333           }\r
334 \r
335           continue;\r
336         }\r
337 \r
338         else if(token.equalsIgnoreCase("SEQUENCE_GROUP"))\r
339         {\r
340           addGroup(al, st);\r
341           continue;\r
342         }\r
343 \r
344         else if(token.equalsIgnoreCase("PROPERTIES"))\r
345         {\r
346           addProperties(al, st);\r
347           continue;\r
348         }\r
349 \r
350 \r
351         graphStyle = AlignmentAnnotation.getGraphValueFromString(token);\r
352         label = st.nextToken();\r
353 \r
354         if(st.countTokens()>1)\r
355           description = st.nextToken();\r
356         else\r
357           description = null;\r
358 \r
359         line = st.nextToken();\r
360 \r
361         st = new StringTokenizer(line, "|", true);\r
362         annotations = new Annotation[alWidth];\r
363 \r
364         index = 0;\r
365         boolean emptyColumn = true;\r
366 \r
367 \r
368         while (st.hasMoreElements() && index<alWidth)\r
369         {\r
370           token = st.nextToken().trim();\r
371           if(token.equals("|"))\r
372           {\r
373             if(emptyColumn)\r
374               index++;\r
375 \r
376             emptyColumn = true;\r
377           }\r
378           else\r
379           {\r
380             annotations[index++] = parseAnnotation(token);\r
381             emptyColumn = false;\r
382           }\r
383         }\r
384 \r
385        annotation = new AlignmentAnnotation(label,\r
386                                           description,\r
387                                           annotations,\r
388                                           0,\r
389                                           0,\r
390                                           graphStyle);\r
391 \r
392        if(refSeq!=null)\r
393        {\r
394          annotation.createSequenceMapping(refSeq, refSeqIndex, false);\r
395          refSeq.addAlignmentAnnotation(annotation);\r
396        }\r
397 \r
398        al.addAnnotation(annotation);\r
399 \r
400        al.setAnnotationIndex(annotation,  al.getAlignmentAnnotation().length - existingAnnotations-1);\r
401       }\r
402 \r
403     }catch(Exception ex)\r
404     {\r
405       ex.printStackTrace();\r
406       System.out.println("Problem reading annotation file: "+ex);\r
407       return false;\r
408     }\r
409     return true;\r
410   }\r
411 \r
412   Annotation parseAnnotation(String string)\r
413   {\r
414     String desc = null, displayChar="";\r
415     char ss = ' '; // secondaryStructure\r
416     float value = 0;\r
417     boolean parsedValue = false;\r
418     StringTokenizer st = new StringTokenizer(string, ",");\r
419     String token;\r
420     while(st.hasMoreTokens())\r
421     {\r
422       token = st.nextToken().trim();\r
423       if(token.length()==0)\r
424         continue;\r
425 \r
426       if(!parsedValue)\r
427       {\r
428         try{\r
429           displayChar = token;\r
430           value = new Float(token).floatValue();\r
431           parsedValue = true;\r
432           continue;\r
433         }catch(NumberFormatException ex){}\r
434       }\r
435 \r
436       if(token.equals("H") || token.equals("E"))\r
437       {\r
438         // Either this character represents a helix or sheet\r
439         // or an integer which can be displayed\r
440         ss = token.charAt(0);\r
441         if(displayChar.equals(token.substring(0,1)))\r
442           displayChar = "";\r
443       }\r
444       else if(desc==null)\r
445         desc = token;\r
446 \r
447     }\r
448 \r
449     if(desc == null)\r
450       desc = value+"";\r
451 \r
452     if(displayChar.length()>1 && desc.length()==1)\r
453     {\r
454       String tmp = displayChar;\r
455       displayChar = desc;\r
456       desc = tmp;\r
457     }\r
458 \r
459     return new Annotation(displayChar, desc, ss, value);\r
460   }\r
461 \r
462   void colourAnnotations(AlignmentI al, String label, String colour)\r
463   {\r
464     UserColourScheme ucs = new UserColourScheme(colour);\r
465     Annotation[] annotations;\r
466     for(int i=0; i<al.getAlignmentAnnotation().length; i++)\r
467     {\r
468       if(al.getAlignmentAnnotation()[i].label.equalsIgnoreCase(label))\r
469       {\r
470         annotations = al.getAlignmentAnnotation()[i].annotations;\r
471         for(int j=0; j<annotations.length; j++)\r
472         {\r
473           if(annotations[j]!=null)\r
474             annotations[j].colour = ucs.findColour('A');\r
475         }\r
476       }\r
477     }\r
478   }\r
479 \r
480   void combineAnnotations(AlignmentI al, StringTokenizer st)\r
481   {\r
482     int graphGroup = -1;\r
483     String group = st.nextToken();\r
484     //First make sure we are not overwriting the graphIndex\r
485     for(int i=0; i<al.getAlignmentAnnotation().length; i++)\r
486     {\r
487       if(al.getAlignmentAnnotation()[i].label.equalsIgnoreCase(group))\r
488       {\r
489         graphGroup = al.getAlignmentAnnotation()[i].graphGroup +1;\r
490         al.getAlignmentAnnotation()[i].graphGroup = graphGroup;\r
491         break;\r
492       }\r
493     }\r
494 \r
495     //Now update groups\r
496     while(st.hasMoreTokens())\r
497     {\r
498       group = st.nextToken();\r
499       for(int i=0; i<al.getAlignmentAnnotation().length; i++)\r
500       {\r
501         if (al.getAlignmentAnnotation()[i].label.equalsIgnoreCase(group))\r
502         {\r
503           al.getAlignmentAnnotation()[i].graphGroup = graphGroup;\r
504           break;\r
505         }\r
506       }\r
507     }\r
508   }\r
509 \r
510   void addLine(AlignmentI al, StringTokenizer st)\r
511   {\r
512     String group = st.nextToken();\r
513     AlignmentAnnotation annotation = null;\r
514 \r
515     for (int i = 0; i < al.getAlignmentAnnotation().length; i++)\r
516     {\r
517       if (al.getAlignmentAnnotation()[i].label.equalsIgnoreCase(group))\r
518       {\r
519         annotation = al.getAlignmentAnnotation()[i];\r
520         break;\r
521       }\r
522     }\r
523 \r
524     if(annotation==null)\r
525       return;\r
526     float value = new Float(st.nextToken()).floatValue();\r
527     String label = st.hasMoreTokens() ?  st.nextToken() : null;\r
528     java.awt.Color colour = null;\r
529     if(st.hasMoreTokens())\r
530     {\r
531       UserColourScheme ucs = new UserColourScheme(st.nextToken());\r
532       colour = ucs.findColour('A');\r
533     }\r
534 \r
535     annotation.setThreshold(new GraphLine(value, label, colour));\r
536   }\r
537 \r
538   void addGroup(AlignmentI al, StringTokenizer st)\r
539   {\r
540     SequenceGroup sg = new SequenceGroup();\r
541     sg.setName(st.nextToken());\r
542     sg.setStartRes(Integer.parseInt(st.nextToken())-1);\r
543     sg.setEndRes(Integer.parseInt(st.nextToken())-1);\r
544 \r
545     String index = st.nextToken();\r
546     if(index.equals("-1"))\r
547     {\r
548       while (st.hasMoreElements())\r
549       {\r
550         sg.addSequence(al.findName(st.nextToken()), false);\r
551       }\r
552     }\r
553     else\r
554     {\r
555       StringTokenizer st2 = new StringTokenizer(index, ",");\r
556 \r
557       while (st2.hasMoreTokens())\r
558       {\r
559         String tmp = st2.nextToken();\r
560         if (tmp.equals("*"))\r
561         {\r
562           for (int i = 0; i < al.getHeight(); i++)\r
563           {\r
564             sg.addSequence(al.getSequenceAt(i), false);\r
565           }\r
566         }\r
567         else if (tmp.indexOf("-") >= 0)\r
568         {\r
569           StringTokenizer st3 = new StringTokenizer(tmp, "-");\r
570 \r
571           int start = (Integer.parseInt(st3.nextToken()));\r
572           int end = (Integer.parseInt(st3.nextToken()));\r
573 \r
574           if (end > start)\r
575             for (int i = start; i <= end; i++)\r
576               sg.addSequence(al.getSequenceAt(i-1), false);\r
577         }\r
578         else\r
579         {\r
580           sg.addSequence(al.getSequenceAt(Integer.parseInt(tmp)-1 ), false);\r
581         }\r
582       }\r
583     }\r
584 \r
585     if(refSeq!=null)\r
586     {\r
587       sg.setStartRes( refSeq.findIndex( sg.getStartRes()+1 )-1 );\r
588       sg.setEndRes(   refSeq.findIndex( sg.getEndRes() +1) -1 );\r
589     }\r
590 \r
591     al.addGroup(sg);\r
592     annotationsHash.put(sg.getName(), sg);\r
593   }\r
594 \r
595   void addProperties(AlignmentI al, StringTokenizer st)\r
596   {\r
597 \r
598     //So far we have only added groups to the annotationHash,\r
599     //the idea is in the future properties can be added to\r
600     //alignments, other annotations etc\r
601     SequenceGroup sg = (SequenceGroup)annotationsHash.get(st.nextToken());\r
602 \r
603     if(sg!=null)\r
604     {\r
605       String keyValue, key, value;\r
606       while(st.hasMoreTokens())\r
607       {\r
608         keyValue = st.nextToken();\r
609         key = keyValue.substring(0,keyValue.indexOf("="));\r
610         value=keyValue.substring(keyValue.indexOf("=")+1);\r
611 \r
612         if(key.equalsIgnoreCase("description"))\r
613           sg.setDescription(value);\r
614         else if(key.equalsIgnoreCase("colour"))\r
615           sg.cs = ColourSchemeProperty.getColour(al, value);\r
616         else if (key.equalsIgnoreCase("pidThreshold"))\r
617         {\r
618           sg.cs.setThreshold(Integer.parseInt(value), true);\r
619 \r
620         }\r
621         else if (key.equalsIgnoreCase("consThreshold"))\r
622         {\r
623           sg.cs.setConservationInc(Integer.parseInt(value));\r
624           Conservation c = new Conservation("Group",\r
625                     ResidueProperties.propHash, 3,\r
626                     sg.getSequences(null),\r
627                     sg.getStartRes(),\r
628                     sg.getEndRes() + 1);\r
629 \r
630             c.calculate();\r
631             c.verdict(false, 25);\r
632 \r
633             sg.cs.setConservation(c);\r
634 \r
635         }\r
636         else if (key.equalsIgnoreCase("outlineColour"))\r
637          {\r
638            sg.setOutlineColour(new UserColourScheme(value).findColour('A'));\r
639          }\r
640         else if (key.equalsIgnoreCase("displayBoxes"))\r
641          sg.setDisplayBoxes( Boolean.valueOf(value).booleanValue() );\r
642         else if (key.equalsIgnoreCase("displayText"))\r
643          sg.setDisplayText( Boolean.valueOf(value).booleanValue() );\r
644         else if (key.equalsIgnoreCase("colourText"))\r
645          sg.setColourText( Boolean.valueOf(value).booleanValue() );\r
646         else if (key.equalsIgnoreCase("textCol1"))\r
647          {\r
648            sg.textColour = new UserColourScheme(value).findColour('A');\r
649          }\r
650         else if (key.equalsIgnoreCase("textCol2"))\r
651         {\r
652           sg.textColour2 = new UserColourScheme(value).findColour('A');\r
653         }\r
654         else if (key.equalsIgnoreCase("textColThreshold"))\r
655          sg.thresholdTextColour = Integer.parseInt(value);\r
656 \r
657        sg.recalcConservation();\r
658       }\r
659     }\r
660   }\r
661 }\r