v2
[jalview.git] / src / jalview / io / StockholmFile.java
1 /*\r
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.7)\r
3  * Copyright (C) 2011 J Procter, AM Waterhouse, J Engelhardt, LM Lui, G Barton, M Clamp, S Searle\r
4  * \r
5  * This file is part of Jalview.\r
6  * \r
7  * Jalview is free software: you can redistribute it and/or\r
8  * modify it under the terms of the GNU General Public License \r
9  * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.\r
10  * \r
11  * Jalview is distributed in the hope that it will be useful, but \r
12  * WITHOUT ANY WARRANTY; without even the implied warranty \r
13  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR \r
14  * PURPOSE.  See the GNU General Public License for more details.\r
15  * \r
16  * You should have received a copy of the GNU General Public License along with Jalview.  If not, see <http://www.gnu.org/licenses/>.\r
17  */\r
18 /*\r
19  * This extension was written by Benjamin Schuster-Boeckler at sanger.ac.uk\r
20  */\r
21 package jalview.io;\r
22 \r
23 import java.io.*;\r
24 import java.util.*;\r
25 \r
26 import javax.xml.parsers.ParserConfigurationException;\r
27 \r
28 import org.xml.sax.SAXException;\r
29 \r
30 import com.stevesoft.pat.*;\r
31 \r
32 import fr.orsay.lri.varna.exceptions.ExceptionFileFormatOrSyntax;\r
33 import fr.orsay.lri.varna.exceptions.ExceptionLoadingFailed;\r
34 import fr.orsay.lri.varna.exceptions.ExceptionPermissionDenied;\r
35 import jalview.datamodel.*;\r
36 import jalview.analysis.Rna;\r
37 \r
38 // import org.apache.log4j.*;\r
39 \r
40 /**\r
41  * This class is supposed to parse a Stockholm format file into Jalview There\r
42  * are TODOs in this class: we do not know what the database source and version\r
43  * is for the file when parsing the #GS= AC tag which associates accessions with\r
44  * sequences. Database references are also not parsed correctly: a separate\r
45  * reference string parser must be added to parse the database reference form\r
46  * into Jalview's local representation.\r
47  * \r
48  * @author bsb at sanger.ac.uk\r
49  * @version 0.3 + jalview mods\r
50  * \r
51  */\r
52 public class StockholmFile extends AlignFile\r
53 {\r
54   // static Logger logger = Logger.getLogger("jalview.io.StockholmFile");\r
55 \r
56   public StockholmFile()\r
57   {\r
58   }\r
59 \r
60   public StockholmFile(String inFile, String type) throws IOException, ExceptionFileFormatOrSyntax, ParserConfigurationException, SAXException, ExceptionPermissionDenied, ExceptionLoadingFailed, InterruptedException\r
61   {\r
62     super(inFile, type);\r
63   }\r
64 \r
65   public StockholmFile(FileParse source) throws IOException, ExceptionFileFormatOrSyntax, ParserConfigurationException, SAXException, ExceptionPermissionDenied, ExceptionLoadingFailed, InterruptedException\r
66   {\r
67     super(source);\r
68   }\r
69 \r
70   public void initData()\r
71   {\r
72     super.initData();\r
73   }\r
74 \r
75   /**\r
76    * Parse a file in Stockholm format into Jalview's data model. The file has to\r
77    * be passed at construction time\r
78    * \r
79    * @throws IOException\r
80    *           If there is an error with the input file\r
81    */\r
82   public void parse() throws IOException\r
83   {\r
84     StringBuffer treeString = new StringBuffer();\r
85     String treeName = null;\r
86     // --------------- Variable Definitions -------------------\r
87     String line;\r
88     String version;\r
89     // String id;\r
90     Hashtable seqAnn = new Hashtable(); // Sequence related annotations\r
91     Hashtable seqs = new Hashtable();\r
92     Regex p, r, rend, s, x;\r
93 \r
94     // Temporary line for processing RNA annotation\r
95     // String RNAannot = "";\r
96 \r
97     // ------------------ Parsing File ----------------------\r
98     // First, we have to check that this file has STOCKHOLM format, i.e. the\r
99     // first line must match\r
100     r = new Regex("# STOCKHOLM ([\\d\\.]+)");\r
101     if (!r.search(nextLine()))\r
102     {\r
103       throw new IOException(\r
104               "This file is not in valid STOCKHOLM format: First line does not contain '# STOCKHOLM'");\r
105     }\r
106     else\r
107     {\r
108       version = r.stringMatched(1);\r
109       // logger.debug("Stockholm version: " + version);\r
110     }\r
111 \r
112     // We define some Regexes here that will be used regularily later\r
113     rend = new Regex("^\\s*\\/\\/"); // Find the end of an alignment\r
114     p = new Regex("(\\S+)\\/(\\d+)\\-(\\d+)"); // split sequence id in\r
115     // id/from/to\r
116     s = new Regex("(\\S+)\\s+(\\S*)\\s+(.*)"); // Parses annotation subtype\r
117     r = new Regex("#=(G[FSRC]?)\\s+(.*)"); // Finds any annotation line\r
118     x = new Regex("(\\S+)\\s+(\\S+)"); // split id from sequence\r
119 \r
120     // Convert all bracket types to parentheses (necessary for passing to VARNA)\r
121     Regex openparen = new Regex("(<|\\[)", "(");\r
122     Regex closeparen = new Regex("(>|\\])", ")");\r
123 \r
124     // Detect if file is RNA by looking for bracket types\r
125     Regex detectbrackets = new Regex("(<|>|\\[|\\]|\\(|\\))");\r
126 \r
127     rend.optimize();\r
128     p.optimize();\r
129     s.optimize();\r
130     r.optimize();\r
131     x.optimize();\r
132     openparen.optimize();\r
133     closeparen.optimize();\r
134 \r
135     while ((line = nextLine()) != null)\r
136     {\r
137       if (line.length() == 0)\r
138       {\r
139         continue;\r
140       }\r
141       if (rend.search(line))\r
142       {\r
143         // End of the alignment, pass stuff back\r
144 \r
145         this.noSeqs = seqs.size();\r
146         // logger.debug("Number of sequences: " + this.noSeqs);\r
147         Enumeration accs = seqs.keys();\r
148         while (accs.hasMoreElements())\r
149         {\r
150           String acc = (String) accs.nextElement();\r
151           // logger.debug("Processing sequence " + acc);\r
152           String seq = (String) seqs.remove(acc);\r
153           if (maxLength < seq.length())\r
154           {\r
155             maxLength = seq.length();\r
156           }\r
157           int start = 1;\r
158           int end = -1;\r
159           String sid = acc;\r
160           /*\r
161            * Retrieve hash of annotations for this accession\r
162            * Associate Annotation with accession\r
163            */\r
164           Hashtable accAnnotations = null;\r
165 \r
166           if (seqAnn != null && seqAnn.containsKey(acc))\r
167           {\r
168             accAnnotations = (Hashtable) seqAnn.remove(acc);\r
169             //TODO: add structures to sequence\r
170           }\r
171 \r
172           // Split accession in id and from/to\r
173           if (p.search(acc))\r
174           {\r
175             sid = p.stringMatched(1);\r
176             start = Integer.parseInt(p.stringMatched(2));\r
177             end = Integer.parseInt(p.stringMatched(3));\r
178           }\r
179           // logger.debug(sid + ", " + start + ", " + end);\r
180 \r
181           Sequence seqO = new Sequence(sid, seq, start, end);\r
182           // Add Description (if any)\r
183           if (accAnnotations != null && accAnnotations.containsKey("DE"))\r
184           {\r
185             String desc = (String) accAnnotations.get("DE");\r
186             seqO.setDescription((desc == null) ? "" : desc);\r
187           }\r
188           // Add DB References (if any)\r
189           if (accAnnotations != null && accAnnotations.containsKey("DR"))\r
190           {\r
191             String dbr = (String) accAnnotations.get("DR");\r
192             if (dbr != null && dbr.indexOf(";") > -1)\r
193             {\r
194               String src = dbr.substring(0, dbr.indexOf(";"));\r
195               String acn = dbr.substring(dbr.indexOf(";") + 1);\r
196               jalview.util.DBRefUtils.parseToDbRef(seqO, src, "0", acn);\r
197               // seqO.addDBRef(dbref);\r
198             }\r
199           }        \r
200           if (accAnnotations != null && accAnnotations.containsKey("SS"))\r
201           {\r
202                   Vector v = (Vector) accAnnotations.get("SS");\r
203                   \r
204                   for (int i = 0; i < v.size(); i++)\r
205                     {\r
206                           AlignmentAnnotation an = (AlignmentAnnotation) v.elementAt(i);\r
207                           seqO.addAlignmentAnnotation(an);\r
208                           //annotations.add(an);\r
209                     }\r
210           }\r
211         \r
212           Hashtable features = null;\r
213           // We need to adjust the positions of all features to account for gaps\r
214           try\r
215           {\r
216             features = (Hashtable) accAnnotations.remove("features");\r
217           } catch (java.lang.NullPointerException e)\r
218           {\r
219             // loggerwarn("Getting Features for " + acc + ": " +\r
220             // e.getMessage());\r
221             // continue;\r
222           }\r
223           // if we have features\r
224           if (features != null)\r
225           {\r
226             int posmap[] = seqO.findPositionMap();\r
227             Enumeration i = features.keys();\r
228             while (i.hasMoreElements())\r
229             {\r
230               // TODO: parse out secondary structure annotation as annotation\r
231               // row\r
232               // TODO: parse out scores as annotation row\r
233               // TODO: map coding region to core jalview feature types\r
234               String type = i.nextElement().toString();\r
235               Hashtable content = (Hashtable) features.remove(type);\r
236               Enumeration j = content.keys();\r
237               while (j.hasMoreElements())\r
238               {\r
239                 String desc = j.nextElement().toString();\r
240                 String ns = content.get(desc).toString();\r
241                 char[] byChar = ns.toCharArray();\r
242                 for (int k = 0; k < byChar.length; k++)\r
243                 {\r
244                   char c = byChar[k];\r
245                   if (!(c == ' ' || c == '_' || c == '-' || c == '.')) // PFAM\r
246                   // uses\r
247                   // '.'\r
248                   // for\r
249                   // feature\r
250                   // background\r
251                   {\r
252                     int new_pos = posmap[k]; // look up nearest seqeunce\r
253                     // position to this column\r
254                     SequenceFeature feat = new SequenceFeature(type, desc,\r
255                             new_pos, new_pos, 0f, null);\r
256 \r
257                     seqO.addSequenceFeature(feat);\r
258                   }\r
259                 }\r
260               }\r
261 \r
262             }\r
263 \r
264           }\r
265           // garbage collect\r
266 \r
267           // logger.debug("Adding seq " + acc + " from " + start + " to " + end\r
268           // + ": " + seq);\r
269           this.seqs.addElement(seqO);\r
270         }\r
271         return; // finished parsing this segment of source\r
272       }\r
273       else if (!r.search(line))\r
274       {\r
275         // System.err.println("Found sequence line: " + line);\r
276 \r
277         // Split sequence in sequence and accession parts\r
278         if (!x.search(line))\r
279         {\r
280           // logger.error("Could not parse sequence line: " + line);\r
281           throw new IOException("Could not parse sequence line: " + line);\r
282         }\r
283         String ns = (String) seqs.get(x.stringMatched(1));\r
284         if (ns == null)\r
285         {\r
286           ns = "";\r
287         }\r
288         ns += x.stringMatched(2);\r
289 \r
290         seqs.put(x.stringMatched(1), ns);\r
291       }\r
292       else\r
293       {\r
294         String annType = r.stringMatched(1);\r
295         String annContent = r.stringMatched(2);\r
296 \r
297         // System.err.println("type:" + annType + " content: " + annContent);\r
298 \r
299         if (annType.equals("GF"))\r
300         {\r
301           /*\r
302            * Generic per-File annotation, free text Magic features: #=GF NH\r
303            * <tree in New Hampshire eXtended format> #=GF TN <Unique identifier\r
304            * for the next tree> Pfam descriptions: 7. DESCRIPTION OF FIELDS\r
305            * \r
306            * Compulsory fields: ------------------\r
307            * \r
308            * AC Accession number: Accession number in form PFxxxxx.version or\r
309            * PBxxxxxx. ID Identification: One word name for family. DE\r
310            * Definition: Short description of family. AU Author: Authors of the\r
311            * entry. SE Source of seed: The source suggesting the seed members\r
312            * belong to one family. GA Gathering method: Search threshold to\r
313            * build the full alignment. TC Trusted Cutoff: Lowest sequence score\r
314            * and domain score of match in the full alignment. NC Noise Cutoff:\r
315            * Highest sequence score and domain score of match not in full\r
316            * alignment. TP Type: Type of family -- presently Family, Domain,\r
317            * Motif or Repeat. SQ Sequence: Number of sequences in alignment. AM\r
318            * Alignment Method The order ls and fs hits are aligned to the model\r
319            * to build the full align. // End of alignment.\r
320            * \r
321            * Optional fields: ----------------\r
322            * \r
323            * DC Database Comment: Comment about database reference. DR Database\r
324            * Reference: Reference to external database. RC Reference Comment:\r
325            * Comment about literature reference. RN Reference Number: Reference\r
326            * Number. RM Reference Medline: Eight digit medline UI number. RT\r
327            * Reference Title: Reference Title. RA Reference Author: Reference\r
328            * Author RL Reference Location: Journal location. PI Previous\r
329            * identifier: Record of all previous ID lines. KW Keywords: Keywords.\r
330            * CC Comment: Comments. NE Pfam accession: Indicates a nested domain.\r
331            * NL Location: Location of nested domains - sequence ID, start and\r
332            * end of insert.\r
333            * \r
334            * Obsolete fields: ----------- AL Alignment method of seed: The\r
335            * method used to align the seed members.\r
336            */\r
337           // Let's save the annotations, maybe we'll be able to do something\r
338           // with them later...\r
339           Regex an = new Regex("(\\w+)\\s*(.*)");\r
340           if (an.search(annContent))\r
341           {\r
342             if (an.stringMatched(1).equals("NH"))\r
343             {\r
344               treeString.append(an.stringMatched(2));\r
345             }\r
346             else if (an.stringMatched(1).equals("TN"))\r
347             {\r
348               if (treeString.length() > 0)\r
349               {\r
350                 if (treeName == null)\r
351                 {\r
352                   treeName = "Tree " + (getTreeCount() + 1);\r
353                 }\r
354                 addNewickTree(treeName, treeString.toString());\r
355               }\r
356               treeName = an.stringMatched(2);\r
357               treeString = new StringBuffer();\r
358             }\r
359             setAlignmentProperty(an.stringMatched(1), an.stringMatched(2));\r
360           }\r
361         }\r
362         else if (annType.equals("GS"))\r
363         {\r
364           // Generic per-Sequence annotation, free text\r
365           /*\r
366            * Pfam uses these features: Feature Description ---------------------\r
367            * ----------- AC <accession> ACcession number DE <freetext>\r
368            * DEscription DR <db>; <accession>; Database Reference OS <organism>\r
369            * OrganiSm (species) OC <clade> Organism Classification (clade, etc.)\r
370            * LO <look> Look (Color, etc.)\r
371            */\r
372           if (s.search(annContent))\r
373           {\r
374             String acc = s.stringMatched(1);\r
375             String type = s.stringMatched(2);\r
376             String content = s.stringMatched(3);\r
377             // TODO: store DR in a vector.\r
378             // TODO: store AC according to generic file db annotation.\r
379             Hashtable ann;\r
380             if (seqAnn.containsKey(acc))\r
381             {\r
382               ann = (Hashtable) seqAnn.get(acc);\r
383             }\r
384             else\r
385             {\r
386               ann = new Hashtable();\r
387             }\r
388             ann.put(type, content);\r
389             seqAnn.put(acc, ann);\r
390           }\r
391           else\r
392           {\r
393             throw new IOException("Error parsing " + line);\r
394           }\r
395         }\r
396         else if (annType.equals("GC"))\r
397         {\r
398           // Generic per-Column annotation, exactly 1 char per column\r
399           // always need a label.\r
400           if (x.search(annContent))\r
401           {\r
402             // parse out and create alignment annotation directly.\r
403             parseAnnotationRow(annotations, x.stringMatched(1),\r
404                     x.stringMatched(2));\r
405           }\r
406         }\r
407         else if (annType.equals("GR"))\r
408         {\r
409           // Generic per-Sequence AND per-Column markup, exactly 1 char per\r
410           // column\r
411           /*\r
412            * Feature Description Markup letters ------- -----------\r
413            * -------------- SS Secondary Structure [HGIEBTSCX] SA Surface\r
414            * Accessibility [0-9X] (0=0%-10%; ...; 9=90%-100%) TM TransMembrane\r
415            * [Mio] PP Posterior Probability [0-9*] (0=0.00-0.05; 1=0.05-0.15;\r
416            * *=0.95-1.00) LI LIgand binding [*] AS Active Site [*] IN INtron (in\r
417            * or after) [0-2]\r
418            */\r
419           if (s.search(annContent))\r
420           {\r
421             String acc = s.stringMatched(1);\r
422             String type = s.stringMatched(2);\r
423             String seq = new String(s.stringMatched(3));\r
424             String description = null;\r
425             // Check for additional information about the current annotation\r
426             // We use a simple string tokenizer here for speed\r
427             StringTokenizer sep = new StringTokenizer(seq, " \t");\r
428             description = sep.nextToken();\r
429             if (sep.hasMoreTokens())\r
430             {\r
431               seq = sep.nextToken();\r
432             }\r
433             else\r
434             {\r
435               seq = description;\r
436               description = new String();\r
437             }\r
438             // sequence id with from-to fields\r
439 \r
440             Hashtable ann;\r
441             // Get an object with all the annotations for this sequence\r
442             if (seqAnn.containsKey(acc))\r
443             {\r
444               // logger.debug("Found annotations for " + acc);\r
445               ann = (Hashtable) seqAnn.get(acc);\r
446             }\r
447             else\r
448             {\r
449               // logger.debug("Creating new annotations holder for " + acc);\r
450               ann = new Hashtable();\r
451               seqAnn.put(acc, ann);\r
452             }\r
453             //TODO test structure, call parseAnnotationRow with vector from hashtable for specific sequence\r
454             Hashtable features;\r
455             // Get an object with all the content for an annotation\r
456             if (ann.containsKey("features"))\r
457             {\r
458               // logger.debug("Found features for " + acc);\r
459               features = (Hashtable) ann.get("features");\r
460             }\r
461             else\r
462             {\r
463               // logger.debug("Creating new features holder for " + acc);\r
464               features = new Hashtable();\r
465               ann.put("features", features);\r
466             }\r
467 \r
468             Hashtable content;\r
469             if (features.containsKey(this.id2type(type)))\r
470             {\r
471               // logger.debug("Found content for " + this.id2type(type));\r
472               content = (Hashtable) features.get(this.id2type(type));\r
473             }\r
474             else\r
475             {\r
476               // logger.debug("Creating new content holder for " +\r
477               // this.id2type(type));\r
478               content = new Hashtable();\r
479               features.put(this.id2type(type), content);\r
480             }\r
481             String ns = (String) content.get(description);\r
482             if (ns == null)\r
483             {\r
484               ns = "";\r
485             }\r
486             ns += seq;\r
487             content.put(description, ns);\r
488
489             if(type.equals("SS")){\r
490                 Hashtable strucAnn;\r
491                 if (seqAnn.containsKey(acc))\r
492                 {\r
493                   strucAnn = (Hashtable) seqAnn.get(acc);\r
494                 }\r
495                 else\r
496                 {\r
497                   strucAnn = new Hashtable();\r
498                 }\r
499                 \r
500                 Vector newStruc=new Vector();\r
501                 parseAnnotationRow(newStruc, type,ns);\r
502                 \r
503                 strucAnn.put(type, newStruc);\r
504                 seqAnn.put(acc, strucAnn);\r
505              }\r
506           }\r
507           else\r
508           {\r
509             System.err\r
510                     .println("Warning - couldn't parse sequence annotation row line:\n"\r
511                             + line);\r
512             // throw new IOException("Error parsing " + line);\r
513           }\r
514         }\r
515         else\r
516         {\r
517           throw new IOException("Unknown annotation detected: " + annType\r
518                   + " " + annContent);\r
519         }\r
520       }\r
521     }\r
522     if (treeString.length() > 0)\r
523     {\r
524       if (treeName == null)\r
525       {\r
526         treeName = "Tree " + (1 + getTreeCount());\r
527       }\r
528       addNewickTree(treeName, treeString.toString());\r
529     }\r
530   }\r
531 \r
532   protected static AlignmentAnnotation parseAnnotationRow(Vector annotation,\r
533           String label, String annots)\r
534   {\r
535     String convert1, convert2 = null;\r
536 \r
537     // Convert all bracket types to parentheses\r
538     Regex openparen = new Regex("(<|\\[)", "(");\r
539     Regex closeparen = new Regex("(>|\\])", ")");\r
540 \r
541     // Detect if file is RNA by looking for bracket types\r
542     Regex detectbrackets = new Regex("(<|>|\\[|\\]|\\(|\\))");\r
543 \r
544     convert1 = openparen.replaceAll(annots);\r
545     convert2 = closeparen.replaceAll(convert1);\r
546     annots = convert2;\r
547 \r
548     String type = (label.indexOf("_cons") == label.length() - 5) ? label\r
549             .substring(0, label.length() - 5) : label;\r
550     boolean ss = false;\r
551     type = id2type(type);\r
552     if (type.equals("secondary structure"))\r
553     {\r
554       ss = true;\r
555     }\r
556     // decide on secondary structure or not.\r
557     Annotation[] els = new Annotation[annots.length()];\r
558     for (int i = 0; i < annots.length(); i++)\r
559     {\r
560       String pos = annots.substring(i, i + 1);\r
561       Annotation ann;\r
562       ann = new Annotation(pos, "", ' ', 0f); // 0f is 'valid' null - will not\r
563       // be written out\r
564       if (ss)\r
565       {\r
566         if (detectbrackets.search(pos))\r
567         {\r
568           ann.secondaryStructure = jalview.schemes.ResidueProperties\r
569                   .getRNASecStrucState(pos).charAt(0);\r
570         }\r
571         else\r
572         {\r
573           ann.secondaryStructure = jalview.schemes.ResidueProperties\r
574                   .getDssp3state(pos).charAt(0);\r
575         }\r
576 \r
577         if (ann.secondaryStructure == pos.charAt(0) || pos.charAt(0) == 'C')\r
578         {\r
579           ann.displayCharacter = ""; // null; // " ";\r
580         }\r
581         else\r
582         {\r
583           ann.displayCharacter = " " + ann.displayCharacter;\r
584         }\r
585       }\r
586 \r
587       els[i] = ann;\r
588     }\r
589     AlignmentAnnotation annot = null;\r
590     Enumeration e = annotation.elements();\r
591     while (e.hasMoreElements())\r
592     {\r
593       annot = (AlignmentAnnotation) e.nextElement();\r
594       if (annot.label.equals(type))\r
595         break;\r
596       annot = null;\r
597     }\r
598     if (annot == null)\r
599     {\r
600       annot = new AlignmentAnnotation(type, type, els);\r
601       annotation.addElement(annot);\r
602     }\r
603     else\r
604     {\r
605       Annotation[] anns = new Annotation[annot.annotations.length\r
606               + els.length];\r
607       System.arraycopy(annot.annotations, 0, anns, 0,\r
608               annot.annotations.length);\r
609       System.arraycopy(els, 0, anns, annot.annotations.length, els.length);\r
610       annot.annotations = anns;\r
611       //System.out.println("else: ");\r
612     }\r
613     return annot;\r
614   }\r
615 \r
616   public static String print(SequenceI[] s)\r
617   {\r
618     return "not yet implemented";\r
619   }\r
620 \r
621   public String print()\r
622   {\r
623     return print(getSeqsAsArray());\r
624   }\r
625 \r
626   private static Hashtable typeIds = null;\r
627   static\r
628   {\r
629     if (typeIds == null)\r
630     {\r
631       typeIds = new Hashtable();\r
632       typeIds.put("SS", "secondary structure");\r
633       typeIds.put("SA", "surface accessibility");\r
634       typeIds.put("TM", "transmembrane");\r
635       typeIds.put("PP", "posterior probability");\r
636       typeIds.put("LI", "ligand binding");\r
637       typeIds.put("AS", "active site");\r
638       typeIds.put("IN", "intron");\r
639       typeIds.put("IR", "interacting residue");\r
640       typeIds.put("AC", "accession");\r
641       typeIds.put("OS", "organism");\r
642       typeIds.put("CL", "class");\r
643       typeIds.put("DE", "description");\r
644       typeIds.put("DR", "reference");\r
645       typeIds.put("LO", "look");\r
646       typeIds.put("RF", "reference positions");\r
647 \r
648     }\r
649   }\r
650 \r
651   protected static String id2type(String id)\r
652   {\r
653     if (typeIds.containsKey(id))\r
654     {\r
655       return (String) typeIds.get(id);\r
656     }\r
657     System.err.println("Warning : Unknown Stockholm annotation type code "\r
658             + id);\r
659     return id;\r
660   }\r
661   /**\r
662    * //ssline is complete secondary structure line private AlignmentAnnotation\r
663    * addHelices(Vector annotation, String label, String ssline) {\r
664    * \r
665    * // decide on secondary structure or not. Annotation[] els = new\r
666    * Annotation[ssline.length()]; for (int i = 0; i < ssline.length(); i++) {\r
667    * String pos = ssline.substring(i, i + 1); Annotation ann; ann = new\r
668    * Annotation(pos, "", ' ', 0f); // 0f is 'valid' null - will not\r
669    * \r
670    * ann.secondaryStructure =\r
671    * jalview.schemes.ResidueProperties.getRNAssState(pos).charAt(0);\r
672    * \r
673    * ann.displayCharacter = "x" + ann.displayCharacter;\r
674    * \r
675    * System.out.println(ann.displayCharacter);\r
676    * \r
677    * els[i] = ann; } AlignmentAnnotation helicesAnnot = null; Enumeration e =\r
678    * annotation.elements(); while (e.hasMoreElements()) { helicesAnnot =\r
679    * (AlignmentAnnotation) e.nextElement(); if (helicesAnnot.label.equals(type))\r
680    * break; helicesAnnot = null; } if (helicesAnnot == null) { helicesAnnot =\r
681    * new AlignmentAnnotation(type, type, els);\r
682    * annotation.addElement(helicesAnnot); } else { Annotation[] anns = new\r
683    * Annotation[helicesAnnot.annotations.length + els.length];\r
684    * System.arraycopy(helicesAnnot.annotations, 0, anns, 0,\r
685    * helicesAnnot.annotations.length); System.arraycopy(els, 0, anns,\r
686    * helicesAnnot.annotations.length, els.length); helicesAnnot.annotations =\r
687    * anns; }\r
688    * \r
689    * helicesAnnot.features = Rna.GetBasePairs(ssline);\r
690    * Rna.HelixMap(helicesAnnot.features);\r
691    * \r
692    * \r
693    * return helicesAnnot; }\r
694    */\r
695 }\r