proxy commit for Anne Menard <menard.annec@gmail.com> throw generic exceptions (just...
[jalview.git] / src / jalview / io / JPredFile.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8)
3  * Copyright (C) 2012 J Procter, AM Waterhouse, LM Lui, J Engelhardt, G Barton, M Clamp, S Searle
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
10  *  
11  * Jalview is distributed in the hope that it will be useful, but 
12  * WITHOUT ANY WARRANTY; without even the implied warranty 
13  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
14  * PURPOSE.  See the GNU General Public License for more details.
15  * 
16  * You should have received a copy of the GNU General Public License along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 /**
19  * PredFile.java
20  * JalviewX / Vamsas Project
21  * JPred.seq.concise reader
22  */
23 package jalview.io;
24
25 import java.io.*;
26 import java.util.*;
27
28 import javax.xml.parsers.ParserConfigurationException;
29
30 import org.xml.sax.SAXException;
31
32 import fr.orsay.lri.varna.exceptions.ExceptionFileFormatOrSyntax;
33 import fr.orsay.lri.varna.exceptions.ExceptionLoadingFailed;
34 import fr.orsay.lri.varna.exceptions.ExceptionPermissionDenied;
35 import fr.orsay.lri.varna.exceptions.ExceptionUnmatchedClosingParentheses;
36
37 import jalview.datamodel.*;
38
39 /**
40  * Parser for the JPred/JNet concise format. This is a series of CSV lines, each
41  * line is either a sequence (QUERY), a sequence profile (align;), or jnet
42  * prediction annotation (anything else). Automagic translation happens for
43  * annotation called 'JNETPRED' (translated to Secondary Structure Prediction),
44  * or 'JNETCONF' (translates to 'Prediction Confidence'). Numeric scores are
45  * differentiated from symbolic by being parseable into a float vector. They are
46  * put in Scores. Symscores gets the others. JNetAnnotationMaker translates the
47  * data parsed by this object into annotation on an alignment. It is
48  * automatically called but can be used to transfer the annotation onto a
49  * sequence in another alignment (and insert gaps where necessary)
50  * 
51  * @author jprocter
52  * @version $Revision$
53  */
54 public class JPredFile extends AlignFile
55 {
56   Vector ids;
57
58   Vector conf;
59
60   Hashtable Scores; // Hash of names and score vectors
61
62   Hashtable Symscores; // indexes of symbol annotation properties in sequenceI
63
64   // vector
65
66   private int QuerySeqPosition;
67
68   /**
69    * Creates a new JPredFile object.
70    * 
71    * @param inFile
72    *          DOCUMENT ME!
73    * @param type
74    *          DOCUMENT ME!
75  * @throws Exception 
76    */
77   public JPredFile(String inFile, String type) throws Exception
78   {
79     super(inFile, type);
80   }
81
82   public JPredFile(FileParse source) throws Exception
83   {
84     super(source);
85   }
86
87   /**
88    * DOCUMENT ME!
89    * 
90    * @param QuerySeqPosition
91    *          DOCUMENT ME!
92    */
93   public void setQuerySeqPosition(int QuerySeqPosition)
94   {
95     this.QuerySeqPosition = QuerySeqPosition;
96   }
97
98   /**
99    * DOCUMENT ME!
100    * 
101    * @return DOCUMENT ME!
102    */
103   public int getQuerySeqPosition()
104   {
105     return QuerySeqPosition;
106   }
107
108   /**
109    * DOCUMENT ME!
110    * 
111    * @return DOCUMENT ME!
112    */
113   public Hashtable getScores()
114   {
115     return Scores;
116   }
117
118   /**
119    * DOCUMENT ME!
120    * 
121    * @return DOCUMENT ME!
122    */
123   public Hashtable getSymscores()
124   {
125     return Symscores;
126   }
127
128   /**
129    * DOCUMENT ME!
130    */
131   public void initData()
132   {
133     super.initData();
134     Scores = new Hashtable();
135     ids = null;
136     conf = null;
137   }
138
139   /**
140    * parse a JPred concise file into a sequence-alignment like object.
141    */
142   public void parse() throws IOException
143   {
144     // JBPNote log.System.out.println("all read in ");
145     String line;
146     QuerySeqPosition = -1;
147     noSeqs = 0;
148
149     Vector seq_entries = new Vector();
150     Vector ids = new Vector();
151     Hashtable Symscores = new Hashtable();
152
153     while ((line = nextLine()) != null)
154     {
155       // Concise format allows no comments or non comma-formatted data
156       StringTokenizer str = new StringTokenizer(line, ":");
157       String id = "";
158
159       if (!str.hasMoreTokens())
160       {
161         continue;
162       }
163
164       id = str.nextToken();
165
166       String seqsym = str.nextToken();
167       StringTokenizer symbols = new StringTokenizer(seqsym, ",");
168
169       // decide if we have more than just alphanumeric symbols
170       int numSymbols = symbols.countTokens();
171
172       if (numSymbols == 0)
173       {
174         continue;
175       }
176
177       if (seqsym.length() != (2 * numSymbols))
178       {
179         // Set of scalars for some property
180         if (Scores.containsKey(id))
181         {
182           int i = 1;
183
184           while (Scores.containsKey(id + "_" + i))
185           {
186             i++;
187           }
188
189           id = id + "_" + i;
190         }
191
192         Vector scores = new Vector();
193
194         // Typecheck from first entry
195         int i = 0;
196         String ascore = "dead";
197
198         try
199         {
200           // store elements as floats...
201           while (symbols.hasMoreTokens())
202           {
203             ascore = symbols.nextToken();
204
205             Float score = new Float(ascore);
206             scores.addElement((Object) score);
207           }
208
209           Scores.put(id, scores);
210         } catch (Exception e)
211         {
212           // or just keep them as strings
213           i = scores.size();
214
215           for (int j = 0; j < i; j++)
216           {
217             scores.setElementAt(
218                     (Object) ((Float) scores.elementAt(j)).toString(), j);
219           }
220
221           scores.addElement((Object) ascore);
222
223           while (symbols.hasMoreTokens())
224           {
225             ascore = symbols.nextToken();
226             scores.addElement((Object) ascore);
227           }
228
229           Scores.put(id, scores);
230         }
231       }
232       else if (id.equals("jnetconf"))
233       {
234         // log.debug System.out.println("here");
235         id = "Prediction Confidence";
236         this.conf = new Vector(numSymbols);
237
238         for (int i = 0; i < numSymbols; i++)
239         {
240           conf.setElementAt(symbols.nextToken(), i);
241         }
242       }
243       else
244       {
245         // Sequence or a prediction string (rendered as sequence)
246         StringBuffer newseq = new StringBuffer();
247
248         for (int i = 0; i < numSymbols; i++)
249         {
250           newseq.append(symbols.nextToken());
251         }
252
253         if (id.indexOf(";") > -1)
254         {
255           seq_entries.addElement(newseq);
256
257           int i = 1;
258           String name = id.substring(id.indexOf(";") + 1);
259
260           while (ids.lastIndexOf(name) > -1)
261           {
262             name = id.substring(id.indexOf(";") + 1) + "_" + ++i;
263           }
264
265           if (QuerySeqPosition == -1)
266             QuerySeqPosition = ids.size();
267           ids.addElement(name);
268           noSeqs++;
269         }
270         else
271         {
272           if (id.equals("JNETPRED"))
273           {
274             id = "Predicted Secondary Structure";
275           }
276
277           seq_entries.addElement(newseq.toString());
278           ids.addElement(id);
279           Symscores.put((Object) id, (Object) new Integer(ids.size() - 1));
280         }
281       }
282     }
283     /*
284      * leave it to the parser user to actually check this. if (noSeqs < 1) {
285      * throw new IOException( "JpredFile Parser: No sequence in the
286      * prediction!"); }
287      */
288
289     maxLength = seq_entries.elementAt(0).toString().length();
290
291     for (int i = 0; i < ids.size(); i++)
292     {
293       // Add all sequence like objects
294       Sequence newSeq = new Sequence(ids.elementAt(i).toString(),
295               seq_entries.elementAt(i).toString(), 1, seq_entries
296                       .elementAt(i).toString().length());
297
298       if (maxLength != seq_entries.elementAt(i).toString().length())
299       {
300         throw new IOException("JPredConcise: Entry ("
301                 + ids.elementAt(i).toString()
302                 + ") has an unexpected number of columns");
303       }
304
305       if ((newSeq.getName().startsWith("QUERY") || newSeq.getName()
306               .startsWith("align;")) && (QuerySeqPosition == -1))
307       {
308         QuerySeqPosition = seqs.size();
309       }
310
311       seqs.addElement(newSeq);
312     }
313     if (seqs.size() > 0 && QuerySeqPosition > -1)
314     {
315       // try to make annotation for a prediction only input (default if no
316       // alignment is given and prediction contains a QUERY or align;sequence_id
317       // line)
318       Alignment tal = new Alignment(this.getSeqsAsArray());
319       try
320       {
321         JnetAnnotationMaker.add_annotation(this, tal, QuerySeqPosition,
322                 true);
323       } catch (Exception e)
324       {
325         tal = null;
326         IOException ex = new IOException(
327                 "Couldn't parse concise annotation for prediction profile.\n"
328                         + e);
329         e.printStackTrace(); // java 1.1 does not have :
330                              // ex.setStackTrace(e.getStackTrace());
331         throw ex;
332       }
333       this.annotations = new Vector();
334       AlignmentAnnotation[] aan = tal.getAlignmentAnnotation();
335       for (int aai = 0; aan != null && aai < aan.length; aai++)
336       {
337         annotations.addElement(aan[aai]);
338       }
339     }
340   }
341
342   /**
343    * print
344    * 
345    * @return String
346    */
347   public String print()
348   {
349     return "Not Supported";
350   }
351
352   /**
353    * DOCUMENT ME!
354    * 
355    * @param args
356    *          DOCUMENT ME!
357  * @throws Exception 
358    */
359   public static void main(String[] args) throws Exception
360   {
361     try
362     {
363       JPredFile blc = new JPredFile(args[0], "File");
364
365       for (int i = 0; i < blc.seqs.size(); i++)
366       {
367         System.out.println(((Sequence) blc.seqs.elementAt(i)).getName()
368                 + "\n"
369                 + ((Sequence) blc.seqs.elementAt(i)).getSequenceAsString()
370                 + "\n");
371       }
372     } catch (java.io.IOException e)
373     {
374       System.err.println("Exception " + e);
375       // e.printStackTrace(); not java 1.1 compatible!
376     }
377   }
378
379   Vector annotSeqs = null;
380
381   /**
382    * removeNonSequences
383    */
384   public void removeNonSequences()
385   {
386     if (annotSeqs != null)
387     {
388       return;
389     }
390     annotSeqs = new Vector();
391     Vector newseqs = new Vector();
392     int i = 0;
393     int j = seqs.size();
394     for (; i < QuerySeqPosition; i++)
395     {
396       annotSeqs.addElement(seqs.elementAt(i));
397     }
398     // check that no stray annotations have been added at the end.
399     {
400       SequenceI sq = (SequenceI) seqs.elementAt(j - 1);
401       if (sq.getName().toUpperCase().startsWith("JPRED"))
402       {
403         annotSeqs.addElement(sq);
404         seqs.removeElementAt(--j);
405       }
406     }
407     for (; i < j; i++)
408     {
409       newseqs.addElement(seqs.elementAt(i));
410     }
411
412     seqs.removeAllElements();
413     seqs = newseqs;
414   }
415 }
416
417 /*
418  * StringBuffer out = new StringBuffer();
419  * 
420  * out.append("START PRED\n"); for (int i = 0; i < s[0].sequence.length(); i++)
421  * { out.append(s[0].sequence.substring(i, i + 1) + " ");
422  * out.append(s[1].sequence.substring(i, i + 1) + " ");
423  * out.append(s[1].score[0].elementAt(i) + " ");
424  * out.append(s[1].score[1].elementAt(i) + " ");
425  * out.append(s[1].score[2].elementAt(i) + " ");
426  * out.append(s[1].score[3].elementAt(i) + " ");
427  * 
428  * out.append("\n"); } out.append("END PRED\n"); return out.toString(); }
429  * 
430  * public static void main(String[] args) { try { BLCFile blc = new
431  * BLCFile(args[0], "File"); DrawableSequence[] s = new
432  * DrawableSequence[blc.seqs.size()]; for (int i = 0; i < blc.seqs.size(); i++)
433  * { s[i] = new DrawableSequence( (Sequence) blc.seqs.elementAt(i)); } String
434  * out = BLCFile.print(s);
435  * 
436  * AlignFrame af = new AlignFrame(null, s); af.resize(700, 500); af.show();
437  * System.out.println(out); } catch (java.io.IOException e) {
438  * System.out.println("Exception " + e); } } }
439  */