Jalview 2.6 source licence
[jalview.git] / src / jalview / analysis / SeqsetUtils.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.6)
3  * Copyright (C) 2010 J Procter, AM Waterhouse, 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 package jalview.analysis;
19
20 import java.util.*;
21
22 import jalview.datamodel.*;
23
24 /**
25  * <p>
26  * Title:
27  * </p>
28  * 
29  * <p>
30  * Description:
31  * </p>
32  * 
33  * <p>
34  * Copyright: Copyright (c) 2004
35  * </p>
36  * 
37  * <p>
38  * Company: Dundee University
39  * </p>
40  * 
41  * @author not attributable
42  * @version 1.0
43  */
44 public class SeqsetUtils
45 {
46
47   /**
48    * Store essential properties of a sequence in a hashtable for later recovery
49    * Keys are Name, Start, End, SeqFeatures, PdbId
50    * 
51    * @param seq
52    *          SequenceI
53    * @return Hashtable
54    */
55   public static Hashtable SeqCharacterHash(SequenceI seq)
56   {
57     Hashtable sqinfo = new Hashtable();
58     sqinfo.put("Name", seq.getName());
59     sqinfo.put("Start", new Integer(seq.getStart()));
60     sqinfo.put("End", new Integer(seq.getEnd()));
61     if (seq.getDescription() != null)
62     {
63       sqinfo.put("Description", seq.getDescription());
64     }
65     Vector sfeat = new Vector();
66     jalview.datamodel.SequenceFeature[] sfarray = seq.getSequenceFeatures();
67     if (sfarray != null && sfarray.length > 0)
68     {
69       for (int i = 0; i < sfarray.length; i++)
70       {
71         sfeat.addElement(sfarray[i]);
72       }
73     }
74     sqinfo.put("SeqFeatures", sfeat);
75     sqinfo.put("PdbId", (seq.getPDBId() != null) ? seq.getPDBId()
76             : new Vector());
77     sqinfo.put("datasetSequence", (seq.getDatasetSequence() != null) ? seq
78             .getDatasetSequence() : new Sequence("THISISAPLACEHOLDER", ""));
79     return sqinfo;
80   }
81
82   /**
83    * Recover essential properties of a sequence from a hashtable TODO: replace
84    * these methods with something more elegant.
85    * 
86    * @param sq
87    *          SequenceI
88    * @param sqinfo
89    *          Hashtable
90    * @return boolean true if name was not updated from sqinfo Name entry
91    */
92   public static boolean SeqCharacterUnhash(SequenceI sq, Hashtable sqinfo)
93   {
94     boolean namePresent = true;
95     if (sqinfo == null)
96     {
97       return false;
98     }
99     String oldname = (String) sqinfo.get("Name");
100     Integer start = (Integer) sqinfo.get("Start");
101     Integer end = (Integer) sqinfo.get("End");
102     Vector sfeatures = (Vector) sqinfo.get("SeqFeatures");
103     Vector pdbid = (Vector) sqinfo.get("PdbId");
104     String description = (String) sqinfo.get("Description");
105     Sequence seqds = (Sequence) sqinfo.get("datasetSequence");
106     if (oldname == null)
107     {
108       namePresent = false;
109     }
110     else
111     {
112       sq.setName(oldname);
113     }
114     if (pdbid != null && pdbid.size() > 0)
115     {
116       sq.setPDBId(pdbid);
117     }
118
119     if ((start != null) && (end != null))
120     {
121       sq.setStart(start.intValue());
122       sq.setEnd(end.intValue());
123     }
124
125     if ((sfeatures != null) && (sfeatures.size() > 0))
126     {
127       SequenceFeature[] sfarray = new SequenceFeature[sfeatures.size()];
128       for (int is = 0, isize = sfeatures.size(); is < isize; is++)
129       {
130         sfarray[is] = (SequenceFeature) sfeatures.elementAt(is);
131       }
132       sq.setSequenceFeatures(sfarray);
133     }
134     if (description != null)
135     {
136       sq.setDescription(description);
137     }
138     if ((seqds != null)
139             && !(seqds.getName().equals("THISISAPLACEHOLDER") && seqds
140                     .getLength() == 0))
141     {
142       sq.setDatasetSequence(seqds);
143     }
144
145     return namePresent;
146   }
147
148   /**
149    * Form of the unique name used in uniquify for the i'th sequence in an
150    * ordered vector of sequences.
151    * 
152    * @param i
153    *          int
154    * @return String
155    */
156   public static String unique_name(int i)
157   {
158     return new String("Sequence" + i);
159   }
160
161   /**
162    * Generates a hash of SeqCharacterHash properties for each sequence in a
163    * sequence set, and optionally renames the sequences to an unambiguous 'safe'
164    * name.
165    * 
166    * @param sequences
167    *          SequenceI[]
168    * @param write_names
169    *          boolean set this to rename each of the sequences to its
170    *          unique_name(index) name
171    * @return Hashtable to be passed to
172    * @see deuniquify to recover original names (and properties) for renamed
173    *      sequences
174    */
175   public static Hashtable uniquify(SequenceI[] sequences,
176           boolean write_names)
177   {
178     // Generate a safely named sequence set and a hash to recover the sequence
179     // names
180     Hashtable map = new Hashtable();
181     // String[] un_names = new String[sequences.length];
182
183     for (int i = 0; i < sequences.length; i++)
184     {
185       String safename = unique_name(i);
186       map.put(safename, SeqCharacterHash(sequences[i]));
187
188       if (write_names)
189       {
190         sequences[i].setName(safename);
191       }
192     }
193
194     return map;
195   }
196
197   /**
198    * recover unsafe sequence names and original properties for a sequence set
199    * using a map generated by
200    * 
201    * @see uniquify(sequences,true)
202    * @param map
203    *          Hashtable
204    * @param sequences
205    *          SequenceI[]
206    * @return boolean
207    */
208   public static boolean deuniquify(Hashtable map, SequenceI[] sequences)
209   {
210     return deuniquify(map, sequences, true);
211   }
212
213   /**
214    * recover unsafe sequence names and original properties for a sequence set
215    * using a map generated by
216    * 
217    * @see uniquify(sequences,true)
218    * @param map
219    *          Hashtable
220    * @param sequences
221    *          SequenceI[]
222    * @param quiet
223    *          when false, don't complain about sequences without any data in the
224    *          map.
225    * @return boolean
226    */
227   public static boolean deuniquify(Hashtable map, SequenceI[] sequences,
228           boolean quiet)
229   {
230     jalview.analysis.SequenceIdMatcher matcher = new SequenceIdMatcher(
231             sequences);
232     SequenceI msq = null;
233     Enumeration keys = map.keys();
234     Vector unmatched = new Vector();
235     for (int i = 0, j = sequences.length; i < j; i++)
236     {
237       unmatched.addElement(sequences[i]);
238     }
239     while (keys.hasMoreElements())
240     {
241       Object key = keys.nextElement();
242       if (key instanceof String)
243       {
244         if ((msq = matcher.findIdMatch((String) key)) != null)
245         {
246           Hashtable sqinfo = (Hashtable) map.get(key);
247           unmatched.removeElement(msq);
248           SeqCharacterUnhash(msq, sqinfo);
249         }
250         else
251         {
252           if (!quiet)
253           {
254             System.err.println("Can't find '" + ((String) key)
255                     + "' in uniquified alignment");
256           }
257         }
258       }
259     }
260     if (unmatched.size() > 0 && !quiet)
261     {
262       System.err.println("Did not find matches for :");
263       for (Enumeration i = unmatched.elements(); i.hasMoreElements(); System.out
264               .println(((SequenceI) i.nextElement()).getName()))
265       {
266         ;
267       }
268       return false;
269     }
270
271     return true;
272   }
273
274   /**
275    * returns a subset of the sequenceI seuqences, including only those that
276    * contain at least one residue.
277    * 
278    * @param sequences
279    *          SequenceI[]
280    * @return SequenceI[]
281    */
282   public static SequenceI[] getNonEmptySequenceSet(SequenceI[] sequences)
283   {
284     // Identify first row of alignment with residues for prediction
285     boolean ungapped[] = new boolean[sequences.length];
286     int msflen = 0;
287     for (int i = 0, j = sequences.length; i < j; i++)
288     {
289       String tempseq = jalview.analysis.AlignSeq.extractGaps(
290               jalview.util.Comparison.GapChars, sequences[i]
291                       .getSequenceAsString());
292
293       if (tempseq.length() == 0)
294       {
295         ungapped[i] = false;
296       }
297       else
298       {
299         ungapped[i] = true;
300         msflen++;
301       }
302     }
303     if (msflen == 0)
304     {
305       return null; // no minimal set
306     }
307     // compose minimal set
308     SequenceI[] mset = new SequenceI[msflen];
309     for (int i = 0, j = sequences.length, k = 0; i < j; i++)
310     {
311       if (ungapped[i])
312       {
313         mset[k++] = sequences[i];
314       }
315     }
316     ungapped = null;
317     return mset;
318   }
319 }