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
5 * This file is part of Jalview.
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.
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.
16 * You should have received a copy of the GNU General Public License along with Jalview. If not, see <http://www.gnu.org/licenses/>.
18 package jalview.analysis;
20 import jalview.datamodel.SequenceGroup;
21 import jalview.datamodel.SequenceI;
23 import java.util.Hashtable;
24 import java.util.List;
25 import java.util.Vector;
28 * various methods for defining groups on an alignment based on some other
37 * Divide the given sequences based on the equivalence of their corresponding
38 * selectedChars string. If exgroups is provided, existing groups will be
42 * @param selectedChars
46 public static SequenceGroup[] makeGroupsFrom(SequenceI[] sequences,
47 String[] selectedChars, List<SequenceGroup> list)
49 // TODO: determine how to get/recover input data for group generation
50 Hashtable gps = new Hashtable();
52 Hashtable pgroup = new Hashtable();
55 for (SequenceGroup sg : list)
57 for (SequenceI sq : sg.getSequences(null))
59 pgroup.put(sq.toString(), sg);
63 for (i = 0; i < sequences.length; i++)
65 String schar = selectedChars[i];
66 SequenceGroup pgp = (SequenceGroup) pgroup
67 .get(((Object) sequences[i]).toString());
70 schar = pgp.getName() + ":" + schar;
72 Vector svec = (Vector) gps.get(schar);
78 if (width < sequences[i].getLength())
80 width = sequences[i].getLength();
82 svec.addElement(sequences[i]);
85 java.util.Enumeration sge = gps.keys();
86 SequenceGroup[] groups = new SequenceGroup[gps.size()];
88 while (sge.hasMoreElements())
90 String key = (String) sge.nextElement();
91 SequenceGroup group = new SequenceGroup((Vector) gps.get(key),
92 "Subseq: " + key, null, true, true, false, 0, width - 1);
102 * subdivide the given sequences based on the distribution of features
104 * @param featureLabels
105 * - null or one or more feature types to filter on.
107 * - null or set of groups to filter features on
109 * - range for feature filter
111 * - range for feature filter
113 * - sequences to be divided
115 * - existing groups to be subdivided
117 * - density, description, score
119 public static void divideByFeature(String[] featureLabels,
120 String[] groupLabels, int start, int stop, SequenceI[] sequences,
121 Vector exgroups, String method)
123 // TODO implement divideByFeature
125 * if (method!=AlignmentSorter.FEATURE_SCORE &&
126 * method!=AlignmentSorter.FEATURE_LABEL &&
127 * method!=AlignmentSorter.FEATURE_DENSITY) { throw newError(
128 * "Implementation Error - sortByFeature method must be one of FEATURE_SCORE, FEATURE_LABEL or FEATURE_DENSITY."
129 * ); } boolean ignoreScore=method!=AlignmentSorter.FEATURE_SCORE;
130 * StringBuffer scoreLabel = new StringBuffer();
131 * scoreLabel.append(start+stop+method); // This doesn't work yet - we'd
132 * like to have a canonical ordering that can be preserved from call to call
133 * for (int i=0;featureLabels!=null && i<featureLabels.length; i++) {
134 * scoreLabel.append(featureLabels[i]==null ? "null" : featureLabels[i]); }
135 * for (int i=0;groupLabels!=null && i<groupLabels.length; i++) {
136 * scoreLabel.append(groupLabels[i]==null ? "null" : groupLabels[i]); }
137 * SequenceI[] seqs = alignment.getSequencesArray();
139 * boolean[] hasScore = new boolean[seqs.length]; // per sequence score //
140 * presence int hasScores = 0; // number of scores present on set double[]
141 * scores = new double[seqs.length]; int[] seqScores = new int[seqs.length];
142 * Object[] feats = new Object[seqs.length]; double min = 0, max = 0; for
143 * (int i = 0; i < seqs.length; i++) { SequenceFeature[] sf =
144 * seqs[i].getSequenceFeatures(); if (sf==null &&
145 * seqs[i].getDatasetSequence()!=null) { sf =
146 * seqs[i].getDatasetSequence().getSequenceFeatures(); } if (sf==null) { sf
147 * = new SequenceFeature[0]; } else { SequenceFeature[] tmp = new
148 * SequenceFeature[sf.length]; for (int s=0; s<tmp.length;s++) { tmp[s] =
149 * sf[s]; } sf = tmp; } int sstart = (start==-1) ? start :
150 * seqs[i].findPosition(start); int sstop = (stop==-1) ? stop :
151 * seqs[i].findPosition(stop); seqScores[i]=0; scores[i]=0.0; int
152 * n=sf.length; for (int f=0;f<sf.length;f++) { // filter for selection
153 * criteria if ( // ignore features outwith alignment start-stop positions.
154 * (sf[f].end < sstart || sf[f].begin > sstop) || // or ignore based on
155 * selection criteria (featureLabels != null &&
156 * !AlignmentSorter.containsIgnoreCase(sf[f].type, featureLabels)) ||
157 * (groupLabels != null // problem here: we cannot eliminate null feature
158 * group features && (sf[f].getFeatureGroup() != null &&
159 * !AlignmentSorter.containsIgnoreCase(sf[f].getFeatureGroup(),
160 * groupLabels)))) { // forget about this feature sf[f] = null; n--; } else
161 * { // or, also take a look at the scores if necessary. if (!ignoreScore &&
162 * sf[f].getScore()!=Float.NaN) { if (seqScores[i]==0) { hasScores++; }
163 * seqScores[i]++; hasScore[i] = true; scores[i] += sf[f].getScore(); //
164 * take the first instance of this // score. } } } SequenceFeature[] fs;
165 * feats[i] = fs = new SequenceFeature[n]; if (n>0) { n=0; for (int
166 * f=0;f<sf.length;f++) { if (sf[f]!=null) { ((SequenceFeature[])
167 * feats[i])[n++] = sf[f]; } } if (method==FEATURE_LABEL) { // order the
168 * labels by alphabet String[] labs = new String[fs.length]; for (int
169 * l=0;l<labs.length; l++) { labs[l] = (fs[l].getDescription()!=null ?
170 * fs[l].getDescription() : fs[l].getType()); }
171 * jalview.util.QuickSort.sort(labs, ((Object[]) feats[i])); } } if
172 * (hasScore[i]) { // compute average score scores[i]/=seqScores[i]; //
173 * update the score bounds. if (hasScores == 1) { max = min = scores[i]; }
174 * else { if (max < scores[i]) { max = scores[i]; } if (min > scores[i]) {
175 * min = scores[i]; } } } }
177 * if (method==FEATURE_SCORE) { if (hasScores == 0) { return; // do nothing
178 * - no scores present to sort by. } // pad score matrix if (hasScores <
179 * seqs.length) { for (int i = 0; i < seqs.length; i++) { if (!hasScore[i])
180 * { scores[i] = (max + i); } else { int nf=(feats[i]==null) ? 0
181 * :((SequenceFeature[]) feats[i]).length;
182 * System.err.println("Sorting on Score: seq "+seqs[i].getName()+
183 * " Feats: "+nf+" Score : "+scores[i]); } } }
185 * jalview.util.QuickSort.sort(scores, seqs); } else if
186 * (method==FEATURE_DENSITY) {
188 * // break ties between equivalent numbers for adjacent sequences by adding
189 * 1/Nseq*i on the original order double fr = 0.9/(1.0*seqs.length); for
190 * (int i=0;i<seqs.length; i++) { double nf; scores[i] =
191 * (0.05+fr*i)+(nf=((feats[i]==null) ? 0.0 :1.0*((SequenceFeature[])
192 * feats[i]).length));
193 * System.err.println("Sorting on Density: seq "+seqs[i].getName()+
194 * " Feats: "+nf+" Score : "+scores[i]); }
195 * jalview.util.QuickSort.sort(scores, seqs); } else { if
196 * (method==FEATURE_LABEL) { throw new Error("Not yet implemented."); } } if
197 * (lastSortByFeatureScore ==null ||
198 * scoreLabel.equals(lastSortByFeatureScore)) { setOrder(alignment, seqs); }
199 * else { setReverseOrder(alignment, seqs); } lastSortByFeatureScore =
200 * scoreLabel.toString();