package jalview.schemes;
import jalview.datamodel.AnnotatedCollectionI;
import jalview.datamodel.HiddenMarkovModel;
import jalview.datamodel.ResidueCount;
import jalview.datamodel.SequenceCollectionI;
import jalview.datamodel.SequenceI;
import jalview.util.ColorUtils;
import jalview.util.Comparison;
import java.awt.Color;
import java.util.HashMap;
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 the alignment's background frequencies for residues.
*
* @author tzvanaalten
*
*/
public class HMMERAlignmentColourScheme extends ResidueColourScheme
{
/*
* the ratio, for each symbol, of its frequency to total symbol count
*/
Map frequency = new HashMap<>();
float logTotalCount;
HiddenMarkovModel hmm;
/**
* Constructor given a Hidden Markov Model
*
* @param sg
*
* @param markov
*/
public HMMERAlignmentColourScheme(AnnotatedCollectionI sg,
HiddenMarkovModel markov)
{
hmm = markov;
countFrequencies(sg);
}
/**
* Default constructor (required by ColourSchemes.loadColourSchemes)
*/
public HMMERAlignmentColourScheme()
{
}
@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);
Double freq = frequency.get(symbol);
if (freq == null)
{
return Color.white;
}
if (prob == 0)
{
return new Color(230, 0, 0);
}
double value = Math.log(prob / freq.doubleValue());
Color colour = null;
if (value > 0)
{
colour = ColorUtils.getGraduatedColour((float) value, 0,
Color.WHITE, logTotalCount, 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
*/
}
@Override
public ColourSchemeI getInstance(AnnotatedCollectionI sg,
Map hiddenRepSequences)
{
List hmms = sg.getHMMConsensusSequences();
HiddenMarkovModel model = hmms.isEmpty() ? null : hmms.get(0).getHMM();
return new HMMERAlignmentColourScheme(sg, model);
}
@Override
public boolean isApplicableTo(AnnotatedCollectionI ac)
{
return !ac.getHMMConsensusSequences().isEmpty();
}
@Override
public String getSchemeName()
{
return JalviewColourScheme.HMMERA.toString();
}
@Override
public boolean isSimple()
{
return false;
}
/**
* Counts and stores the relatively frequency of every residue in the
* alignment
*
* @param sg
*/
public void countFrequencies(AnnotatedCollectionI sg)
{
ResidueCount counts = new ResidueCount(sg.getSequences());
int total = counts.getTotalCount(); // excludes gaps
for (char symbol : counts.getSymbolCounts().symbols)
{
double freq = counts.getCount(symbol) / (double) total;
frequency.put(symbol, freq);
}
logTotalCount = (float) Math.log(total);
}
}