import jalview.analysis.AlignmentUtils;
import jalview.analysis.SequenceIdMatcher;
import jalview.api.AlignViewportI;
+import jalview.api.FeatureColourI;
import jalview.api.FeaturesSourceI;
import jalview.datamodel.AlignedCodonFrame;
import jalview.datamodel.Alignment;
import jalview.io.gff.GffHelperBase;
import jalview.io.gff.GffHelperFactory;
import jalview.io.gff.GffHelperI;
-import jalview.schemes.AnnotationColourGradient;
-import jalview.schemes.GraduatedColor;
+import jalview.schemes.FeatureColour;
import jalview.schemes.UserColourScheme;
-import jalview.util.Format;
import jalview.util.MapList;
import jalview.util.ParseHtmlBodyAndLinks;
import jalview.util.StringUtils;
-import java.awt.Color;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
* - process html strings into plain text
* @return true if features were added
*/
- public boolean parse(AlignmentI align, Map<String, Object> colours,
+ public boolean parse(AlignmentI align,
+ Map<String, FeatureColourI> colours,
boolean removeHTML)
{
return parse(align, colours, removeHTML, false);
* - when true, ID matches to compound sequence IDs are allowed
* @return true if features were added
*/
- public boolean parse(AlignmentI align, Map<String, Object> colours,
+ public boolean parse(AlignmentI align,
+ Map<String, FeatureColourI> colours,
boolean removeHTML, boolean relaxedIdmatching)
{
Map<String, String> gffProps = new HashMap<String, String>();
else if (ft.equalsIgnoreCase("endgroup"))
{
// We should check whether this is the current group,
- // but at present theres no way of showing more than 1 group
+ // but at present there's no way of showing more than 1 group
featureGroup = null;
}
else
{
- parseFeatureColour(line, ft, gffColumns, colours);
+ String colscheme = gffColumns[1];
+ FeatureColourI colour = FeatureColour
+ .parseJalviewFeatureColour(colscheme);
+ if (colour != null)
+ {
+ colours.put(ft, colour);
+ }
}
continue;
}
* @param featureGroup
*/
protected boolean parseJalviewFeature(String line, String[] gffColumns,
- AlignmentI alignment, Map<String, Object> featureColours,
+ AlignmentI alignment, Map<String, FeatureColourI> featureColours,
boolean removeHTML, boolean relaxedIdMatching, String featureGroup)
{
/*
* synthesize a colour from the feature type
*/
UserColourScheme ucs = new UserColourScheme(ft);
- featureColours.put(ft, ucs.findColour('A'));
+ featureColours.put(ft, new FeatureColour(ucs.findColour('A')));
}
SequenceFeature sf = new SequenceFeature(ft, desc, "", startPos,
endPos, featureGroup);
* map to which to add derived colour specification
*/
protected void parseFeatureColour(String line, String featureType,
- String[] gffColumns, Map<String, Object> colours)
+ String[] gffColumns, Map<String, FeatureColourI> colours)
{
- Object colour = null;
+ FeatureColourI colour = null;
String colscheme = gffColumns[1];
if (colscheme.indexOf("|") > -1
|| colscheme.trim().equalsIgnoreCase("label"))
else
{
UserColourScheme ucs = new UserColourScheme(colscheme);
- colour = ucs.findColour('A');
+ colour = new FeatureColour(ucs.findColour('A'));
}
if (colour != null)
{
* @param colourDescriptor
* @return
*/
- protected GraduatedColor parseGraduatedColourScheme(String line,
+ protected FeatureColourI parseGraduatedColourScheme(String line,
String colourDescriptor)
{
// Parse '|' separated graduated colourscheme fields:
maxcol = "000000";
}
- GraduatedColor colour = null;
+ FeatureColourI colour = null;
try
{
- colour = new GraduatedColor(
+ colour = new FeatureColour(
new UserColourScheme(mincol).findColour('A'),
new UserColourScheme(maxcol).findColour('A'), min, max);
} catch (Exception e)
colour.setAutoScaled(abso == null);
// add in any additional parameters
String ttype = null, tval = null;
+ boolean hasThreshold = false;
if (gcol.hasMoreTokens())
{
// threshold type and possibly a threshold value
ttype = gcol.nextToken();
if (ttype.toLowerCase().startsWith("below"))
{
- colour.setThreshType(AnnotationColourGradient.BELOW_THRESHOLD);
+ colour.setBelowThreshold(true);
+ hasThreshold = true;
}
else if (ttype.toLowerCase().startsWith("above"))
{
- colour.setThreshType(AnnotationColourGradient.ABOVE_THRESHOLD);
+ colour.setAboveThreshold(true);
+ hasThreshold = true;
}
else
{
- colour.setThreshType(AnnotationColourGradient.NO_THRESHOLD);
if (!ttype.toLowerCase().startsWith("no"))
{
System.err.println("Ignoring unrecognised threshold type : "
}
}
}
- if (colour.getThreshType() != AnnotationColourGradient.NO_THRESHOLD)
+ if (hasThreshold)
{
try
{
gcol.nextToken();
tval = gcol.nextToken();
- colour.setThresh(new Float(tval).floatValue());
+ colour.setThreshold(new Float(tval).floatValue());
} catch (Exception e)
{
System.err.println("Couldn't parse threshold value as a float: ("
* @return features file contents
*/
public String printJalviewFormat(SequenceI[] sequences,
- Map<String, Object> visible)
+ Map<String, FeatureColourI> visible)
{
return printJalviewFormat(sequences, visible, true, true);
}
*
* @param sequences
* source of features
- * @param visible
+ * @param featureColours
* hash of Colours for each feature type
* @param visOnly
* when true only feature types in 'visible' will be output
* @return features file contents
*/
public String printJalviewFormat(SequenceI[] sequences,
- Map<String, Object> visible, boolean visOnly, boolean nonpos)
+ Map<String, FeatureColourI> featureColours, boolean visOnly,
+ boolean nonpos)
{
StringBuilder out = new StringBuilder(256);
boolean featuresGen = false;
- if (visOnly && !nonpos && (visible == null || visible.size() < 1))
+ if (visOnly && !nonpos
+ && (featureColours == null || featureColours.size() < 1))
{
// no point continuing.
return "No Features Visible";
}
- if (visible != null && visOnly)
+ if (featureColours != null && visOnly)
{
// write feature colours only if we're given them and we are generating
// viewed features
// TODO: decide if feature links should also be written here ?
- Iterator<String> en = visible.keySet().iterator();
- String featureType, color;
+ Iterator<String> en = featureColours.keySet().iterator();
while (en.hasNext())
{
- featureType = en.next().toString();
-
- if (visible.get(featureType) instanceof GraduatedColor)
- {
- GraduatedColor gc = (GraduatedColor) visible.get(featureType);
- color = (gc.isColourByLabel() ? "label|" : "")
- + Format.getHexString(gc.getMinColor()) + "|"
- + Format.getHexString(gc.getMaxColor())
- + (gc.isAutoScale() ? "|" : "|abso|") + gc.getMin() + "|"
- + gc.getMax() + "|";
- if (gc.getThreshType() != AnnotationColourGradient.NO_THRESHOLD)
- {
- if (gc.getThreshType() == AnnotationColourGradient.BELOW_THRESHOLD)
- {
- color += "below";
- }
- else
- {
- if (gc.getThreshType() != AnnotationColourGradient.ABOVE_THRESHOLD)
- {
- System.err.println("WARNING: Unsupported threshold type ("
- + gc.getThreshType() + ") : Assuming 'above'");
- }
- color += "above";
- }
- // add the value
- color += "|" + gc.getThresh();
- }
- else
- {
- color += "none";
- }
- }
- else if (visible.get(featureType) instanceof Color)
- {
- color = Format.getHexString((Color) visible.get(featureType));
- }
- else
- {
- // legacy support for integer objects containing colour triplet values
- color = Format.getHexString(new Color(Integer.parseInt(visible
- .get(featureType).toString())));
- }
- out.append(featureType);
- out.append(TAB);
- out.append(color);
- out.append(newline);
+ String featureType = en.next();
+ FeatureColourI colour = featureColours.get(featureType);
+ out.append(colour.toJalviewFormat(featureType)).append(newline);
}
}
+
// Work out which groups are both present and visible
List<String> groups = new ArrayList<String>();
int groupIndex = 0;
{
isnonpos = features[j].begin == 0 && features[j].end == 0;
if ((!nonpos && isnonpos)
- || (!isnonpos && visOnly && !visible
+ || (!isnonpos && visOnly && !featureColours
.containsKey(features[j].type)))
{
continue;
features = sequences[i].getSequenceFeatures();
if (features != null)
{
- for (int j = 0; j < features.length; j++)
+ for (SequenceFeature sequenceFeature : features)
{
- isnonpos = features[j].begin == 0 && features[j].end == 0;
+ isnonpos = sequenceFeature.begin == 0 && sequenceFeature.end == 0;
if ((!nonpos && isnonpos)
- || (!isnonpos && visOnly && !visible
- .containsKey(features[j].type)))
+ || (!isnonpos && visOnly && !featureColours
+ .containsKey(sequenceFeature.type)))
{
// skip if feature is nonpos and we ignore them or if we only
// output visible and it isn't non-pos and it's not visible
}
if (group != null
- && (features[j].featureGroup == null || !features[j].featureGroup
+ && (sequenceFeature.featureGroup == null || !sequenceFeature.featureGroup
.equals(group)))
{
continue;
}
- if (group == null && features[j].featureGroup != null)
+ if (group == null && sequenceFeature.featureGroup != null)
{
continue;
}
// we have features to output
featuresGen = true;
- if (features[j].description == null
- || features[j].description.equals(""))
+ if (sequenceFeature.description == null
+ || sequenceFeature.description.equals(""))
{
- out.append(features[j].type).append(TAB);
+ out.append(sequenceFeature.type).append(TAB);
}
else
{
- if (features[j].links != null
- && features[j].getDescription().indexOf("<html>") == -1)
+ if (sequenceFeature.links != null
+ && sequenceFeature.getDescription().indexOf("<html>") == -1)
{
out.append("<html>");
}
- out.append(features[j].description + " ");
- if (features[j].links != null)
+ out.append(sequenceFeature.description);
+ if (sequenceFeature.links != null)
{
- for (int l = 0; l < features[j].links.size(); l++)
+ for (int l = 0; l < sequenceFeature.links.size(); l++)
{
- String label = features[j].links.elementAt(l).toString();
+ String label = sequenceFeature.links.elementAt(l);
String href = label.substring(label.indexOf("|") + 1);
label = label.substring(0, label.indexOf("|"));
- if (features[j].description.indexOf(href) == -1)
+ if (sequenceFeature.description.indexOf(href) == -1)
{
- out.append("<a href=\"" + href + "\">" + label + "</a>");
+ out.append(" <a href=\"" + href + "\">" + label
+ + "</a>");
}
}
- if (features[j].getDescription().indexOf("</html>") == -1)
+ if (sequenceFeature.getDescription().indexOf("</html>") == -1)
{
out.append("</html>");
}
}
out.append(sequences[i].getName());
out.append("\t-1\t");
- out.append(features[j].begin);
+ out.append(sequenceFeature.begin);
out.append(TAB);
- out.append(features[j].end);
+ out.append(sequenceFeature.end);
out.append(TAB);
- out.append(features[j].type);
- if (!Float.isNaN(features[j].score))
+ out.append(sequenceFeature.type);
+ if (!Float.isNaN(sequenceFeature.score))
{
out.append(TAB);
- out.append(features[j].score);
+ out.append(sequenceFeature.score);
}
out.append(newline);
}
* @return
*/
public String printGffFormat(SequenceI[] sequences,
- Map<String, Object> visible)
+ Map<String, FeatureColourI> visible)
{
return printGffFormat(sequences, visible, true, true);
}
*
* @param sequences
* the sequences whose features are to be output
- * @param visible
+ * @param featureColours
* a map whose keys are the type names of visible features
* @param outputVisibleOnly
* @param includeNonPositionalFeatures
* @return
*/
public String printGffFormat(SequenceI[] sequences,
- Map<String, Object> visible, boolean outputVisibleOnly,
+ Map<String, FeatureColourI> featureColours,
+ boolean outputVisibleOnly,
boolean includeNonPositionalFeatures)
{
StringBuilder out = new StringBuilder(256);
- out.append(String.format("%s %d\n", GFF_VERSION, gffVersion));
+ int version = gffVersion == 0 ? 2 : gffVersion;
+ out.append(String.format("%s %d\n", GFF_VERSION, version));
String source;
boolean isnonpos;
for (SequenceI seq : sequences)
// TODO why the test !isnonpos here?
// what about not visible non-positional features?
if (!isnonpos && outputVisibleOnly
- && !visible.containsKey(sf.type))
+ && !featureColours.containsKey(sf.type))
{
/*
* ignore not visible features if not wanted