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