import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
+import java.util.StringTokenizer;
/**
* Parses and writes features files, which may be in Jalview, GFF2 or GFF3
}
/**
+ * Process a feature type colour specification
+ *
+ * @param line
+ * the current input line (for error messages only)
+ * @param featureType
+ * the first token on the line
+ * @param gffColumns
+ * holds tokens on the line
+ * @param colours
+ * map to which to add derived colour specification
+ */
+ protected void parseFeatureColour(String line, String featureType,
+ String[] gffColumns, Map<String, FeatureColourI> colours)
+ {
+ FeatureColourI colour = null;
+ String colscheme = gffColumns[1];
+ if (colscheme.indexOf("|") > -1
+ || colscheme.trim().equalsIgnoreCase("label"))
+ {
+ colour = parseGraduatedColourScheme(line, colscheme);
+ }
+ else
+ {
+ UserColourScheme ucs = new UserColourScheme(colscheme);
+ colour = new FeatureColour(ucs.findColour('A'));
+ }
+ if (colour != null)
+ {
+ colours.put(featureType, colour);
+ }
+ }
+
+ /**
+ * Parse a Jalview graduated colour descriptor
+ *
+ * @param line
+ * @param colourDescriptor
+ * @return
+ */
+ protected FeatureColourI parseGraduatedColourScheme(String line,
+ String colourDescriptor)
+ {
+ // Parse '|' separated graduated colourscheme fields:
+ // [label|][mincolour|maxcolour|[absolute|]minvalue|maxvalue|thresholdtype|thresholdvalue]
+ // can either provide 'label' only, first is optional, next two
+ // colors are required (but may be
+ // left blank), next is optional, nxt two min/max are required.
+ // first is either 'label'
+ // first/second and third are both hexadecimal or word equivalent
+ // colour.
+ // next two are values parsed as floats.
+ // fifth is either 'above','below', or 'none'.
+ // sixth is a float value and only required when fifth is either
+ // 'above' or 'below'.
+ StringTokenizer gcol = new StringTokenizer(colourDescriptor, "|", true);
+ // set defaults
+ float min = Float.MIN_VALUE, max = Float.MAX_VALUE;
+ boolean labelCol = false;
+ // Parse spec line
+ String mincol = gcol.nextToken();
+ if (mincol == "|")
+ {
+ System.err
+ .println("Expected either 'label' or a colour specification in the line: "
+ + line);
+ return null;
+ }
+ String maxcol = null;
+ if (mincol.toLowerCase().indexOf("label") == 0)
+ {
+ labelCol = true;
+ mincol = (gcol.hasMoreTokens() ? gcol.nextToken() : null); // skip '|'
+ mincol = (gcol.hasMoreTokens() ? gcol.nextToken() : null);
+ }
+ String abso = null, minval, maxval;
+ if (mincol != null)
+ {
+ // at least four more tokens
+ if (mincol.equals("|"))
+ {
+ mincol = "";
+ }
+ else
+ {
+ gcol.nextToken(); // skip next '|'
+ }
+ // continue parsing rest of line
+ maxcol = gcol.nextToken();
+ if (maxcol.equals("|"))
+ {
+ maxcol = "";
+ }
+ else
+ {
+ gcol.nextToken(); // skip next '|'
+ }
+ abso = gcol.nextToken();
+ gcol.nextToken(); // skip next '|'
+ if (abso.toLowerCase().indexOf("abso") != 0)
+ {
+ minval = abso;
+ abso = null;
+ }
+ else
+ {
+ minval = gcol.nextToken();
+ gcol.nextToken(); // skip next '|'
+ }
+ maxval = gcol.nextToken();
+ if (gcol.hasMoreTokens())
+ {
+ gcol.nextToken(); // skip next '|'
+ }
+ try
+ {
+ if (minval.length() > 0)
+ {
+ min = Float.valueOf(minval);
+ }
+ } catch (Exception e)
+ {
+ System.err
+ .println("Couldn't parse the minimum value for graduated colour for type ("
+ + colourDescriptor
+ + ") - did you misspell 'auto' for the optional automatic colour switch ?");
+ e.printStackTrace();
+ }
+ try
+ {
+ if (maxval.length() > 0)
+ {
+ max = Float.valueOf(maxval);
+ }
+ } catch (Exception e)
+ {
+ System.err
+ .println("Couldn't parse the maximum value for graduated colour for type ("
+ + colourDescriptor + ")");
+ e.printStackTrace();
+ }
+ }
+ else
+ {
+ // add in some dummy min/max colours for the label-only
+ // colourscheme.
+ mincol = "FFFFFF";
+ maxcol = "000000";
+ }
+
+ FeatureColourI colour = null;
+ try
+ {
+ colour = new FeatureColour(
+ new UserColourScheme(mincol).findColour('A'),
+ new UserColourScheme(maxcol).findColour('A'), min, max);
+ } catch (Exception e)
+ {
+ System.err.println("Couldn't parse the graduated colour scheme ("
+ + colourDescriptor + ")");
+ e.printStackTrace();
+ }
+ if (colour != null)
+ {
+ colour.setColourByLabel(labelCol);
+ 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.setBelowThreshold(true);
+ hasThreshold = true;
+ }
+ else if (ttype.toLowerCase().startsWith("above"))
+ {
+ colour.setAboveThreshold(true);
+ hasThreshold = true;
+ }
+ else
+ {
+ if (!ttype.toLowerCase().startsWith("no"))
+ {
+ System.err.println("Ignoring unrecognised threshold type : "
+ + ttype);
+ }
+ }
+ }
+ if (hasThreshold)
+ {
+ try
+ {
+ gcol.nextToken();
+ tval = gcol.nextToken();
+ colour.setThreshold(new Float(tval).floatValue());
+ } catch (Exception e)
+ {
+ System.err.println("Couldn't parse threshold value as a float: ("
+ + tval + ")");
+ e.printStackTrace();
+ }
+ }
+ // parse the thresh-is-min token ?
+ if (gcol.hasMoreTokens())
+ {
+ System.err
+ .println("Ignoring additional tokens in parameters in graduated colour specification\n");
+ while (gcol.hasMoreTokens())
+ {
+ System.err.println("|" + gcol.nextToken());
+ }
+ System.err.println("\n");
+ }
+ }
+ return colour;
+ }
+
+ /**
* clear any temporary handles used to speed up ID matching
*/
protected void resetMatcher()
*
* @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, FeatureColourI> visible, boolean visOnly,
+ 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();
+ Iterator<String> en = featureColours.keySet().iterator();
while (en.hasNext())
{
- String featureType = en.next().toString();
- FeatureColourI colour = visible.get(featureType);
+ String featureType = en.next();
+ FeatureColourI colour = featureColours.get(featureType);
out.append(colour.toJalviewFormat(featureType)).append(newline);
}
}
{
isnonpos = features[j].begin == 0 && features[j].end == 0;
if ((!nonpos && isnonpos)
- || (!isnonpos && visOnly && !visible
+ || (!isnonpos && visOnly && !featureColours
.containsKey(features[j].type)))
{
continue;
{
isnonpos = sequenceFeature.begin == 0 && sequenceFeature.end == 0;
if ((!nonpos && isnonpos)
- || (!isnonpos && visOnly && !visible
+ || (!isnonpos && visOnly && !featureColours
.containsKey(sequenceFeature.type)))
{
// skip if feature is nonpos and we ignore them or if we only
*
* @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, FeatureColourI> visible, boolean outputVisibleOnly,
+ Map<String, FeatureColourI> featureColours,
+ boolean outputVisibleOnly,
boolean includeNonPositionalFeatures)
{
StringBuilder out = new StringBuilder(256);
// 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