/* * 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.analysis.Conservation; import jalview.datamodel.AnnotatedCollectionI; import jalview.datamodel.ProfileI; import jalview.datamodel.ProfilesI; import jalview.datamodel.SequenceCollectionI; import jalview.datamodel.SequenceI; import jalview.util.ColorUtils; import jalview.util.Comparison; import jalview.util.MessageManager; import java.awt.Color; import java.util.Map; /** * DOCUMENT ME! * * @author $author$ * @version $Revision$ */ public class ResidueColourScheme implements ColourSchemeI { final int[] symbolIndex; boolean conservationColouring = false; Color[] colors = null; int threshold = 0; /* Set when threshold colouring to either pid_gaps or pid_nogaps */ protected boolean ignoreGaps = false; /* * Consensus data indexed by column */ ProfilesI consensus; /* * Conservation string as a char array */ char[] conservation; /* * The conservation slider percentage setting */ int inc = 30; /** * Creates a new ResidueColourScheme object. * * @param final int[] index table into colors (ResidueProperties.naIndex or * ResidueProperties.aaIndex) * @param colors * colours for symbols in sequences * @param threshold * threshold for conservation shading */ public ResidueColourScheme(int[] aaOrnaIndex, Color[] colours, int threshold) { symbolIndex = aaOrnaIndex; this.colors = colours; this.threshold = threshold; } /** * Creates a new ResidueColourScheme object with a lookup table for indexing * the colour map */ public ResidueColourScheme(int[] aaOrNaIndex) { symbolIndex = aaOrNaIndex; } /** * Creates a new ResidueColourScheme object - default constructor for * non-sequence dependent colourschemes */ public ResidueColourScheme() { symbolIndex = null; } /** * Find a colour without an index in a sequence */ @Override public Color findColour(char c) { return colors == null ? Color.white : colors[symbolIndex[c]]; } @Override public Color findColour(char c, int j, SequenceI seq) { Color currentColour; if (colors != null && symbolIndex != null && (threshold == 0) || aboveThreshold(c, j)) { currentColour = colors[symbolIndex[c]]; } else { currentColour = Color.white; } if (conservationColouring) { currentColour = applyConservation(currentColour, j); } return currentColour; } /** * Get the percentage threshold for this colour scheme * * @return Returns the percentage threshold */ @Override public int getThreshold() { return threshold; } /** * Sets the percentage consensus threshold value, and whether gaps are ignored * in percentage identity calculation * * @param consensusThreshold * @param ignoreGaps */ @Override public void setThreshold(int consensusThreshold, boolean ignoreGaps) { threshold = consensusThreshold; this.ignoreGaps = ignoreGaps; } /** * Answers true if there is a consensus profile for the specified column, and * the given residue matches the consensus (or joint consensus) residue for * the column, and the percentage identity for the profile is equal to or * greater than the current threshold; else answers false. The percentage * calculation depends on whether or not we are ignoring gapped sequences. * * @param residue * @param column * (index into consensus profiles) * * @return * @see #setThreshold(int, boolean) */ public boolean aboveThreshold(char residue, int column) { if ('a' <= residue && residue <= 'z') { // TO UPPERCASE !!! // Faster than toUpperCase residue -= ('a' - 'A'); } if (consensus == null) { return false; } ProfileI profile = consensus.get(column); /* * test whether this is the consensus (or joint consensus) residue */ if (profile != null && profile.getModalResidue().contains(String.valueOf(residue))) { if (profile.getPercentageIdentity(ignoreGaps) >= threshold) { return true; } } return false; } @Override public boolean conservationApplied() { return conservationColouring; } @Override public void setConservationApplied(boolean conservationApplied) { conservationColouring = conservationApplied; } @Override public void setConservationInc(int i) { inc = i; } @Override public int getConservationInc() { return inc; } /** * DOCUMENT ME! * * @param consensus * DOCUMENT ME! */ @Override public void setConsensus(ProfilesI consensus) { if (consensus == null) { return; } this.consensus = consensus; } @Override public void setConservation(Conservation cons) { if (cons == null) { conservationColouring = false; conservation = null; } else { conservationColouring = true; int iSize = cons.getConsSequence().getLength(); conservation = new char[iSize]; for (int i = 0; i < iSize; i++) { conservation[i] = cons.getConsSequence().getCharAt(i); } } } /** * Applies a combination of column conservation score, and conservation * percentage slider, to 'bleach' out the residue colours towards white. *

* If a column is fully conserved (identical residues, conservation score 11, * shown as *), or all 10 physico-chemical properties are conserved * (conservation score 10, shown as +), then the colour is left unchanged. *

* Otherwise a 'bleaching' factor is computed and applied to the colour. This * is designed to fade colours for scores of 0-9 completely to white at slider * positions ranging from 18% - 100% respectively. * * @param currentColour * @param column * * @return bleached (or unmodified) colour */ Color applyConservation(Color currentColour, int column) { if (conservation == null || conservation.length <= column) { return currentColour; } char conservationScore = conservation[column]; /* * if residues are fully conserved (* or 11), or all properties * are conserved (+ or 10), leave colour unchanged */ if (conservationScore == '*' || conservationScore == '+' || conservationScore == (char) 10 || conservationScore == (char) 11) { return currentColour; } if (Comparison.isGap(conservationScore)) { return Color.white; } /* * convert score 0-9 to a bleaching factor 1.1 - 0.2 */ float bleachFactor = (11 - (conservationScore - '0')) / 10f; /* * scale this up by 0-5 (percentage slider / 20) * as a result, scores of: 0 1 2 3 4 5 6 7 8 9 * fade to white at slider value: 18 20 22 25 29 33 40 50 67 100% */ bleachFactor *= (inc / 20f); return ColorUtils.bleachColour(currentColour, bleachFactor); } @Override public void alignmentChanged(AnnotatedCollectionI alignment, Map hiddenReps) { } @Override public ColourSchemeI applyTo(AnnotatedCollectionI sg, Map hiddenRepSequences) { try { return getClass().newInstance(); } catch (Exception q) { throw new Error(MessageManager.formatMessage( "error.implementation_error_cannot_duplicate_colour_scheme", new String[] { getClass().getName() }), q); } } }