labs)
{
if (labs == null)
{
return true;
}
if (lab == null)
{
return false;
}
for (String label : labs)
{
if (lab.equalsIgnoreCase(label))
{
return true;
}
}
return false;
}
/**
* Sort sequences by feature score or density, optionally restricted by
* feature types, feature groups, or alignment start/end positions.
*
* If the sort is repeated for the same combination of types and groups, sort
* order is reversed.
*
* @param featureLabels
* a list of feature types to include (or null for all)
* @param groupLabels
* a list of feature groups to include (or null for all)
* @param start
* start column position to include (base zero)
* @param stop
* end column position to include (base zero)
* @param alignment
* the alignment to be sorted
* @param method
* either "average_score" or "density" ("text" not yet implemented)
*/
public static void sortByFeature(List featureLabels,
List groupLabels, int start, int stop,
AlignmentI alignment, String method)
{
if (method != FEATURE_SCORE && method != FEATURE_LABEL
&& method != FEATURE_DENSITY)
{
throw new Error(
MessageManager
.getString("error.implementation_error_sortbyfeature"));
}
boolean ignoreScore = method != FEATURE_SCORE;
StringBuffer scoreLabel = new StringBuffer();
scoreLabel.append(start + stop + method);
// This doesn't quite work yet - we'd like to have a canonical ordering that
// can be preserved from call to call
if (featureLabels != null)
{
for (String label : featureLabels)
{
scoreLabel.append(label);
}
}
if (groupLabels != null)
{
for (String label : groupLabels)
{
scoreLabel.append(label);
}
}
/*
* if resorting the same feature, toggle sort order
*/
if (lastSortByFeatureScore == null
|| !scoreLabel.toString().equals(lastSortByFeatureScore))
{
sortByFeatureScoreAscending = true;
}
else
{
sortByFeatureScoreAscending = !sortByFeatureScoreAscending;
}
lastSortByFeatureScore = scoreLabel.toString();
SequenceI[] seqs = alignment.getSequencesArray();
boolean[] hasScore = new boolean[seqs.length]; // per sequence score
// presence
int hasScores = 0; // number of scores present on set
double[] scores = new double[seqs.length];
int[] seqScores = new int[seqs.length];
Object[] feats = new Object[seqs.length];
double min = 0, max = 0;
for (int i = 0; i < seqs.length; i++)
{
SequenceFeature[] sf = seqs[i].getSequenceFeatures();
if (sf == null)
{
sf = new SequenceFeature[0];
}
else
{
SequenceFeature[] tmp = new SequenceFeature[sf.length];
for (int s = 0; s < tmp.length; s++)
{
tmp[s] = sf[s];
}
sf = tmp;
}
int sstart = (start == -1) ? start : seqs[i].findPosition(start);
int sstop = (stop == -1) ? stop : seqs[i].findPosition(stop);
seqScores[i] = 0;
scores[i] = 0.0;
int n = sf.length;
for (int f = 0; f < sf.length; f++)
{
// filter for selection criteria
if (
// ignore features outwith alignment start-stop positions.
(sf[f].end < sstart || sf[f].begin > sstop) ||
// or ignore based on selection criteria
(featureLabels != null && !AlignmentSorter
.containsIgnoreCase(sf[f].type, featureLabels))
|| (groupLabels != null
// problem here: we cannot eliminate null feature group features
&& (sf[f].getFeatureGroup() != null && !AlignmentSorter
.containsIgnoreCase(sf[f].getFeatureGroup(),
groupLabels))))
{
// forget about this feature
sf[f] = null;
n--;
}
else
{
// or, also take a look at the scores if necessary.
if (!ignoreScore && !Float.isNaN(sf[f].getScore()))
{
if (seqScores[i] == 0)
{
hasScores++;
}
seqScores[i]++;
hasScore[i] = true;
scores[i] += sf[f].getScore(); // take the first instance of this
// score.
}
}
}
SequenceFeature[] fs;
feats[i] = fs = new SequenceFeature[n];
if (n > 0)
{
n = 0;
for (int f = 0; f < sf.length; f++)
{
if (sf[f] != null)
{
((SequenceFeature[]) feats[i])[n++] = sf[f];
}
}
if (method == FEATURE_LABEL)
{
// order the labels by alphabet
String[] labs = new String[fs.length];
for (int l = 0; l < labs.length; l++)
{
labs[l] = (fs[l].getDescription() != null ? fs[l]
.getDescription() : fs[l].getType());
}
QuickSort.sort(labs, ((Object[]) feats[i]));
}
}
if (hasScore[i])
{
// compute average score
scores[i] /= seqScores[i];
// update the score bounds.
if (hasScores == 1)
{
max = min = scores[i];
}
else
{
if (max < scores[i])
{
max = scores[i];
}
if (min > scores[i])
{
min = scores[i];
}
}
}
}
if (method == FEATURE_SCORE)
{
if (hasScores == 0)
{
return; // do nothing - no scores present to sort by.
}
// pad score matrix
if (hasScores < seqs.length)
{
for (int i = 0; i < seqs.length; i++)
{
if (!hasScore[i])
{
scores[i] = (max + 1 + i);
}
else
{
// int nf = (feats[i] == null) ? 0
// : ((SequenceFeature[]) feats[i]).length;
// // System.err.println("Sorting on Score: seq " +
// seqs[i].getName()
// + " Feats: " + nf + " Score : " + scores[i]);
}
}
}
QuickSort.sortByDouble(scores, seqs, sortByFeatureScoreAscending);
}
else if (method == FEATURE_DENSITY)
{
for (int i = 0; i < seqs.length; i++)
{
int featureCount = feats[i] == null ? 0
: ((SequenceFeature[]) feats[i]).length;
scores[i] = featureCount;
// System.err.println("Sorting on Density: seq "+seqs[i].getName()+
// " Feats: "+featureCount+" Score : "+scores[i]);
}
QuickSort.sortByDouble(scores, seqs, sortByFeatureScoreAscending);
}
else
{
if (method == FEATURE_LABEL)
{
throw new Error(
MessageManager.getString("error.not_yet_implemented"));
}
}
setOrder(alignment, seqs);
}
}