fixes bug reported by Christopher Tan (help@jalview.org) - preservation of sequence...
[jalview.git] / src / jalview / analysis / SeqsetUtils.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer
3  * Copyright (C) 2006 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 package jalview.analysis;
20
21 import java.util.*;
22
23 import jalview.datamodel.*;
24
25 /**
26  * <p>Title: </p>
27  *
28  * <p>Description: </p>
29  *
30  * <p>Copyright: Copyright (c) 2004</p>
31  *
32  * <p>Company: Dundee University</p>
33  *
34  * @author not attributable
35  * @version 1.0
36  */
37 public class SeqsetUtils
38 {
39
40   /**
41    * Store essential properties of a sequence in a hashtable for later recovery
42    *  Keys are Name, Start, End, SeqFeatures, PdbId
43    * @param seq SequenceI
44    * @return Hashtable
45    */
46   public static Hashtable SeqCharacterHash(SequenceI seq)
47   {
48     Hashtable sqinfo = new Hashtable();
49     sqinfo.put("Name", seq.getName());
50     sqinfo.put("Start", new Integer(seq.getStart()));
51     sqinfo.put("End", new Integer(seq.getEnd()));
52     if (seq.getDescription()!=null)
53       sqinfo.put("Description", seq.getDescription());
54     Vector sfeat = new Vector();
55     jalview.datamodel.SequenceFeature[] sfarray=seq.getSequenceFeatures();
56     if (sfarray!=null && sfarray.length>0) {
57       for (int i=0;i<sfarray.length;i++)
58         sfeat.add(sfarray[i]);
59     }
60     sqinfo.put("SeqFeatures", sfeat);
61     sqinfo.put("PdbId",
62                (seq.getPDBId() != null) ? seq.getPDBId() : new Vector());
63     sqinfo.put("datasetSequence", (seq.getDatasetSequence() !=null) ? seq.getDatasetSequence() : new Sequence("THISISAPLACEHOLDER",""));
64     return sqinfo;
65   }
66
67   /**
68    * Recover essential properties of a sequence from a hashtable
69    * TODO: replace these methods with something more elegant.
70    * @param sq SequenceI
71    * @param sqinfo Hashtable
72    * @return boolean true if name was not updated from sqinfo Name entry
73    */
74   public static boolean SeqCharacterUnhash(SequenceI sq, Hashtable sqinfo)
75   {
76     boolean namePresent = true;
77     if (sqinfo==null)
78       return false;
79     String oldname = (String) sqinfo.get("Name");
80     Integer start = (Integer) sqinfo.get("Start");
81     Integer end = (Integer) sqinfo.get("End");
82     Vector sfeatures = (Vector) sqinfo.get(
83         "SeqFeatures");
84     Vector pdbid = (Vector) sqinfo.get("PdbId");
85     String description=(String) sqinfo.get("Description");
86     Sequence seqds = (Sequence) sqinfo.get("datasetSequence");
87     if (oldname == null)
88     {
89       namePresent = false;
90     }
91     else
92     {
93       sq.setName(oldname);
94     }
95     if (pdbid!=null && pdbid.size()>0)
96     {
97       sq.setPDBId(pdbid);
98     }
99
100     if ( (start != null) && (end != null))
101     {
102       sq.setStart(start.intValue());
103       sq.setEnd(end.intValue());
104     }
105
106     if ((sfeatures != null) && (sfeatures.size()>0))
107     {
108       SequenceFeature[] sfarray = (SequenceFeature[]) sfeatures.toArray();
109       sq.setSequenceFeatures(sfarray);
110     }
111     if (description!=null)
112       sq.setDescription(description);
113     if ((seqds!=null) && !(seqds.getName().equals("THISISAPLACEHOLDER") && seqds.getLength()==0)) {
114       sq.setDatasetSequence(seqds);
115     }
116
117     return namePresent;
118   }
119
120   /**
121    * Form of the unique name used in uniquify for the i'th sequence in an ordered vector of sequences.
122    * @param i int
123    * @return String
124    */
125   public static String unique_name(int i)
126   {
127     return new String("Sequence" + i);
128   }
129
130   /**
131    * Generates a hash of SeqCharacterHash properties for each sequence
132    * in a sequence set, and optionally renames the sequences to an
133    * unambiguous 'safe' name.
134    * @param sequences SequenceI[]
135    * @param write_names boolean set this to rename each of the sequences to its unique_name(index) name
136    * @return Hashtable to be passed to @see deuniquify to recover original names (and properties) for renamed sequences
137    */
138   public static Hashtable uniquify(SequenceI[] sequences, boolean write_names)
139   {
140     // Generate a safely named sequence set and a hash to recover the sequence names
141     Hashtable map = new Hashtable();
142     //String[] un_names = new String[sequences.length];
143
144     for (int i = 0; i < sequences.length; i++)
145     {
146       String safename = unique_name(i);
147       map.put(safename, SeqCharacterHash(sequences[i]));
148
149       if (write_names)
150       {
151         sequences[i].setName(safename);
152       }
153     }
154
155
156     return map;
157   }
158   /**
159    * recover unsafe sequence names and original properties for a sequence
160    * set using a map generated by @see uniquify(sequences,true)
161    * @param map Hashtable
162    * @param sequences SequenceI[]
163    * @return boolean
164    */
165   public static boolean deuniquify(Hashtable map, SequenceI[] sequences)
166   {
167     jalview.analysis.SequenceIdMatcher matcher = new SequenceIdMatcher(sequences);
168     SequenceI msq = null;
169     Enumeration keys = map.keys();
170     Vector unmatched = new Vector();
171     for (int i=0, j=sequences.length; i<j; i++)
172       unmatched.add(sequences[i]);
173     while (keys.hasMoreElements()) {
174       Object key = keys.nextElement();
175       if (key instanceof String) {
176         if ((msq = matcher.findIdMatch((String) key))!=null) {
177           Hashtable sqinfo = (Hashtable) map.get(key);
178           unmatched.remove(msq);
179           SeqCharacterUnhash(msq, sqinfo);
180         }
181         else
182         {
183           System.err.println("Can't find '"+((String) key)+"' in uniquified alignment");
184         }
185       }
186     }
187     if (unmatched.size()>0) {
188       System.err.println("Did not find matches for :");
189       for (Enumeration i = unmatched.elements(); i.hasMoreElements(); System.out.println(((SequenceI) i.nextElement()).getName()))
190            ;
191       return false;
192     }
193
194     return true;
195   }
196   /**
197    * returns a subset of the sequenceI seuqences,
198    * including only those that contain at least one residue.
199    * @param sequences SequenceI[]
200    * @return SequenceI[]
201    */
202   public static SequenceI[] getNonEmptySequenceSet(SequenceI[] sequences) {
203       // Identify first row of alignment with residues for prediction
204       boolean ungapped[] = new boolean[sequences.length];
205       int msflen=0;
206       for (int i=0,j=sequences.length; i<j;i++) {
207         String tempseq = jalview.analysis.AlignSeq.extractGaps(jalview.util.Comparison.GapChars, sequences[i].getSequence());
208         if (tempseq.length()==0)
209           ungapped[i]=false;
210         else {
211           ungapped[i]=true;
212           msflen++;
213         }
214       }
215       if (msflen==0)
216         return null; // no minimal set
217       // compose minimal set
218       SequenceI[] mset = new SequenceI[msflen];
219       for (int i=0,j=sequences.length,k=0; i<j;i++) {
220         if (ungapped[i])
221           mset[k++] = sequences[i];
222       }
223       ungapped = null;
224       return mset;
225   }
226 }