X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fio%2FFeaturesFile.java;h=73783e5b408a0dac903dabe9d10d480626651a16;hb=37de9310bec3501cbc6381e0c3dcb282fcaad812;hp=2dd5f26275e0ed0d12a4c6b706ae9b2281181066;hpb=0b8abe58b934e03c34575b06d532a99f0ba70196;p=jalview.git diff --git a/src/jalview/io/FeaturesFile.java b/src/jalview/io/FeaturesFile.java index 2dd5f26..73783e5 100755 --- a/src/jalview/io/FeaturesFile.java +++ b/src/jalview/io/FeaturesFile.java @@ -23,6 +23,7 @@ package jalview.io; 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; @@ -33,15 +34,12 @@ import jalview.datamodel.SequenceI; 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; @@ -50,7 +48,6 @@ import java.util.Iterator; 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 @@ -140,8 +137,8 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI * - process html strings into plain text * @return true if features were added */ - public boolean parse(AlignmentI align, Map colours, - boolean removeHTML) + public boolean parse(AlignmentI align, + Map colours, boolean removeHTML) { return parse(align, colours, removeHTML, false); } @@ -177,8 +174,9 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI * - when true, ID matches to compound sequence IDs are allowed * @return true if features were added */ - public boolean parse(AlignmentI align, Map colours, - boolean removeHTML, boolean relaxedIdmatching) + public boolean parse(AlignmentI align, + Map colours, boolean removeHTML, + boolean relaxedIdmatching) { Map gffProps = new HashMap(); /* @@ -232,12 +230,18 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI 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; } @@ -297,7 +301,7 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI * @param featureGroup */ protected boolean parseJalviewFeature(String line, String[] gffColumns, - AlignmentI alignment, Map featureColours, + AlignmentI alignment, Map featureColours, boolean removeHTML, boolean relaxedIdMatching, String featureGroup) { /* @@ -350,7 +354,7 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI * 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); @@ -381,225 +385,6 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI } /** - * 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 colours) - { - Object 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 = ucs.findColour('A'); - } - if (colour != null) - { - colours.put(featureType, colour); - } - } - - /** - * Parse a Jalview graduated colour descriptor - * - * @param line - * @param colourDescriptor - * @return - */ - protected GraduatedColor 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"; - } - - GraduatedColor colour = null; - try - { - colour = new GraduatedColor( - 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; - if (gcol.hasMoreTokens()) - { - // threshold type and possibly a threshold value - ttype = gcol.nextToken(); - if (ttype.toLowerCase().startsWith("below")) - { - colour.setThreshType(AnnotationColourGradient.BELOW_THRESHOLD); - } - else if (ttype.toLowerCase().startsWith("above")) - { - colour.setThreshType(AnnotationColourGradient.ABOVE_THRESHOLD); - } - else - { - colour.setThreshType(AnnotationColourGradient.NO_THRESHOLD); - if (!ttype.toLowerCase().startsWith("no")) - { - System.err.println("Ignoring unrecognised threshold type : " - + ttype); - } - } - } - if (colour.getThreshType() != AnnotationColourGradient.NO_THRESHOLD) - { - try - { - gcol.nextToken(); - tval = gcol.nextToken(); - colour.setThresh(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() @@ -703,7 +488,7 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI * @return features file contents */ public String printJalviewFormat(SequenceI[] sequences, - Map visible) + Map visible) { return printJalviewFormat(sequences, visible, true, true); } @@ -723,7 +508,8 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI * @return features file contents */ public String printJalviewFormat(SequenceI[] sequences, - Map visible, boolean visOnly, boolean nonpos) + Map visible, boolean visOnly, + boolean nonpos) { StringBuilder out = new StringBuilder(256); boolean featuresGen = false; @@ -739,58 +525,14 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI // viewed features // TODO: decide if feature links should also be written here ? Iterator en = visible.keySet().iterator(); - String featureType, color; 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().toString(); + FeatureColourI colour = visible.get(featureType); + out.append(colour.toJalviewFormat(featureType)).append(newline); } } + // Work out which groups are both present and visible List groups = new ArrayList(); int groupIndex = 0; @@ -842,12 +584,13 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI 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))) + .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 @@ -855,47 +598,48 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI } 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("") == -1) + if (sequenceFeature.links != null + && sequenceFeature.getDescription().indexOf("") == -1) { out.append(""); } - 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("" + label + ""); + out.append(" " + label + + ""); } } - if (features[j].getDescription().indexOf("") == -1) + if (sequenceFeature.getDescription().indexOf("") == -1) { out.append(""); } @@ -905,15 +649,15 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI } 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); } @@ -1003,7 +747,7 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI * @return */ public String printGffFormat(SequenceI[] sequences, - Map visible) + Map visible) { return printGffFormat(sequences, visible, true, true); } @@ -1020,11 +764,12 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI * @return */ public String printGffFormat(SequenceI[] sequences, - Map visible, boolean outputVisibleOnly, + Map visible, 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)