applet can define groups as parameters
[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   public boolean readAnnotationFile(AlignmentI al,\r
229                                     String file,\r
230                                     String protocol)\r
231   {\r
232     try\r
233     {\r
234       BufferedReader in = null;\r
235       if (protocol.equals(AppletFormatAdapter.FILE))\r
236       {\r
237         in = new BufferedReader(new FileReader(file));\r
238       }\r
239       else if (protocol.equals(AppletFormatAdapter.URL))\r
240       {\r
241         URL url = new URL(file);\r
242         in = new BufferedReader(new InputStreamReader(url.openStream()));\r
243       }\r
244      else if (protocol.equals(AppletFormatAdapter.PASTE))\r
245       {\r
246         in = new BufferedReader(new StringReader(file));\r
247       }\r
248       else if (protocol.equals(AppletFormatAdapter.CLASSLOADER))\r
249       {\r
250         java.io.InputStream is = getClass().getResourceAsStream("/" + file);\r
251         if (is != null)\r
252         {\r
253           in = new BufferedReader(new java.io.InputStreamReader(is));\r
254         }\r
255     }\r
256 \r
257       String line, label, description, token;\r
258       int graphStyle, index;\r
259       int refSeqIndex = 1;\r
260       int existingAnnotations = 0;\r
261       if(al.getAlignmentAnnotation()!=null)\r
262        existingAnnotations = al.getAlignmentAnnotation().length;\r
263 \r
264       int alWidth = al.getWidth();\r
265 \r
266       StringTokenizer st;\r
267       Annotation[] annotations;\r
268       AlignmentAnnotation annotation = null;\r
269 \r
270       // First confirm this is an Annotation file\r
271       boolean jvAnnotationFile = false;\r
272       while ( (line = in.readLine()) != null)\r
273       {\r
274         if (line.indexOf("#") == 0 )\r
275           continue;\r
276 \r
277         if (line.indexOf("JALVIEW_ANNOTATION") > -1)\r
278         {\r
279           jvAnnotationFile = true;\r
280           break;\r
281         }\r
282       }\r
283 \r
284       if(!jvAnnotationFile)\r
285       {\r
286         in.close();\r
287         return false;\r
288       }\r
289 \r
290       while ( (line = in.readLine()) != null)\r
291       {\r
292         if(line.indexOf("#")==0\r
293            || line.indexOf("JALVIEW_ANNOTATION")>-1\r
294            || line.length()==0)\r
295           continue;\r
296 \r
297         st = new StringTokenizer(line, "\t");\r
298         token = st.nextToken();\r
299         if(token.equalsIgnoreCase("COLOUR"))\r
300         {\r
301           colourAnnotations(al, st.nextToken(), st.nextToken());\r
302           continue;\r
303         }\r
304 \r
305         else if(token.equalsIgnoreCase("COMBINE") )\r
306         {\r
307           combineAnnotations(al, st);\r
308           continue;\r
309         }\r
310 \r
311         else if (token.equalsIgnoreCase("GRAPHLINE"))\r
312         {\r
313           addLine(al, st);\r
314           continue;\r
315         }\r
316 \r
317 \r
318         else if(token.equalsIgnoreCase("SEQUENCE_REF") )\r
319         {\r
320           refSeq = al.findName(st.nextToken());\r
321           try{\r
322             refSeqIndex = Integer.parseInt(st.nextToken());\r
323             if(refSeqIndex<1)\r
324             {\r
325               refSeqIndex = 1;\r
326               System.out.println("WARNING: SEQUENCE_REF index must be > 0 in AnnotationFile");\r
327             }\r
328           }\r
329           catch(Exception ex)\r
330           {\r
331             refSeqIndex = 1;\r
332           }\r
333 \r
334           continue;\r
335         }\r
336 \r
337         else if(token.equalsIgnoreCase("SEQUENCE_GROUP"))\r
338         {\r
339           addGroup(al, st);\r
340           continue;\r
341         }\r
342 \r
343         else if(token.equalsIgnoreCase("PROPERTIES"))\r
344         {\r
345           addProperties(al, st);\r
346           continue;\r
347         }\r
348 \r
349 \r
350         graphStyle = AlignmentAnnotation.getGraphValueFromString(token);\r
351         label = st.nextToken();\r
352 \r
353         if(st.countTokens()>1)\r
354           description = st.nextToken();\r
355         else\r
356           description = null;\r
357 \r
358         line = st.nextToken();\r
359 \r
360         st = new StringTokenizer(line, "|", true);\r
361         annotations = new Annotation[alWidth];\r
362 \r
363         index = 0;\r
364         boolean emptyColumn = true;\r
365 \r
366 \r
367         while (st.hasMoreElements() && index<alWidth)\r
368         {\r
369           token = st.nextToken().trim();\r
370           if(token.equals("|"))\r
371           {\r
372             if(emptyColumn)\r
373               index++;\r
374 \r
375             emptyColumn = true;\r
376           }\r
377           else\r
378           {\r
379             annotations[index++] = parseAnnotation(token);\r
380             emptyColumn = false;\r
381           }\r
382         }\r
383 \r
384        annotation = new AlignmentAnnotation(label,\r
385                                           description,\r
386                                           annotations,\r
387                                           0,\r
388                                           0,\r
389                                           graphStyle);\r
390 \r
391        if(refSeq!=null)\r
392        {\r
393          annotation.createSequenceMapping(refSeq, refSeqIndex, false);\r
394          refSeq.addAlignmentAnnotation(annotation);\r
395        }\r
396 \r
397        al.addAnnotation(annotation);\r
398 \r
399        al.setAnnotationIndex(annotation,  al.getAlignmentAnnotation().length - existingAnnotations-1);\r
400       }\r
401 \r
402     }catch(Exception ex)\r
403     {\r
404       ex.printStackTrace();\r
405       System.out.println("Problem reading annotation file: "+ex);\r
406       return false;\r
407     }\r
408     return true;\r
409   }\r
410 \r
411   Annotation parseAnnotation(String string)\r
412   {\r
413     String desc = null, displayChar="";\r
414     char ss = ' '; // secondaryStructure\r
415     float value = 0;\r
416     boolean parsedValue = false;\r
417     StringTokenizer st = new StringTokenizer(string, ",");\r
418     String token;\r
419     while(st.hasMoreTokens())\r
420     {\r
421       token = st.nextToken().trim();\r
422       if(token.length()==0)\r
423         continue;\r
424 \r
425       if(!parsedValue)\r
426       {\r
427         try{\r
428           displayChar = token;\r
429           value = new Float(token).floatValue();\r
430           parsedValue = true;\r
431           continue;\r
432         }catch(NumberFormatException ex){}\r
433       }\r
434 \r
435       if(token.equals("H") || token.equals("E"))\r
436       {\r
437         // Either this character represents a helix or sheet\r
438         // or an integer which can be displayed\r
439         ss = token.charAt(0);\r
440         if(displayChar.equals(token.substring(0,1)))\r
441           displayChar = "";\r
442       }\r
443       else if(desc==null)\r
444         desc = token;\r
445 \r
446     }\r
447 \r
448     if(desc == null)\r
449       desc = value+"";\r
450 \r
451     if(displayChar.length()>1 && desc.length()==1)\r
452     {\r
453       String tmp = displayChar;\r
454       displayChar = desc;\r
455       desc = tmp;\r
456     }\r
457 \r
458     return new Annotation(displayChar, desc, ss, value);\r
459   }\r
460 \r
461   void colourAnnotations(AlignmentI al, String label, String colour)\r
462   {\r
463     UserColourScheme ucs = new UserColourScheme(colour);\r
464     Annotation[] annotations;\r
465     for(int i=0; i<al.getAlignmentAnnotation().length; i++)\r
466     {\r
467       if(al.getAlignmentAnnotation()[i].label.equalsIgnoreCase(label))\r
468       {\r
469         annotations = al.getAlignmentAnnotation()[i].annotations;\r
470         for(int j=0; j<annotations.length; j++)\r
471         {\r
472           if(annotations[j]!=null)\r
473             annotations[j].colour = ucs.findColour('A');\r
474         }\r
475       }\r
476     }\r
477   }\r
478 \r
479   void combineAnnotations(AlignmentI al, StringTokenizer st)\r
480   {\r
481     int graphGroup = -1;\r
482     String group = st.nextToken();\r
483     //First make sure we are not overwriting the graphIndex\r
484     for(int i=0; i<al.getAlignmentAnnotation().length; i++)\r
485     {\r
486       if(al.getAlignmentAnnotation()[i].label.equalsIgnoreCase(group))\r
487       {\r
488         graphGroup = al.getAlignmentAnnotation()[i].graphGroup +1;\r
489         al.getAlignmentAnnotation()[i].graphGroup = graphGroup;\r
490         break;\r
491       }\r
492     }\r
493 \r
494     //Now update groups\r
495     while(st.hasMoreTokens())\r
496     {\r
497       group = st.nextToken();\r
498       for(int i=0; i<al.getAlignmentAnnotation().length; i++)\r
499       {\r
500         if (al.getAlignmentAnnotation()[i].label.equalsIgnoreCase(group))\r
501         {\r
502           al.getAlignmentAnnotation()[i].graphGroup = graphGroup;\r
503           break;\r
504         }\r
505       }\r
506     }\r
507   }\r
508 \r
509   void addLine(AlignmentI al, StringTokenizer st)\r
510   {\r
511     String group = st.nextToken();\r
512     AlignmentAnnotation annotation = null;\r
513 \r
514     for (int i = 0; i < al.getAlignmentAnnotation().length; i++)\r
515     {\r
516       if (al.getAlignmentAnnotation()[i].label.equalsIgnoreCase(group))\r
517       {\r
518         annotation = al.getAlignmentAnnotation()[i];\r
519         break;\r
520       }\r
521     }\r
522 \r
523     if(annotation==null)\r
524       return;\r
525     float value = new Float(st.nextToken()).floatValue();\r
526     String label = st.hasMoreTokens() ?  st.nextToken() : null;\r
527     java.awt.Color colour = null;\r
528     if(st.hasMoreTokens())\r
529     {\r
530       UserColourScheme ucs = new UserColourScheme(st.nextToken());\r
531       colour = ucs.findColour('A');\r
532     }\r
533 \r
534     annotation.setThreshold(new GraphLine(value, label, colour));\r
535   }\r
536 \r
537   void addGroup(AlignmentI al, StringTokenizer st)\r
538   {\r
539     SequenceGroup sg = new SequenceGroup();\r
540     sg.setName(st.nextToken());\r
541     sg.setStartRes(Integer.parseInt(st.nextToken())-1);\r
542     sg.setEndRes(Integer.parseInt(st.nextToken())-1);\r
543 \r
544     String index = st.nextToken();\r
545     if(index.equals("-1"))\r
546     {\r
547       while (st.hasMoreElements())\r
548       {\r
549         sg.addSequence(al.findName(st.nextToken()), false);\r
550       }\r
551     }\r
552     else\r
553     {\r
554       StringTokenizer st2 = new StringTokenizer(index, ",");\r
555 \r
556       while (st2.hasMoreTokens())\r
557       {\r
558         String tmp = st2.nextToken();\r
559         if (tmp.equals("*"))\r
560         {\r
561           for (int i = 0; i < al.getHeight(); i++)\r
562           {\r
563             sg.addSequence(al.getSequenceAt(i), false);\r
564           }\r
565         }\r
566         else if (tmp.indexOf("-") >= 0)\r
567         {\r
568           StringTokenizer st3 = new StringTokenizer(tmp, "-");\r
569 \r
570           int start = (Integer.parseInt(st3.nextToken()));\r
571           int end = (Integer.parseInt(st3.nextToken()));\r
572 \r
573           if (end > start)\r
574             for (int i = start; i <= end; i++)\r
575               sg.addSequence(al.getSequenceAt(i-1), false);\r
576         }\r
577         else\r
578         {\r
579           sg.addSequence(al.getSequenceAt(Integer.parseInt(tmp)-1 ), false);\r
580         }\r
581       }\r
582     }\r
583 \r
584     if(refSeq!=null)\r
585     {\r
586       sg.setStartRes( refSeq.findIndex( sg.getStartRes()+1 )-1 );\r
587       sg.setEndRes(   refSeq.findIndex( sg.getEndRes() +1) -1 );\r
588     }\r
589 \r
590     if(sg.getSize()>0)\r
591     {\r
592       al.addGroup(sg);\r
593     }\r
594   }\r
595 \r
596   void addProperties(AlignmentI al, StringTokenizer st)\r
597   {\r
598 \r
599     //So far we have only added groups to the annotationHash,\r
600     //the idea is in the future properties can be added to\r
601     //alignments, other annotations etc\r
602     if(al.getGroups()==null)\r
603       return;\r
604     SequenceGroup sg = null;\r
605 \r
606     String name = st.nextToken();\r
607 \r
608     Vector groups = al.getGroups();\r
609     for(int i=0; i<groups.size(); i++)\r
610     {\r
611       sg = (SequenceGroup)groups.elementAt(i);\r
612       if(sg.getName().equals(name))\r
613         break;\r
614       else\r
615         sg = null;\r
616     }\r
617 \r
618     if(sg!=null)\r
619     {\r
620       String keyValue, key, value;\r
621       while(st.hasMoreTokens())\r
622       {\r
623         keyValue = st.nextToken();\r
624         key = keyValue.substring(0,keyValue.indexOf("="));\r
625         value=keyValue.substring(keyValue.indexOf("=")+1);\r
626 \r
627         if(key.equalsIgnoreCase("description"))\r
628           sg.setDescription(value);\r
629         else if(key.equalsIgnoreCase("colour"))\r
630           sg.cs = ColourSchemeProperty.getColour(al, value);\r
631         else if (key.equalsIgnoreCase("pidThreshold"))\r
632         {\r
633           sg.cs.setThreshold(Integer.parseInt(value), true);\r
634 \r
635         }\r
636         else if (key.equalsIgnoreCase("consThreshold"))\r
637         {\r
638           sg.cs.setConservationInc(Integer.parseInt(value));\r
639           Conservation c = new Conservation("Group",\r
640                     ResidueProperties.propHash, 3,\r
641                     sg.getSequences(null),\r
642                     sg.getStartRes(),\r
643                     sg.getEndRes() + 1);\r
644 \r
645             c.calculate();\r
646             c.verdict(false, 25);\r
647 \r
648             sg.cs.setConservation(c);\r
649 \r
650         }\r
651         else if (key.equalsIgnoreCase("outlineColour"))\r
652          {\r
653            sg.setOutlineColour(new UserColourScheme(value).findColour('A'));\r
654          }\r
655         else if (key.equalsIgnoreCase("displayBoxes"))\r
656          sg.setDisplayBoxes( Boolean.valueOf(value).booleanValue() );\r
657         else if (key.equalsIgnoreCase("displayText"))\r
658          sg.setDisplayText( Boolean.valueOf(value).booleanValue() );\r
659         else if (key.equalsIgnoreCase("colourText"))\r
660          sg.setColourText( Boolean.valueOf(value).booleanValue() );\r
661         else if (key.equalsIgnoreCase("textCol1"))\r
662          {\r
663            sg.textColour = new UserColourScheme(value).findColour('A');\r
664          }\r
665         else if (key.equalsIgnoreCase("textCol2"))\r
666         {\r
667           sg.textColour2 = new UserColourScheme(value).findColour('A');\r
668         }\r
669         else if (key.equalsIgnoreCase("textColThreshold"))\r
670          sg.thresholdTextColour = Integer.parseInt(value);\r
671 \r
672        sg.recalcConservation();\r
673       }\r
674     }\r
675   }\r
676 }\r