package jalview.schemes;
import jalview.datamodel.AnnotatedCollectionI;
import jalview.datamodel.HiddenMarkovModel;
import jalview.datamodel.SequenceCollectionI;
import jalview.datamodel.SequenceI;
import jalview.util.ColorUtils;
import jalview.util.Comparison;
import java.awt.Color;
import java.util.List;
import java.util.Map;
/**
* A colour scheme based on a selected Hidden Markov Model. The colour is
*
* - white for a gap
* - red for an insertion
* - orange for negative information content
* - white to blue for increasing information content
*
* where information content is the log ratio
*
*
* log(profile match emission probability / residue background probability>
*
*
* using global ('Uniprot') background frequencies for residues.
*
* @author tzvanaalten
*
*/
public class HMMERColourScheme extends ResidueColourScheme
{
/*
* The highest possible log ratio is when match emission probability in
* the HMM model is 1, and background (for W) is 0.0109 giving
* log(1/0.0109) = log(91.743) = 4.519
*/
private static final float MAX_LOG_RATIO = 4.519f;
private static final Color REDDISH = new Color(230, 0, 0);
HiddenMarkovModel hmm;
/**
* Constructor given a Hidden Markov Model
*
* @param markov
*/
public HMMERColourScheme(HiddenMarkovModel markov)
{
hmm = markov;
}
/**
* Default constructor (required by ColourSchemes.loadColourSchemes)
*/
public HMMERColourScheme()
{
}
@Override
public Color findColour(char symbol, int position, SequenceI seq,
String consensusResidue, float pid)
{
return findColour(symbol, position);
}
/**
* Returns the colour at a particular symbol at a column in the alignment:
*
* - white for a gap
* - red for an insertion
* - orange for negative information content
* - white to blue for increasing information content
*
*
* @param symbol
* @param column
* @return
*/
private Color findColour(char symbol, int column)
{
if (hmm == null || Comparison.isGap(symbol))
{
return Color.white;
}
if (Character.isLowerCase(symbol))
{
symbol = Character.toUpperCase(symbol);
}
double prob = hmm.getMatchEmissionProbability(column, symbol);
Float freq = 0f;
String alpha = hmm.getAlphabetType();
if (!ResidueProperties.backgroundFrequencies.get(alpha)
.containsKey(symbol))
{
return Color.WHITE;
}
else
{
freq = ResidueProperties.backgroundFrequencies.get(alpha).get(symbol);
}
if (prob == 0D)
{
return REDDISH;
}
double value = Math.log(prob / freq.floatValue());
Color colour = null;
if (value > 0)
{
colour = ColorUtils.getGraduatedColour((float) value, 0,
Color.WHITE, MAX_LOG_RATIO, Color.blue);
}
else if (value < 0)
{
return Color.ORANGE;
}
return colour;
}
@Override
public void alignmentChanged(AnnotatedCollectionI collection,
Map hiddenReps)
{
/*
* ? no need to do anything if alignment is adjusted
* since findColour() handles everything
*/
}
/**
* Answers a new colour scheme instance based on the HMM of the first sequence
* in sg that has an HMM
*/
@Override
public ColourSchemeI getInstance(AnnotatedCollectionI sg,
Map hiddenRepSequences)
{
HiddenMarkovModel model = null;
List seqs = sg.getHMMConsensusSequences();
if (!seqs.isEmpty())
{
model = seqs.get(0).getHMM();
}
HMMERColourScheme colour = new HMMERColourScheme(model);
return colour;
}
@Override
public String getSchemeName()
{
return JalviewColourScheme.HMMERU.toString();
}
@Override
public boolean isSimple()
{
return false;
}
@Override
public boolean isApplicableTo(AnnotatedCollectionI ac)
{
return !ac.getHMMConsensusSequences().isEmpty();
}
}