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
*
* - white for a gap
* - red for an insertion (position is gapped in the HMM consensus)
* - 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)
*
*
* 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:
*
* - 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 (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;
}
}