package jalview.schemes; import jalview.api.AlignViewportI; import jalview.datamodel.AnnotatedCollectionI; import jalview.datamodel.HiddenMarkovModel; import jalview.datamodel.SequenceI; import jalview.util.ColorUtils; import jalview.util.Comparison; import java.awt.Color; import java.util.List; import java.util.Map; /** * Base class for colour schemes based on a selected Hidden Markov Model. The * colour is with reference to an HMM consensus sequence and HMM profile * * where information content is the log ratio * *
 *   log(profile match emission probability / residue background probability)
 * 
* * Sub-class implementations use either global ('Uniprot') or local * ('alignment') background frequencies. * * @author tzvanaalten * @author gmcarstairs */ public abstract class HmmerColourScheme extends ResidueColourScheme { private static final Color INSERTION_COLOUR = new Color(230, 0, 0); // reddish /* * the aligned HMM consensus sequence to use as reference for colouring */ private SequenceI hmmSeq; private HiddenMarkovModel hmm; private Map frequencies; /** * Constructor given a list of Hidden Markov Model consensus sequences. The * first sequence provides the HMM profile from which we can read the emission * probabilities that determine the colour. * * @param hmmSeqs */ public HmmerColourScheme(List hmmSeqs) { hmmSeq = hmmSeqs.isEmpty() ? null : hmmSeqs.get(0); hmm = hmmSeq == null ? null : hmmSeq.getHMM(); } /** * Default constructor (required by ColourSchemes.loadColourSchemes) */ public HmmerColourScheme() { } @Override public Color findColour(char symbol, int column, SequenceI seq, String consensusResidue, float pid) { return findColour(symbol, column); } /** * Returns the colour at a particular symbol at a column in the alignment: * * * @param symbol * @param column * @return */ private Color findColour(char symbol, int column) { if (getHmm() == null || Comparison.isGap(symbol)) { return Color.white; } if (Comparison.isGap(hmmSeq.getCharAt(column))) { return INSERTION_COLOUR; } if (Character.isLowerCase(symbol)) { symbol = Character.toUpperCase(symbol); } final double prob = getHmm().getMatchEmissionProbability(column, symbol); Float freq = 0f; if (!frequencies.containsKey(symbol)) { return Color.WHITE; } else { freq = frequencies.get(symbol); } /* * Orange if match emission probability is less than background probability */ double infoRatio = prob / freq.floatValue(); Color colour = Color.ORANGE; if (infoRatio >= 1) { /* * log-scale graduated shade of blue if prob is greater than background */ float infoLog = (float) Math.log(infoRatio); colour = ColorUtils.getGraduatedColour(infoLog, 0, Color.WHITE, getMaxInformationScore(), Color.blue); } return colour; } /** * Answers the maximum possible value of information score (log ratio), for * use in scaling a graduated colour range * * @return */ abstract float getMaxInformationScore(); /** * Answers a new colour scheme instance based on the HMM of the first sequence * in ac that has an HMM */ @Override public ColourSchemeI getInstance(AlignViewportI viewport, AnnotatedCollectionI ac) { return newInstance(ac); } /** * Answers a new instance of the colour scheme for the given HMM * * @param ac * @return */ protected abstract HmmerColourScheme newInstance(AnnotatedCollectionI ac); @Override public boolean isSimple() { return false; } /** * Answers true if the sequence collection has an HMM consensus sequence, else * false */ @Override public boolean isApplicableTo(AnnotatedCollectionI ac) { return !ac.getHmmSequences().isEmpty(); } protected Map getFrequencies() { return frequencies; } protected void setFrequencies(Map frequencies) { this.frequencies = frequencies; } protected HiddenMarkovModel getHmm() { return hmm; } protected SequenceI getHmmSequence() { return hmmSeq; } }