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 featureTypes
* a list of feature types to include (or null for all)
* @param groups
* a list of feature groups to include (or null for all)
* @param startCol
* start column position to include (base zero)
* @param endCol
* 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 featureTypes,
List groups, final int startCol, final int endCol,
AlignmentI alignment, String method)
{
if (method != FEATURE_SCORE && method != FEATURE_LABEL
&& method != FEATURE_DENSITY)
{
String msg = String
.format("Implementation Error - sortByFeature method must be either '%s' or '%s'",
FEATURE_SCORE, FEATURE_DENSITY);
System.err.println(msg);
return;
}
flipFeatureSortIfUnchanged(method, featureTypes, groups, startCol, endCol);
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 = 0d;
double max = 0d;
for (int i = 0; i < seqs.length; i++)
{
/*
* get sequence residues overlapping column region
* and features for residue positions and specified types
*/
String[] types = featureTypes == null ? null : featureTypes
.toArray(new String[featureTypes.size()]);
List sfs = seqs[i].findFeatures(startCol + 1,
endCol + 1, types);
seqScores[i] = 0;
scores[i] = 0.0;
Iterator it = sfs.listIterator();
while (it.hasNext())
{
SequenceFeature sf = it.next();
/*
* accept all features with null or empty group, otherwise
* check group is one of the currently visible groups
*/
String featureGroup = sf.getFeatureGroup();
if (groups != null && featureGroup != null
&& !"".equals(featureGroup)
&& !groups.contains(featureGroup))
{
it.remove();
}
else
{
float score = sf.getScore();
if (FEATURE_SCORE.equals(method) && !Float.isNaN(score))
{
if (seqScores[i] == 0)
{
hasScores++;
}
seqScores[i]++;
hasScore[i] = true;
scores[i] += score;
// take the first instance of this score // ??
}
}
}
feats[i] = sfs.toArray(new SequenceFeature[sfs.size()]);
if (!sfs.isEmpty())
{
if (method == FEATURE_LABEL)
{
// order the labels by alphabet (not yet implemented)
String[] labs = new String[sfs.size()];
for (int l = 0; l < sfs.size(); l++)
{
SequenceFeature sf = sfs.get(l);
String description = sf.getDescription();
labs[l] = (description != null ? description : sf.getType());
}
QuickSort.sort(labs, feats[i]);
}
}
if (hasScore[i])
{
// compute average score
scores[i] /= seqScores[i];
// update the score bounds.
if (hasScores == 1)
{
min = scores[i];
max = min;
}
else
{
max = Math.max(max, scores[i]);
min = Math.min(min, scores[i]);
}
}
}
if (FEATURE_SCORE.equals(method))
{
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, sortByFeatureAscending);
}
else if (FEATURE_DENSITY.equals(method))
{
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, sortByFeatureAscending);
}
setOrder(alignment, seqs);
}
/**
* Builds a string hash of criteria for sorting, and if unchanged from last
* time, reverse the sort order
*
* @param method
* @param featureTypes
* @param groups
* @param startCol
* @param endCol
*/
protected static void flipFeatureSortIfUnchanged(String method,
List featureTypes, List groups,
final int startCol, final int endCol)
{
StringBuilder sb = new StringBuilder(64);
sb.append(startCol).append(method).append(endCol);
if (featureTypes != null)
{
Collections.sort(featureTypes);
sb.append(featureTypes.toString());
}
if (groups != null)
{
Collections.sort(groups);
sb.append(groups.toString());
}
String scoreCriteria = sb.toString();
/*
* if resorting on the same criteria, toggle sort order
*/
if (sortByFeatureCriteria == null
|| !scoreCriteria.equals(sortByFeatureCriteria))
{
sortByFeatureAscending = true;
}
else
{
sortByFeatureAscending = !sortByFeatureAscending;
}
sortByFeatureCriteria = scoreCriteria;
}
}