X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fschemes%2FAnnotationColourGradient.java;h=c74fdbc62f83ce0dd089217dd817b08685d37483;hb=424648b2e57e45eaa21c006b44828d8fca418581;hp=20b08857c757ec16f291d6962d625118173f2762;hpb=4d2e0d36506302cc00677527725bcccbdf27d766;p=jalview.git diff --git a/src/jalview/schemes/AnnotationColourGradient.java b/src/jalview/schemes/AnnotationColourGradient.java index 20b0885..c74fdbc 100755 --- a/src/jalview/schemes/AnnotationColourGradient.java +++ b/src/jalview/schemes/AnnotationColourGradient.java @@ -1,186 +1,489 @@ -/* -* Jalview - A Sequence Alignment Editor and Viewer -* Copyright (C) 2006 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle -* -* This program is free software; you can redistribute it and/or -* modify it under the terms of the GNU General Public License -* as published by the Free Software Foundation; either version 2 -* of the License, or (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -*/ -package jalview.schemes; - -import java.awt.*; - -import jalview.datamodel.*; - -public class AnnotationColourGradient extends ResidueColourScheme -{ - public static int NO_THRESHOLD = -1; - public static int BELOW_THRESHOLD = 0; - public static int ABOVE_THRESHOLD = 1; - - AlignmentAnnotation annotation; - int aboveAnnotationThreshold = -1; - - GraphLine annotationThreshold; - - float r1, g1, b1, rr, gg, bb, dr, dg, db; - float range = 0; - - ColourSchemeI colourScheme; - - /** - * Creates a new AnnotationColourGradient object. - */ - public AnnotationColourGradient(AlignmentAnnotation annotation, - ColourSchemeI originalColour, - int aboveThreshold) - { - if(originalColour instanceof AnnotationColourGradient) - { - colourScheme = ((AnnotationColourGradient)originalColour).colourScheme; - } - else - colourScheme = originalColour; - - this.annotation = annotation; - - aboveAnnotationThreshold = aboveThreshold; - - if(aboveThreshold!=NO_THRESHOLD && annotation.threshold!=null) - annotationThreshold = annotation.threshold; - } - - /** - * Creates a new AnnotationColourGradient object. - */ - public AnnotationColourGradient(AlignmentAnnotation annotation, - Color minColour, Color maxColour, int aboveThreshold) - { - this.annotation = annotation; - - aboveAnnotationThreshold = aboveThreshold; - - if(aboveThreshold!=NO_THRESHOLD && annotation.threshold!=null) - annotationThreshold = annotation.threshold; - - r1 = minColour.getRed(); - g1 = minColour.getGreen(); - b1 = minColour.getBlue(); - - rr = maxColour.getRed() - r1; - gg = maxColour.getGreen() - g1; - bb = maxColour.getBlue() - b1; - - range = annotation.graphMax - annotation.graphMin; - - } - - - public String getAnnotation() - { - return annotation.label; - } - - public int getAboveThreshold() - { - return aboveAnnotationThreshold; - } - - public float getAnnotationThreshold() - { - if(annotationThreshold==null) - return 0; - else - return annotationThreshold.value; - } - - public ColourSchemeI getBaseColour() - { - return colourScheme; - } - - public Color getMinColour() - { - return new Color( (int) r1, (int) g1, (int) b1); - } - - public Color getMaxColour() - { - return new Color( (int) (r1 + rr), (int) (g1 + gg), (int) (b1 + bb)); - } - - /** - * DOCUMENT ME! - * - * @param n DOCUMENT ME! - * - * @return DOCUMENT ME! - */ - public Color findColour(char c) - { - return Color.red; - } - - /** - * DOCUMENT ME! - * - * @param n DOCUMENT ME! - * @param j DOCUMENT ME! - * - * @return DOCUMENT ME! - */ - public Color findColour(char c, int j) - { - Color currentColour = Color.white; - - if ((threshold == 0) || aboveThreshold(c, j)) - { - if( j=annotationThreshold.value) - || (annotationThreshold!=null && aboveAnnotationThreshold==BELOW_THRESHOLD && annotation.annotations[j].value<=annotationThreshold.value)) - { - if(colourScheme!=null) - { - currentColour = colourScheme.findColour(c, j); - } - else if(range!=0) - { - dr = rr * - ( (annotation.annotations[j].value - annotation.graphMin) / - range) - + r1; - dg = gg * - ( (annotation.annotations[j].value - annotation.graphMin) / - range) - + g1; - db = bb * - ( (annotation.annotations[j].value - annotation.graphMin) / - range) - + b1; - - currentColour = new Color( (int) dr, (int) dg, (int) db); - } - } - } - } - - if(conservationColouring) - currentColour = applyConservation(currentColour, j); - - return currentColour; - } -} +/* + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors + * + * This file is part of Jalview. + * + * Jalview is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * Jalview is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Jalview. If not, see . + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ +package jalview.schemes; + +import jalview.datamodel.AlignmentAnnotation; +import jalview.datamodel.AlignmentI; +import jalview.datamodel.AnnotatedCollectionI; +import jalview.datamodel.Annotation; +import jalview.datamodel.GraphLine; +import jalview.datamodel.SequenceCollectionI; +import jalview.datamodel.SequenceI; +import jalview.renderer.AnnotationRenderer; +import jalview.util.Comparison; + +import java.awt.Color; +import java.util.IdentityHashMap; +import java.util.Map; + +public class AnnotationColourGradient extends FollowerColourScheme +{ + public static final int NO_THRESHOLD = -1; + + public static final int BELOW_THRESHOLD = 0; + + public static final int ABOVE_THRESHOLD = 1; + + private final AlignmentAnnotation annotation; + + private final int aboveAnnotationThreshold; + + public boolean thresholdIsMinMax = false; + + private GraphLine annotationThreshold; + + private int redMin; + + private int greenMin; + + private int blueMin; + + private int redRange; + + private int greenRange; + + private int blueRange; + + private boolean predefinedColours = false; + + private boolean seqAssociated = false; + + /** + * false if the scheme was constructed without a minColour and maxColour used + * to decide if existing colours should be taken from annotation elements when + * they exist + */ + private boolean noGradient = false; + + private IdentityHashMap seqannot = null; + + @Override + public ColourSchemeI getInstance(AnnotatedCollectionI sg, + Map hiddenRepSequences) + { + AnnotationColourGradient acg = new AnnotationColourGradient(annotation, + getColourScheme(), aboveAnnotationThreshold); + acg.thresholdIsMinMax = thresholdIsMinMax; + acg.annotationThreshold = (annotationThreshold == null) ? null + : new GraphLine(annotationThreshold); + acg.redMin = redMin; + acg.greenMin = greenMin; + acg.blueMin = blueMin; + acg.redRange = redRange; + acg.greenRange = greenRange; + acg.blueRange = blueRange; + acg.predefinedColours = predefinedColours; + acg.seqAssociated = seqAssociated; + acg.noGradient = noGradient; + return acg; + } + + /** + * Creates a new AnnotationColourGradient object. + */ + public AnnotationColourGradient(AlignmentAnnotation annotation, + ColourSchemeI originalColour, int aboveThreshold) + { + if (originalColour instanceof AnnotationColourGradient) + { + setColourScheme(((AnnotationColourGradient) originalColour) + .getColourScheme()); + } + else + { + setColourScheme(originalColour); + } + + this.annotation = annotation; + + aboveAnnotationThreshold = aboveThreshold; + + if (aboveThreshold != NO_THRESHOLD && annotation.threshold != null) + { + annotationThreshold = annotation.threshold; + } + // clear values so we don't get weird black bands... + redMin = 254; + greenMin = 254; + blueMin = 254; + redRange = 0; + greenRange = 0; + blueRange = 0; + + noGradient = true; + checkLimits(); + } + + /** + * Creates a new AnnotationColourGradient object. + */ + public AnnotationColourGradient(AlignmentAnnotation annotation, + Color minColour, Color maxColour, int aboveThreshold) + { + this.annotation = annotation; + + aboveAnnotationThreshold = aboveThreshold; + + if (aboveThreshold != NO_THRESHOLD && annotation.threshold != null) + { + annotationThreshold = annotation.threshold; + } + + redMin = minColour.getRed(); + greenMin = minColour.getGreen(); + blueMin = minColour.getBlue(); + + redRange = maxColour.getRed() - redMin; + greenRange = maxColour.getGreen() - greenMin; + blueRange = maxColour.getBlue() - blueMin; + + noGradient = false; + checkLimits(); + } + + private void checkLimits() + { + aamax = annotation.graphMax; + aamin = annotation.graphMin; + if (annotation.isRNA()) + { + // reset colour palette + ColourSchemeProperty.resetRnaHelicesShading(); + ColourSchemeProperty.initRnaHelicesShading(1 + (int) aamax); + } + } + + @Override + public void alignmentChanged(AnnotatedCollectionI alignment, + Map hiddenReps) + { + super.alignmentChanged(alignment, hiddenReps); + + if (seqAssociated && annotation.getCalcId() != null) + { + if (seqannot != null) + { + seqannot.clear(); + } + else + { + seqannot = new IdentityHashMap<>(); + } + // resolve the context containing all the annotation for the sequence + AnnotatedCollectionI alcontext = alignment instanceof AlignmentI + ? alignment + : alignment.getContext(); + boolean f = true, rna = false; + for (AlignmentAnnotation alan : alcontext + .findAnnotation(annotation.getCalcId())) + { + if (alan.sequenceRef != null + && (alan.label != null && annotation != null + && alan.label.equals(annotation.label))) + { + if (!rna && alan.isRNA()) + { + rna = true; + } + seqannot.put(alan.sequenceRef, alan); + if (f || alan.graphMax > aamax) + { + aamax = alan.graphMax; + } + if (f || alan.graphMin < aamin) + { + aamin = alan.graphMin; + } + f = false; + } + } + if (rna) + { + ColourSchemeProperty.initRnaHelicesShading(1 + (int) aamax); + } + } + } + + float aamin = 0f, aamax = 0f; + + public AlignmentAnnotation getAnnotation() + { + return annotation; + } + + public int getAboveThreshold() + { + return aboveAnnotationThreshold; + } + + public float getAnnotationThreshold() + { + if (annotationThreshold == null) + { + return 0; + } + else + { + return annotationThreshold.value; + } + } + + public Color getMinColour() + { + return new Color(redMin, greenMin, blueMin); + } + + public Color getMaxColour() + { + return new Color(redMin + redRange, greenMin + greenRange, + blueMin + blueRange); + } + + /** + * DOCUMENT ME! + * + * @param n + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + @Override + public Color findColour(char c) + { + return Color.red; + } + + /** + * Returns the colour for a given character and position in a sequence + * + * @param c + * the residue character + * @param j + * the aligned position + * @param seq + * the sequence + * @return + */ + @Override + public Color findColour(char c, int j, SequenceI seq) + { + /* + * locate the annotation we are configured to colour by + */ + AlignmentAnnotation ann = (seqAssociated && seqannot != null + ? seqannot.get(seq) + : this.annotation); + + /* + * if gap or no annotation at position, no colour (White) + */ + if (ann == null || ann.annotations == null + || j >= ann.annotations.length || ann.annotations[j] == null + || Comparison.isGap(c)) + { + return Color.white; + } + + Annotation aj = ann.annotations[j]; + // 'use original colours' => colourScheme != null + // -> look up colour to be used + // predefined colours => preconfigured shading + // -> only use original colours reference if thresholding enabled & + // minmax exists + // annotation.hasIcons => null or black colours replaced with glyph + // colours + // -> reuse original colours if present + // -> if thresholding enabled then return colour on non-whitespace glyph + + /* + * if threshold applies, and annotation fails the test - no colour (white) + */ + if (annotationThreshold != null) + { + if ((aboveAnnotationThreshold == ABOVE_THRESHOLD + && aj.value < annotationThreshold.value) + || (aboveAnnotationThreshold == BELOW_THRESHOLD + && aj.value > annotationThreshold.value)) + { + return Color.white; + } + } + + /* + * If 'use original colours' then return the colour of the annotation + * at the aligned position - computed using the background colour scheme + */ + if (predefinedColours && aj.colour != null + && !aj.colour.equals(Color.black)) + { + return aj.colour; + } + + Color result = Color.white; + if (ann.hasIcons && ann.graph == AlignmentAnnotation.NO_GRAPH) + { + /* + * secondary structure symbol colouring + */ + if (aj.secondaryStructure > ' ' && aj.secondaryStructure != '.' + && aj.secondaryStructure != '-') + { + if (getColourScheme() != null) + { + result = getColourScheme().findColour(c, j, seq, null, 0f); + } + else + { + if (ann.isRNA()) + { + result = ColourSchemeProperty.rnaHelices[(int) aj.value]; + } + else + { + result = ann.annotations[j].secondaryStructure == 'H' + ? AnnotationRenderer.HELIX_COLOUR + : ann.annotations[j].secondaryStructure == 'E' + ? AnnotationRenderer.SHEET_COLOUR + : AnnotationRenderer.STEM_COLOUR; + } + } + } + else + { + return Color.white; + } + } + else if (noGradient) + { + if (getColourScheme() != null) + { + result = getColourScheme().findColour(c, j, seq, null, 0f); + } + else + { + if (aj.colour != null) + { + result = aj.colour; + } + } + } + else + { + result = shadeCalculation(ann, j); + } + + return result; + } + + /** + * Returns a graduated colour for the annotation at the given column. If there + * is a threshold value, and it is used as the top/bottom of the colour range, + * and the value satisfies the threshold condition, then a colour + * proportionate to the range from the threshold is calculated. For all other + * cases, a colour proportionate to the annotation's min-max range is + * calulated. Note that thresholding is _not_ done here (a colour is computed + * even if threshold is not passed). + * + * @param ann + * @param col + * @return + */ + Color shadeCalculation(AlignmentAnnotation ann, int col) + { + float range = 1f; + float value = ann.annotations[col].value; + if (thresholdIsMinMax && ann.threshold != null + && aboveAnnotationThreshold == ABOVE_THRESHOLD + && value >= ann.threshold.value) + { + range = ann.graphMax == ann.threshold.value ? 1f + : (value - ann.threshold.value) + / (ann.graphMax - ann.threshold.value); + } + else if (thresholdIsMinMax && ann.threshold != null + && aboveAnnotationThreshold == BELOW_THRESHOLD + && value <= ann.threshold.value) + { + range = ann.graphMin == ann.threshold.value ? 0f + : (value - ann.graphMin) + / (ann.threshold.value - ann.graphMin); + } + else + { + if (ann.graphMax != ann.graphMin) + { + range = (value - ann.graphMin) / (ann.graphMax - ann.graphMin); + } + else + { + range = 0f; + } + } + + int dr = (int) (redRange * range + redMin); + int dg = (int) (greenRange * range + greenMin); + int db = (int) (blueRange * range + blueMin); + + return new Color(dr, dg, db); + } + + public boolean isPredefinedColours() + { + return predefinedColours; + } + + public void setPredefinedColours(boolean predefinedColours) + { + this.predefinedColours = predefinedColours; + } + + public boolean isSeqAssociated() + { + return seqAssociated; + } + + public void setSeqAssociated(boolean sassoc) + { + seqAssociated = sassoc; + } + + public boolean isThresholdIsMinMax() + { + return thresholdIsMinMax; + } + + public void setThresholdIsMinMax(boolean minMax) + { + this.thresholdIsMinMax = minMax; + } + + @Override + public String getSchemeName() + { + return "Annotation"; + } + + @Override + public boolean isSimple() + { + return false; + } +}