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