label.group_consensus = Group Consensus
label.group_conservation = Group Conservation
label.show_consensus_histogram = Show Consensus Histogram
+label.show_ssconsensus_histogram = Show SS Consensus Histogram
label.show_consensus_logo = Show Consensus Logo
+label.show_ssconsensus_logo = Show SS Consensus Logo
label.norm_consensus_logo = Normalise Consensus Logo
label.apply_all_groups = Apply to all groups
label.autocalculated_annotation = Autocalculated Annotation
label.quality_descr = Alignment Quality based on Blosum62 scores
label.conservation_descr = Conservation of total alignment less than {0}% gaps
label.consensus_descr = PID
+label.ssconsensus_descr = SS Consensus
label.complement_consensus_descr = PID for cDNA
label.strucconsensus_descr = PID for base pairs
label.occupancy_descr = Number of aligned positions
import jalview.datamodel.ProfilesI;
import jalview.datamodel.ResidueCount;
import jalview.datamodel.ResidueCount.SymbolCounts;
+import jalview.datamodel.SecondaryStructureCount;
import jalview.datamodel.SequenceI;
import jalview.ext.android.SparseIntArray;
import jalview.util.Comparison;
public class AAFrequency
{
public static final String PROFILE = "P";
+ private static final String SS_ANNOTATION_LABEL = "Secondary Structure";
+ private static final char COIL = 'C';
/*
* Quick look-up of String value of char 'A' to 'Z'
// jalview.bin.Console.outPrintln(elapsed);
}
+
+ public static final ProfilesI calculateSS(List<SequenceI> list, int start,
+ int end)
+ {
+ return calculateSS(list, start, end, false);
+ }
+
+ public static final ProfilesI calculateSS(List<SequenceI> sequences,
+ int start, int end, boolean profile)
+ {
+ SequenceI[] seqs = new SequenceI[sequences.size()];
+ int width = 0;
+ synchronized (sequences)
+ {
+ for (int i = 0; i < sequences.size(); i++)
+ {
+ seqs[i] = sequences.get(i);
+ int length = seqs[i].getLength();
+ if (length > width)
+ {
+ width = length;
+ }
+ }
+
+ if (end >= width)
+ {
+ end = width;
+ }
+
+ ProfilesI reply = calculateSS(seqs, width, start, end, profile);
+ return reply;
+ }
+ }
+
+ public static final ProfilesI calculateSS(final SequenceI[] sequences,
+ int width, int start, int end, boolean saveFullProfile)
+ {
+ // long now = System.currentTimeMillis();
+ int seqCount = sequences.length;
+
+ ProfileI[] result = new ProfileI[width];
+
+ for (int column = start; column < end; column++)
+ {
+ /*
+ * Apply a heuristic to detect nucleotide data (which can
+ * be counted in more compact arrays); here we test for
+ * more than 90% nucleotide; recheck every 10 columns in case
+ * of misleading data e.g. highly conserved Alanine in peptide!
+ * Mistakenly guessing nucleotide has a small performance cost,
+ * as it will result in counting in sparse arrays.
+ * Mistakenly guessing peptide has a small space cost,
+ * as it will use a larger than necessary array to hold counts.
+ */
+
+ int ssCount = 0;
+
+ SecondaryStructureCount ssCounts = new SecondaryStructureCount();
+
+ for (int row = 0; row < seqCount; row++)
+ {
+ if (sequences[row] == null)
+ {
+ jalview.bin.Console.errPrintln(
+ "WARNING: Consensus skipping null sequence - possible race condition.");
+ continue;
+ }
+
+ char c = sequences[row].getCharAt(column);
+
+ if (sequences[row].getLength() > column && !Comparison.isGap(c))
+ {
+
+ AlignmentAnnotation[] aa = sequences[row].getAnnotation(SS_ANNOTATION_LABEL);
+ if(aa == null) {
+ continue;
+ }
+ int seqPosition = sequences[row].findPosition(column);
+ char ss;
+ if (aa[0].getAnnotationForPosition(seqPosition) != null) {
+ ss = aa[0].getAnnotationForPosition(seqPosition).secondaryStructure;
+
+ //There is no representation for coil and it can be either ' ' or null.
+ if (ss == ' ') {
+ ss = COIL;
+ }
+ }
+ else {
+ ss = COIL;
+ }
+
+ //secondaryStructures[row][column] = ss;
+
+ ssCounts.add(ss);
+ ssCount++;
+
+ }
+ else
+ {
+ /*
+ * count a gap if the sequence doesn't reach this column
+ */
+ ssCounts.addGap();
+ }
+ }
+
+ int maxSSCount = ssCounts.getModalCount();
+ String maxSS = ssCounts.getSSForCount(maxSSCount);
+ int gapCount = ssCounts.getGapCount();
+ ProfileI profile = new Profile(maxSS, ssCount, gapCount,
+ maxSSCount);
+
+ if (saveFullProfile)
+ {
+ profile.setSSCounts(ssCounts);
+ }
+
+ result[column] = profile;
+ }
+ return new Profiles(result);
+ // long elapsed = System.currentTimeMillis() - now;
+ // jalview.bin.Console.outPrintln(elapsed);
+ }
+
/**
* Make an estimate of the profile size we are going to compute i.e. how many
* different characters may be present in it. Overestimating has a cost of
// long elapsed = System.currentTimeMillis() - now;
// jalview.bin.Console.outPrintln(-elapsed);
}
+
+
+ public static void completeSSConsensus(AlignmentAnnotation ssConsensus,
+ ProfilesI profiles, int startCol, int endCol, boolean ignoreGaps,
+ boolean showSequenceLogo, long nseq)
+ {
+ // long now = System.currentTimeMillis();
+ if (ssConsensus == null || ssConsensus.annotations == null
+ || ssConsensus.annotations.length < endCol)
+ {
+ /*
+ * called with a bad alignment annotation row
+ * wait for it to be initialised properly
+ */
+ return;
+ }
+
+ for (int i = startCol; i < endCol; i++)
+ {
+ ProfileI profile = profiles.get(i);
+ if (profile == null)
+ {
+ /*
+ * happens if sequences calculated over were
+ * shorter than alignment width
+ */
+ ssConsensus.annotations[i] = null;
+ return;
+ }
+
+ final int dp = getPercentageDp(nseq);
+
+ float value = profile.getSSPercentageIdentity(ignoreGaps);
+
+ String description = getSSTooltip(profile, value, showSequenceLogo,
+ ignoreGaps, dp);
+
+ String modalSS = profile.getModalSS();
+ if ("".equals(modalSS))
+ {
+ modalSS = "-";
+ }
+ else if (modalSS.length() > 1)
+ {
+ modalSS = "+";
+ }
+ ssConsensus.annotations[i] = new Annotation(modalSS, description,
+ ' ', value);
+ }
+ // long elapsed = System.currentTimeMillis() - now;
+ // jalview.bin.Console.outPrintln(-elapsed);
+ }
/**
* Derive the gap count annotation row.
}
return description;
}
+
+ static String getSSTooltip(ProfileI profile, float pid,
+ boolean showSequenceLogo, boolean ignoreGaps, int dp)
+ {
+ SecondaryStructureCount counts = profile.getSSCounts();
+
+ String description = null;
+ if (counts != null && showSequenceLogo)
+ {
+ int normaliseBy = ignoreGaps ? profile.getNonGapped()
+ : profile.getHeight();
+ description = counts.getTooltip(normaliseBy, dp);
+ }
+ else
+ {
+ StringBuilder sb = new StringBuilder(64);
+ String maxSS = profile.getModalSS();
+ if (maxSS.length() > 1)
+ {
+ sb.append("[").append(maxSS).append("]");
+ }
+ else
+ {
+ sb.append(maxSS);
+ }
+ if (maxSS.length() > 0)
+ {
+ sb.append(" ");
+ Format.appendPercentage(sb, pid, dp);
+ sb.append("%");
+ }
+ description = sb.toString();
+ }
+ return description;
+ }
/**
* Returns the sorted profile for the given consensus data. The returned array
*/
public static int[] extractProfile(ProfileI profile, boolean ignoreGaps)
{
- ResidueCount counts = profile.getCounts();
- if (counts == null)
+ char[] symbols;
+ int[] values;
+
+ if (profile.getCounts() != null)
{
+ ResidueCount counts = profile.getCounts();
+ SymbolCounts symbolCounts = counts.getSymbolCounts();
+ symbols = symbolCounts.symbols;
+ values = symbolCounts.values;
+
+ }
+ else if(profile.getSSCounts() != null)
+ {
+ SecondaryStructureCount counts = profile.getSSCounts();
+ // to do
+ SecondaryStructureCount.SymbolCounts symbolCounts = counts.getSymbolCounts();
+ symbols = symbolCounts.symbols;
+ values = symbolCounts.values;
+ }
+ else {
return null;
}
+
- SymbolCounts symbolCounts = counts.getSymbolCounts();
- char[] symbols = symbolCounts.symbols;
- int[] values = symbolCounts.values;
QuickSort.sort(values, symbols);
int totalPercentage = 0;
final int divisor = ignoreGaps ? profile.getNonGapped()
boolean isValidCharWidth();
boolean isShowConsensusHistogram();
+
+ boolean isShowSSConsensusHistogram();
boolean isShowSequenceLogo();
+
+ boolean isShowSequenceSSLogo();
boolean isNormaliseSequenceLogo();
* @return
*/
AlignmentAnnotation getAlignmentConsensusAnnotation();
+
+ AlignmentAnnotation getAlignmentSecondaryStructureConsensusAnnotation();
+
/**
* get the container for alignment gap annotation
* @param hconsensus
*/
void setSequenceConsensusHash(ProfilesI hconsensus);
+
+ void setSequenceSSConsensusHash(ProfilesI hSSConsensus);
+
/**
* Set the cDNA complement consensus for the viewport
Iterator<int[]> getViewAsVisibleContigs(boolean selectedRegionOnly);
ContactMatrixI getContactMatrix(AlignmentAnnotation alignmentAnnotation);
+
+ ProfilesI getSequenceSSConsensusHash();
+
}
* in the alignment.</li>
* <li>SHOW_CONSENSUS_HISTOGRAM (false) Show consensus annotation row's
* histogram.</li>
+ * <li>SHOW_SSCONSENSUS_HISTOGRAM (false) Show secondary structure consensus annotation row's
+ * histogram.</li>
* <li>SHOW_CONSENSUS_LOGO (false) Show consensus annotation row's sequence
* logo.</li>
* <li>NORMALISE_CONSENSUS_LOGO (false) Show consensus annotation row's sequence
* an object holding counts of symbols in the profile
*/
private ResidueCount counts;
+
+ private SecondaryStructureCount ssCounts;
/*
* the number of sequences (gapped or not) in the profile
* the highest count for any residue in the profile
*/
private int maxCount;
+ private int maxSSCount;
+
/*
* the residue (e.g. K) or residues (e.g. KQW) with the
* highest count in the profile
*/
private String modalResidue;
+
+ private String modalSS;
/**
* Constructor which allows derived data to be stored without having to store
this.maxCount = max;
this.modalResidue = modalRes;
}
+
+ public Profile(String modalSS, int ssCount, int gaps, int maxSSCount)
+ {
+ this.height = ssCount;
+ this.gapped = gaps;
+ this.maxSSCount = maxSSCount;
+ this.modalSS = modalSS;
+ }
/* (non-Javadoc)
* @see jalview.datamodel.ProfileI#setCounts(jalview.datamodel.ResidueCount)
{
this.counts = residueCounts;
}
+
+ @Override
+ public void setSSCounts(SecondaryStructureCount secondaryStructureCount)
+ {
+ this.ssCounts = secondaryStructureCount;
+ }
/* (non-Javadoc)
* @see jalview.datamodel.ProfileI#getPercentageIdentity(boolean)
}
return pid;
}
+
+ @Override
+ public float getSSPercentageIdentity(boolean ignoreGaps)
+ {
+ if (height == 0)
+ {
+ return 0f;
+ }
+ float ssPid = 0f;
+ if (ignoreGaps && gapped < height)
+ {
+ ssPid = (maxSSCount * 100f) / (height - gapped);
+ }
+ else
+ {
+ ssPid = (maxSSCount * 100f) / height;
+ }
+ return ssPid;
+ }
/* (non-Javadoc)
* @see jalview.datamodel.ProfileI#getCounts()
{
return counts;
}
+
+ @Override
+ public SecondaryStructureCount getSSCounts()
+ {
+ return ssCounts;
+ }
/* (non-Javadoc)
* @see jalview.datamodel.ProfileI#getHeight()
{
return maxCount;
}
+
+ @Override
+ public int getMaxSSCount()
+ {
+ return maxSSCount;
+ }
/* (non-Javadoc)
* @see jalview.datamodel.ProfileI#getModalResidue()
{
return modalResidue;
}
+
+ @Override
+ public String getModalSS()
+ {
+ return modalSS;
+ }
/* (non-Javadoc)
* @see jalview.datamodel.ProfileI#getNonGapped()
* @param residueCounts
*/
public abstract void setCounts(ResidueCount residueCounts);
+ public abstract void setSSCounts(SecondaryStructureCount secondaryStructureCount);
+
/**
* Returns the percentage identity of the profile, i.e. the highest proportion
* @return
*/
public abstract float getPercentageIdentity(boolean ignoreGaps);
+
+ public abstract float getSSPercentageIdentity(boolean ignoreGaps);
/**
* Returns the full symbol counts for this profile
* @return
*/
public abstract int getMaxCount();
+ public abstract int getMaxSSCount();
/**
* Returns the symbol (or concatenated symbols) which have the highest count
* @return
*/
public abstract String getModalResidue();
+ public abstract String getModalSS();
/**
* Answers the number of non-gapped sequences in the profile
* @return
*/
public abstract int getNonGapped();
+ SecondaryStructureCount getSSCounts();
}
\ No newline at end of file
--- /dev/null
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.datamodel;
+
+import jalview.util.Comparison;
+import jalview.util.Format;
+import jalview.util.QuickSort;
+import jalview.util.SparseCount;
+
+/**
+ * A class to count occurrences of residues in a profile, optimised for speed
+ * and memory footprint.
+ *
+ * @author gmcarstairs
+ *
+ */
+public class SecondaryStructureCount
+{
+ /**
+ * A data bean to hold the results of counting symbols
+ */
+ public class SymbolCounts
+ {
+ /**
+ * the symbols seen (as char values), in no particular order
+ */
+ public final char[] symbols;
+
+ /**
+ * the counts for each symbol, in the same order as the symbols
+ */
+ public final int[] values;
+
+ SymbolCounts(char[] s, int[] v)
+ {
+ symbols = s;
+ values = v;
+ }
+ }
+
+ private static final int TOUPPERCASE = 'A' - 'a';
+
+ /*
+ * nucleotide symbols to count (including N unknown)
+ */
+ private static final String SS_SYMBOLS = "HEC";
+
+
+ static final int GAP_COUNT = 0;
+
+ /*
+ * fast lookup tables holding the index into our count
+ * arrays of each symbol; index 0 is reserved for gap counting
+ */
+ private static int[] SS_INDEX = new int[26];
+
+ static
+ {
+ for (int i = 0; i < SS_SYMBOLS.length(); i++)
+ {
+ SS_INDEX[SS_SYMBOLS.charAt(i) - 'A'] = i + 1;
+ }
+ }
+
+ /*
+ * counts array, just big enough for the nucleotide or peptide
+ * character set (plus gap counts in position 0)
+ */
+ private short[] counts;
+
+ /*
+ * alternative array of int counts for use if any count
+ * exceeds the maximum value of short (32767)
+ */
+ private int[] intCounts;
+
+ /*
+ * flag set if we switch from short to int counts
+ */
+ private boolean useIntCounts;
+
+ /*
+ * general-purpose counter, only for use for characters
+ * that are not in the expected alphabet
+ */
+ private SparseCount otherData;
+
+ /*
+ * keeps track of the maximum count value recorded
+ * (if this class ever allows decrements, would need to
+ * calculate this on request instead)
+ */
+ int maxCount;
+
+ /**
+ * Constructor that allocates an array just big enough for the anticipated
+ * characters, plus one position to count gaps
+ */
+ public SecondaryStructureCount()
+ {
+ //isSS = true;
+ int charsToCount = SS_SYMBOLS.length();
+ counts = new short[charsToCount + 1];
+ }
+
+ /**
+ * Increments the count for the given character. The supplied character may be
+ * upper or lower case but counts are for the upper case only. Gap characters
+ * (space, ., -) are all counted together.
+ *
+ * @param c
+ * @return the new value of the count for the character
+ */
+ public int add(final char c)
+ {
+ char u = toUpperCase(c);
+ int newValue = 0;
+ int offset = getOffset(u);
+
+ /*
+ * offset 0 is reserved for gap counting, so 0 here means either
+ * an unexpected character, or a gap character passed in error
+ */
+ if (offset == 0)
+ {
+ if (Comparison.isGap(u))
+ {
+ newValue = addGap();
+ }
+ else
+ {
+ newValue = addOtherCharacter(u);
+ }
+ }
+ else
+ {
+ newValue = increment(offset);
+ }
+ return newValue;
+ }
+
+ /**
+ * Increment the count at the specified offset. If this would result in short
+ * overflow, promote to counting int values instead.
+ *
+ * @param offset
+ * @return the new value of the count at this offset
+ */
+ int increment(int offset)
+ {
+ int newValue = 0;
+ if (useIntCounts)
+ {
+ newValue = intCounts[offset];
+ intCounts[offset] = ++newValue;
+ }
+ else
+ {
+ if (counts[offset] == Short.MAX_VALUE)
+ {
+ handleOverflow();
+ newValue = intCounts[offset];
+ intCounts[offset] = ++newValue;
+ }
+ else
+ {
+ newValue = counts[offset];
+ counts[offset] = (short) ++newValue;
+ }
+ }
+
+ if (offset != GAP_COUNT)
+ {
+ // update modal residue count
+ maxCount = Math.max(maxCount, newValue);
+ }
+ return newValue;
+ }
+
+ /**
+ * Switch from counting in short to counting in int
+ */
+ synchronized void handleOverflow()
+ {
+ intCounts = new int[counts.length];
+ for (int i = 0; i < counts.length; i++)
+ {
+ intCounts[i] = counts[i];
+ }
+ counts = null;
+ useIntCounts = true;
+ }
+
+ /**
+ * Returns this character's offset in the count array
+ *
+ * @param c
+ * @return
+ */
+ int getOffset(char c)
+ {
+ int offset = 0;
+ if ('A' <= c && c <= 'Z')
+ {
+ offset = SS_INDEX[c - 'A'];
+ }
+ return offset;
+ }
+
+ /**
+ * @param c
+ * @return
+ */
+ protected char toUpperCase(final char c)
+ {
+ char u = c;
+ if ('a' <= c && c <= 'z')
+ {
+ u = (char) (c + TOUPPERCASE);
+ }
+ return u;
+ }
+
+ /**
+ * Increment count for some unanticipated character. The first time this
+ * called, a SparseCount is instantiated to hold these 'extra' counts.
+ *
+ * @param c
+ * @return the new value of the count for the character
+ */
+ int addOtherCharacter(char c)
+ {
+ if (otherData == null)
+ {
+ otherData = new SparseCount();
+ }
+ int newValue = otherData.add(c, 1);
+ maxCount = Math.max(maxCount, newValue);
+ return newValue;
+ }
+
+ /**
+ * Set count for some unanticipated character. The first time this called, a
+ * SparseCount is instantiated to hold these 'extra' counts.
+ *
+ * @param c
+ * @param value
+ */
+ void setOtherCharacter(char c, int value)
+ {
+ if (otherData == null)
+ {
+ otherData = new SparseCount();
+ }
+ otherData.put(c, value);
+ }
+
+ /**
+ * Increment count of gap characters
+ *
+ * @return the new count of gaps
+ */
+ public int addGap()
+ {
+ int newValue = increment(GAP_COUNT);
+ return newValue;
+ }
+
+ /**
+ * Answers true if we are counting ints (only after overflow of short counts)
+ *
+ * @return
+ */
+ boolean isCountingInts()
+ {
+ return useIntCounts;
+ }
+
+ /**
+ * Sets the count for the given character. The supplied character may be upper
+ * or lower case but counts are for the upper case only.
+ *
+ * @param c
+ * @param count
+ */
+ public void put(char c, int count)
+ {
+ char u = toUpperCase(c);
+ int offset = getOffset(u);
+
+ /*
+ * offset 0 is reserved for gap counting, so 0 here means either
+ * an unexpected character, or a gap character passed in error
+ */
+ if (offset == 0)
+ {
+ if (Comparison.isGap(u))
+ {
+ set(0, count);
+ }
+ else
+ {
+ setOtherCharacter(u, count);
+ maxCount = Math.max(maxCount, count);
+ }
+ }
+ else
+ {
+ set(offset, count);
+ maxCount = Math.max(maxCount, count);
+ }
+ }
+
+ /**
+ * Sets the count at the specified offset. If this would result in short
+ * overflow, promote to counting int values instead.
+ *
+ * @param offset
+ * @param value
+ */
+ void set(int offset, int value)
+ {
+ if (useIntCounts)
+ {
+ intCounts[offset] = value;
+ }
+ else
+ {
+ if (value > Short.MAX_VALUE || value < Short.MIN_VALUE)
+ {
+ handleOverflow();
+ intCounts[offset] = value;
+ }
+ else
+ {
+ counts[offset] = (short) value;
+ }
+ }
+ }
+
+ /**
+ * Returns the count for the given character, or zero if no count held
+ *
+ * @param c
+ * @return
+ */
+ public int getCount(char c)
+ {
+ char u = toUpperCase(c);
+ int offset = getOffset(u);
+ if (offset == 0)
+ {
+ if (!Comparison.isGap(u))
+ {
+ // should have called getGapCount()
+ return otherData == null ? 0 : otherData.get(u);
+ }
+ }
+ return useIntCounts ? intCounts[offset] : counts[offset];
+ }
+
+ public int getGapCount()
+ {
+ return useIntCounts ? intCounts[0] : counts[0];
+ }
+
+ /**
+ * Answers true if this object wraps a counter for unexpected characters
+ *
+ * @return
+ */
+ boolean isUsingOtherData()
+ {
+ return otherData != null;
+ }
+
+ /**
+ * Returns the character (or concatenated characters) for the symbol(s) with
+ * the given count in the profile. Can be used to get the modal residue by
+ * supplying the modal count value. Returns an empty string if no symbol has
+ * the given count. The symbols are in alphabetic order of standard peptide or
+ * nucleotide characters, followed by 'other' symbols if any.
+ *
+ * @return
+ */
+ public String getSSForCount(int count)
+ {
+ if (count == 0)
+ {
+ return "";
+ }
+
+ /*
+ * find counts for the given value and append the
+ * corresponding symbol
+ */
+ StringBuilder modal = new StringBuilder();
+ if (useIntCounts)
+ {
+ for (int i = 1; i < intCounts.length; i++)
+ {
+ if (intCounts[i] == count)
+ {
+ modal.append(
+ SS_SYMBOLS.charAt(i - 1));
+ }
+ }
+ }
+ else
+ {
+ for (int i = 1; i < counts.length; i++)
+ {
+ if (counts[i] == count)
+ {
+ modal.append(
+ SS_SYMBOLS.charAt(i - 1));
+ }
+ }
+ }
+ if (otherData != null)
+ {
+ for (int i = 0; i < otherData.size(); i++)
+ {
+ if (otherData.valueAt(i) == count)
+ {
+ modal.append((char) otherData.keyAt(i));
+ }
+ }
+ }
+ return modal.toString();
+ }
+
+ /**
+ * Returns the highest count for any symbol(s) in the profile (excluding gap)
+ *
+ * @return
+ */
+ public int getModalCount()
+ {
+ return maxCount;
+ }
+
+ /**
+ * Returns the number of distinct symbols with a non-zero count (excluding the
+ * gap symbol)
+ *
+ * @return
+ */
+ public int size()
+ {
+ int size = 0;
+ if (useIntCounts)
+ {
+ for (int i = 1; i < intCounts.length; i++)
+ {
+ if (intCounts[i] > 0)
+ {
+ size++;
+ }
+ }
+ }
+ else
+ {
+ for (int i = 1; i < counts.length; i++)
+ {
+ if (counts[i] > 0)
+ {
+ size++;
+ }
+ }
+ }
+
+ /*
+ * include 'other' characters recorded (even if count is zero
+ * though that would be a strange use case)
+ */
+ if (otherData != null)
+ {
+ size += otherData.size();
+ }
+
+ return size;
+ }
+
+ /**
+ * Returns a data bean holding those symbols that have a non-zero count
+ * (excluding the gap symbol), with their counts.
+ *
+ * @return
+ */
+ public SymbolCounts getSymbolCounts()
+ {
+ int size = size();
+ char[] symbols = new char[size];
+ int[] values = new int[size];
+ int j = 0;
+
+ if (useIntCounts)
+ {
+ for (int i = 1; i < intCounts.length; i++)
+ {
+ if (intCounts[i] > 0)
+ {
+ char symbol = SS_SYMBOLS.charAt(i - 1);
+ symbols[j] = symbol;
+ values[j] = intCounts[i];
+ j++;
+ }
+ }
+ }
+ else
+ {
+ for (int i = 1; i < counts.length; i++)
+ {
+ if (counts[i] > 0)
+ {
+ char symbol = SS_SYMBOLS.charAt(i - 1);
+ symbols[j] = symbol;
+ values[j] = counts[i];
+ j++;
+ }
+ }
+ }
+ if (otherData != null)
+ {
+ for (int i = 0; i < otherData.size(); i++)
+ {
+ symbols[j] = (char) otherData.keyAt(i);
+ values[j] = otherData.valueAt(i);
+ j++;
+ }
+ }
+
+ return new SymbolCounts(symbols, values);
+ }
+
+ /**
+ * Returns a tooltip string showing residues in descending order of their
+ * percentage frequency in the profile
+ *
+ * @param normaliseBy
+ * the divisor for residue counts (may or may not include gapped
+ * sequence count)
+ * @param percentageDecPl
+ * the number of decimal places to show in percentages
+ * @return
+ */
+ public String getTooltip(int normaliseBy, int percentageDecPl)
+ {
+ SymbolCounts symbolCounts = getSymbolCounts();
+ char[] ca = symbolCounts.symbols;
+ int[] vl = symbolCounts.values;
+
+ /*
+ * sort characters into ascending order of their counts
+ */
+ QuickSort.sort(vl, ca);
+
+ /*
+ * traverse in reverse order (highest count first) to build tooltip
+ */
+ boolean first = true;
+ StringBuilder sb = new StringBuilder(64);
+ for (int c = ca.length - 1; c >= 0; c--)
+ {
+ final char residue = ca[c];
+ // TODO combine residues which share a percentage
+ // (see AAFrequency.completeCdnaConsensus)
+ float tval = (vl[c] * 100f) / normaliseBy;
+ sb.append(first ? "" : "; ").append(residue).append(" ");
+ Format.appendPercentage(sb, tval, percentageDecPl);
+ sb.append("%");
+ first = false;
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Returns a string representation of the symbol counts, for debug purposes.
+ */
+ @Override
+ public String toString()
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.append("[ ");
+ SymbolCounts sc = getSymbolCounts();
+ for (int i = 0; i < sc.symbols.length; i++)
+ {
+ sb.append(sc.symbols[i]).append(":").append(sc.values[i]).append(" ");
+ }
+ sb.append("]");
+ return sb.toString();
+ }
+}
* consensus calculation property
*/
private boolean showSequenceLogo = false;
+
+
+ private boolean showSequenceSSLogo = false;
/**
* flag indicating if logo should be rendered normalised
private boolean hidecols = false;
AlignmentAnnotation consensus = null;
+
+
+ AlignmentAnnotation ssConsensus = null;
AlignmentAnnotation conservation = null;
private boolean showConsensusHistogram;
+
+ private boolean showSSConsensusHistogram;
private AnnotatedCollectionI context;
showSequenceLogo = seqsel.showSequenceLogo;
normaliseSequenceLogo = seqsel.normaliseSequenceLogo;
showConsensusHistogram = seqsel.showConsensusHistogram;
+ showSSConsensusHistogram = seqsel.showSSConsensusHistogram;
idColour = seqsel.idColour;
outlineColour = seqsel.outlineColour;
seqrep = seqsel.seqrep;
cs.setConsensus(cnsns);
upd = true;
}
+
+
+ ProfilesI ssCnsns = AAFrequency.calculateSS(sequences, startRes,
+ endRes + 1, showSequenceLogo);
+ if (ssConsensus != null)
+ {
+ _updateSSConsensusRow(ssCnsns, sequences.size());
+ upd = true;
+ }
+ if (cs != null)
+ {
+ cs.setSsConsensus(ssCnsns);
+ upd = true;
+ }
+
if ((conservation != null)
|| (cs != null && cs.conservationApplied()))
// for
// ignoreGapsInConsensusCalculation);
}
+
+ public ProfilesI ssConsensusData = null;
+
+ private void _updateSSConsensusRow(ProfilesI ssCnsns, long nseq)
+ {
+ if (ssConsensus == null)
+ {
+ getSSConsensus();
+ }
+ ssConsensus.label = "Sec Str Consensus for " + getName();
+ ssConsensus.description = "Percent Identity";
+ ssConsensusData = ssCnsns;
+ // preserve width if already set
+ int aWidth = (ssConsensus.annotations != null)
+ ? (endRes < ssConsensus.annotations.length
+ ? ssConsensus.annotations.length
+ : endRes + 1)
+ : endRes + 1;
+ ssConsensus.annotations = null;
+ ssConsensus.annotations = new Annotation[aWidth]; // should be alignment width
+
+ AAFrequency.completeSSConsensus(ssConsensus, ssCnsns, startRes, endRes + 1,
+ ignoreGapsInConsensus, showSequenceLogo, nseq); // TODO: setting
+ // container
+ // for
+ // ignoreGapsInConsensusCalculation);
+ }
/**
* @param s
}
return consensus;
}
+
+ public AlignmentAnnotation getSSConsensus()
+ {
+ // TODO get or calculate and get consensus annotation row for this group
+ int aWidth = this.getWidth();
+ // pointer
+ // possibility
+ // here.
+ if (aWidth < 0)
+ {
+ return null;
+ }
+ if (ssConsensus == null)
+ {
+ ssConsensus = new AlignmentAnnotation("", "", new Annotation[1], 0f,
+ 100f, AlignmentAnnotation.BAR_GRAPH);
+ ssConsensus.hasText = true;
+ ssConsensus.autoCalculated = true;
+ ssConsensus.groupRef = this;
+ ssConsensus.label = "Sec Str Consensus for " + getName();
+ ssConsensus.description = "Percent Identity";
+ }
+ return ssConsensus;
+ }
/**
* set this alignmentAnnotation object as the one used to render consensus
}
this.showSequenceLogo = showSequenceLogo;
}
+
+
+ public void setshowSequenceSSLogo(boolean showSequenceSSLogo)
+ {
+ // TODO: decouple calculation from settings update
+ if (this.showSequenceSSLogo != showSequenceSSLogo && ssConsensus != null)
+ {
+ this.showSequenceSSLogo = showSequenceSSLogo;
+ recalcConservation();
+ }
+ this.showSequenceSSLogo = showSequenceSSLogo;
+ }
/**
*
}
this.showConsensusHistogram = showConsHist;
}
+
+ public void setShowSSConsensusHistogram(boolean showSSConsHist)
+ {
+
+ if (showSSConsensusHistogram != showSSConsHist && consensus != null)
+ {
+ this.showSSConsensusHistogram = showSSConsHist;
+ recalcConservation();
+ }
+ this.showSSConsensusHistogram = showSSConsHist;
+ }
/**
* @return the showConsensusHistogram
}
ap.av.updateConservation(ap);
ap.av.updateConsensus(ap);
+ ap.av.updateSecondaryStructureConsensus(ap);
ap.av.updateStrucConsensus(ap);
}
}
viewport.setShowConsensusHistogram(showConsensusHistogram.getState());
alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
}
+
+ @Override
+ protected void showSSConsensusHistogram_actionPerformed(ActionEvent e)
+ {
+ viewport.setShowSSConsensusHistogram(showSSConsensusHistogram.getState());
+ alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
+ }
/*
* (non-Javadoc)
}
showConsensusHistogram = Cache.getDefault("SHOW_CONSENSUS_HISTOGRAM",
true);
- showSequenceLogo = Cache.getDefault("SHOW_CONSENSUS_LOGO", false);
+ showSSConsensusHistogram = Cache.getDefault("SHOW_SSCONSENSUS_HISTOGRAM",
+ true);
+ showSequenceLogo = Cache.getDefault("SHOW_CONSENSUS_LOGO", true);
normaliseSequenceLogo = Cache.getDefault("NORMALISE_CONSENSUS_LOGO",
false);
showGroupConsensus = Cache.getDefault("SHOW_GROUP_CONSENSUS", false);
if (residueShading != null)
{
residueShading.setConsensus(hconsensus);
+ residueShading.setSsConsensus(hSSConsensus);
}
setColourAppliesToAllGroups(true);
}
import jalview.analysis.AlignmentAnnotationUtils;
import jalview.analysis.AlignmentUtils;
import jalview.analysis.Conservation;
+import jalview.api.AlignCalcWorkerI;
import jalview.api.AlignViewportI;
import jalview.bin.Console;
import jalview.commands.ChangeCaseCommand;
import jalview.util.StringUtils;
import jalview.util.UrlLink;
import jalview.viewmodel.seqfeatures.FeatureRendererModel;
+import jalview.workers.SecondaryStructureConsensusThread;
/**
* The popup menu that is displayed on right-click on a sequence id, or in the
{
final AlignmentI alignment = this.ap.getAlignment();
AlignmentUtils.addReferenceAnnotations(candidates, alignment, null);
+
+ if(AlignmentUtils.isSSAnnotationPresent(candidates)) {
+ restartSSConsensusWorker();
+ }
+
refresh();
}
+
+
+ private void restartSSConsensusWorker() {
+
+ List<AlignCalcWorkerI> workers = ap.alignFrame.getViewport().getCalcManager()
+ .getRegisteredWorkersOfClass(SecondaryStructureConsensusThread.class);
+ if (!workers.isEmpty()) {
+
+ ap.alignFrame.getViewport().getCalcManager().startWorker(workers.remove(0));
+
+ }
+
+ }
+
+
protected void makeReferenceSeq_actionPerformed(ActionEvent actionEvent)
{
protected JCheckBoxMenuItem showGroupConservation = new JCheckBoxMenuItem();
- protected JCheckBoxMenuItem showConsensusHistogram = new JCheckBoxMenuItem();
+ protected JCheckBoxMenuItem showConsensusHistogram = new JCheckBoxMenuItem();
+
+ protected JCheckBoxMenuItem showSSConsensusHistogram = new JCheckBoxMenuItem();
protected JCheckBoxMenuItem showSequenceLogo = new JCheckBoxMenuItem();
showConsensusHistogram_actionPerformed(e);
}
+ });
+ showSSConsensusHistogram.setText(
+ MessageManager.getString("label.show_ssconsensus_histogram"));
+ showSSConsensusHistogram.addActionListener(new ActionListener()
+ {
+
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ showConsensusHistogram_actionPerformed(e);
+ }
+
});
showSequenceLogo
.setText(MessageManager.getString("label.show_consensus_logo"));
autoAnnMenu.addSeparator();
autoAnnMenu.add(applyAutoAnnotationSettings);
autoAnnMenu.add(showConsensusHistogram);
+ autoAnnMenu.add(showSSConsensusHistogram);
autoAnnMenu.add(showSequenceLogo);
autoAnnMenu.add(normaliseSequenceLogo);
autoAnnMenu.addSeparator();
// TODO Auto-generated method stub
}
+
+ protected void showSSConsensusHistogram_actionPerformed(ActionEvent e)
+ {
+ // TODO Auto-generated method stub
+
+ }
protected void showSequenceLogo_actionPerformed(ActionEvent e)
{
view.isIgnoreGapsinConsensus());
viewport.getResidueShading()
.setConsensus(viewport.getSequenceConsensusHash());
+ viewport.getResidueShading()
+ .setSsConsensus(viewport.getSequenceSSConsensusHash());
if (safeBoolean(view.isConservationSelected()) && cs != null)
{
viewport.getResidueShading()
private HiddenColumns hiddenColumns;
private ProfilesI hconsensus;
+
+ private ProfilesI hSSconsensus;
private Hashtable<String, Object>[] complementConsensus;
{
hiddenColumns = null;
hconsensus = null;
+ hSSconsensus = null;
complementConsensus = null;
hStrucConsensus = null;
fadedImage = null;
columnSelection = av.getColumnSelection();
hiddenColumns = av.getAlignment().getHiddenColumns();
hconsensus = av.getSequenceConsensusHash();
+ hSSconsensus = av.getSequenceSSConsensusHash();
complementConsensus = av.getComplementConsensusHash();
hStrucConsensus = av.getRnaStructureConsensusHash();
av_ignoreGapsConsensus = av.isIgnoreGapsConsensus();
}
}
}
+
+ else if(aa.autoCalculated && aa.label.startsWith("SecondaryStructureConsensus"))
+ {
+ return AAFrequency.extractProfile(
+ hSSconsensus.get(column),
+ av_ignoreGapsConsensus);
+
+ }
+
else
{
if (aa.autoCalculated && aa.label.startsWith("StrucConsensus"))
.getAlignmentStrucConsensusAnnotation();
final AlignmentAnnotation complementConsensusAnnot = av
.getComplementConsensusAnnotation();
+ final AlignmentAnnotation ssConsensusAnnot = av
+ .getAlignmentSecondaryStructureConsensusAnnotation();
BitSet graphGroupDrawn = new BitSet();
int charOffset = 0; // offset for a label
normaliseProfile = row.groupRef.isNormaliseSequenceLogo();
}
else if (row == consensusAnnot || row == structConsensusAnnot
- || row == complementConsensusAnnot)
+ || row == complementConsensusAnnot || row == ssConsensusAnnot)
{
renderHistogram = av_renderHistogram;
renderProfile = av_renderProfile;
* {profile type, #values, total count, char1, pct1, char2, pct2...}
*/
int profl[] = getProfileFor(_aa, column);
+
+
// just try to draw the logo if profl is not null
if (profl != null && profl[2] != 0)
}
else
{
+
colour = profcolour.findColour(dc[0], column, null);
+
}
g.setColor(colour == Color.white ? Color.lightGray : colour);
* the consensus data for each column
*/
private ProfilesI consensus;
+
+ /*
+ * the consensus data for each column
+ */
+ private ProfilesI ssConsensus;
+
+
+ public ProfilesI getSsConsensus()
+ {
+ return ssConsensus;
+ }
+
+ public void setSsConsensus(ProfilesI ssConsensus)
+ {
+ this.ssConsensus = ssConsensus;
+ }
/*
* if true, apply shading of colour by conservation
this.conservationIncrement = rs.conservationIncrement;
this.ignoreGaps = rs.ignoreGaps;
this.pidThreshold = rs.pidThreshold;
+ this.ssConsensus = rs.ssConsensus;
}
/**
public void setConsensus(ProfilesI cons)
{
consensus = cons;
+
}
/**
return colour;
}
+
+ @Override
+ public Color findSSColour(char symbol, int position, SequenceI seq)
+ {
+ if (colourScheme == null)
+ {
+ return Color.white; // Colour is 'None'
+ }
+
+ /*
+ * get 'base' colour
+ */
+ ProfileI profile = ssConsensus == null ? null : ssConsensus.get(position);
+ String modalSS = profile == null ? null
+ : profile.getModalSS();
+ float pid = profile == null ? 0f
+ : profile.getSSPercentageIdentity(ignoreGaps);
+ Color colour = colourScheme.findColour(symbol, position, seq,
+ modalSS, pid);
+
+ /*
+ * apply PID threshold and consensus fading if in force
+ */
+ if (!Comparison.isGap(symbol))
+ {
+ colour = adjustColour(symbol, position, colour);
+ }
+
+ return colour;
+ }
/**
* Adjusts colour by applying thresholding or conservation shading, if in
{
public abstract void setConsensus(ProfilesI cons);
+
+ public abstract void setSsConsensus(ProfilesI cons);
public abstract boolean conservationApplied();
public abstract void setColourScheme(ColourSchemeI cs);
+ Color findSSColour(char symbol, int position, SequenceI seq);
+
}
\ No newline at end of file
import jalview.workers.AlignCalcManager;
import jalview.workers.ComplementConsensusThread;
import jalview.workers.ConsensusThread;
+import jalview.workers.SecondaryStructureConsensusThread;
import jalview.workers.StrucConsensusThread;
/**
}
protected AlignmentAnnotation consensus;
+
+ protected AlignmentAnnotation secondaryStructureConsensus;
protected AlignmentAnnotation complementConsensus;
protected AlignmentAnnotation quality;
protected AlignmentAnnotation[] groupConsensus;
+
+ protected AlignmentAnnotation[] groupSSConsensus;
protected AlignmentAnnotation[] groupConservation;
* results of alignment consensus analysis for visible portion of view
*/
protected ProfilesI hconsensus = null;
+
+ protected ProfilesI hSSConsensus = null;
+
+
/**
* results of cDNA complement consensus visible portion of view
{
this.hconsensus = hconsensus;
}
-
+
+ @Override
+ public void setSequenceSSConsensusHash(ProfilesI hSSConsensus)
+ {
+ this.hSSConsensus = hSSConsensus;
+ }
+
@Override
public void setComplementConsensusHash(
Hashtable<String, Object>[] hconsensus)
{
return hconsensus;
}
+
+ @Override
+ public ProfilesI getSequenceSSConsensusHash()
+ {
+ return hSSConsensus;
+ }
@Override
public Hashtable<String, Object>[] getComplementConsensusHash()
return consensus;
}
+
+ @Override
+ public AlignmentAnnotation getAlignmentSecondaryStructureConsensusAnnotation()
+ {
+ return secondaryStructureConsensus;
+ }
+
+
@Override
public AlignmentAnnotation getAlignmentGapAnnotation()
{
}
}
}
+
+
+
+
+ /**
+ * trigger update of consensus annotation
+ */
+ public void updateSecondaryStructureConsensus(final AlignmentViewPanel ap)
+ {
+ // see note in mantis : issue number 8585
+ if (secondaryStructureConsensus == null || !autoCalculateConsensus)
+ {
+ return;
+ }
+ if (calculator
+ .getRegisteredWorkersOfClass(SecondaryStructureConsensusThread.class) == null)
+ {
+ calculator.registerWorker(new SecondaryStructureConsensusThread(this, ap));
+ }
+ }
// --------START Structure Conservation
public void updateStrucConsensus(final AlignmentViewPanel ap)
consensus = null;
complementConsensus = null;
strucConsensus = null;
+ secondaryStructureConsensus = null;
conservation = null;
quality = null;
groupConsensus = null;
* should consensus profile be rendered by default
*/
protected boolean showSequenceLogo = false;
+
+ protected boolean showSequenceSSLogo = false;
/**
* should consensus profile be rendered normalised to row height
* should consensus histograms be rendered by default
*/
protected boolean showConsensusHistogram = true;
+
+ protected boolean showSSConsensusHistogram = true;
+
+ public void setShowSSConsensusHistogram(boolean showSSConsensusHistogram)
+ {
+ this.showSSConsensusHistogram = showSSConsensusHistogram;
+ }
/**
* @return the showConsensusProfile
{
return showSequenceLogo;
}
+
+ @Override
+ public boolean isShowSequenceSSLogo()
+ {
+ return showSequenceSSLogo;
+ }
/**
* @param showSequenceLogo
}
this.showSequenceLogo = showSequenceLogo;
}
+
+ public void setShowSequenceSSLogo(boolean showSequenceSSLogo)
+ {
+ if (showSequenceSSLogo != this.showSequenceSSLogo)
+ {
+ // TODO: decouple settings setting from calculation when refactoring
+ // annotation update method from alignframe to viewport
+ this.showSequenceSSLogo = showSequenceSSLogo;
+ calculator.updateAnnotationFor(SecondaryStructureConsensusThread.class);
+ }
+ this.showSequenceSSLogo = showSequenceSSLogo;
+ }
/**
* @param showConsensusHistogram
{
return this.showConsensusHistogram;
}
+
+ @Override
+ public boolean isShowSSConsensusHistogram()
+ {
+ return this.showSSConsensusHistogram;
+ }
/**
* when set, updateAlignment will always ensure sequences are of equal length
if (ap != null)
{
updateConsensus(ap);
+ updateSecondaryStructureConsensus(ap);
if (residueShading != null)
{
residueShading.setThreshold(residueShading.getThreshold(),
if (autoCalculateConsensus)
{
updateConsensus(ap);
+ updateSecondaryStructureConsensus(ap);
}
if (hconsensus != null && autoCalculateConsensus)
{
consensus = new AlignmentAnnotation("Consensus",
MessageManager.getString("label.consensus_descr"),
new Annotation[1], 0f, 100f, AlignmentAnnotation.BAR_GRAPH);
+
+ secondaryStructureConsensus = new AlignmentAnnotation("SecondaryStructureConsensus",
+ MessageManager.getString("label.ssconsensus_descr"),
+ new Annotation[1], 0f, 100f, AlignmentAnnotation.BAR_GRAPH);
+
initConsensus(consensus);
+ initSSConsensus(secondaryStructureConsensus);
initGapCounts();
-
initComplementConsensus();
}
}
+
/**
* If this is a protein alignment and there are mappings to cDNA, adds the
* cDNA consensus annotation and returns true, else returns false.
alignment.addAnnotation(aa);
}
}
+
+ private void initSSConsensus(AlignmentAnnotation aa)
+ {
+ aa.hasText = true;
+ aa.autoCalculated = true;
+
+ if (showConsensus)
+ {
+ alignment.addAnnotation(aa);
+ }
+ }
// these should be extracted from the view model - style and settings for
// derived annotation
boolean conv = isShowGroupConservation();
boolean cons = isShowGroupConsensus();
boolean showprf = isShowSequenceLogo();
+ boolean showSSprf = isShowSequenceSSLogo();
boolean showConsHist = isShowConsensusHistogram();
+ boolean showSSConsHist = isShowSSConsensusHistogram();
boolean normLogo = isNormaliseSequenceLogo();
/**
{
// set defaults for this group's conservation/consensus
sg.setshowSequenceLogo(showprf);
+ sg.setshowSequenceSSLogo(showSSprf);
sg.setShowConsensusHistogram(showConsHist);
+ sg.setShowSSConsensusHistogram(showSSConsHist);
sg.setNormaliseSequenceLogo(normLogo);
}
if (conv)
{
updateCalcs = true;
alignment.addAnnotation(sg.getConsensus(), 0);
+ alignment.addAnnotation(sg.getSSConsensus(), 0);
}
// refresh the annotation rows
if (updateCalcs)
+ ((ignoreGapsInConsensusCalculation) ? " without gaps" : ""));
return sq;
}
+
+ public SequenceI getSSConsensusSeq()
+ {
+ if (secondaryStructureConsensus == null)
+ {
+ updateSecondaryStructureConsensus(null);
+ }
+ if (secondaryStructureConsensus == null)
+ {
+ return null;
+ }
+ StringBuffer seqs = new StringBuffer();
+ for (int i = 0; i < secondaryStructureConsensus.annotations.length; i++)
+ {
+ Annotation annotation = secondaryStructureConsensus.annotations[i];
+ if (annotation != null)
+ {
+ String description = annotation.description;
+ if (description != null && description.startsWith("["))
+ {
+ // consensus is a tie - just pick the first one
+ seqs.append(description.charAt(1));
+ }
+ else
+ {
+ seqs.append(annotation.displayCharacter);
+ }
+ }
+ }
+
+ SequenceI sq = new Sequence("Sec Str Consensus", seqs.toString());
+ sq.setDescription("Percentage Identity Sec Str Consensus "
+ + ((ignoreGapsInConsensusCalculation) ? " without gaps" : ""));
+ return sq;
+ }
@Override
public void setCurrentTree(TreeModel tree)
*/
package jalview.workers;
-import jalview.api.AlignCalcManagerI;
-import jalview.api.AlignCalcWorkerI;
-import jalview.datamodel.AlignmentAnnotation;
-
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
+import jalview.api.AlignCalcManagerI;
+import jalview.api.AlignCalcWorkerI;
+import jalview.datamodel.AlignmentAnnotation;
+
public class AlignCalcManager implements AlignCalcManagerI
{
/*
--- /dev/null
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.workers;
+
+import jalview.analysis.AAFrequency;
+import jalview.api.AlignViewportI;
+import jalview.api.AlignmentViewPanel;
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.Annotation;
+import jalview.datamodel.ProfilesI;
+import jalview.datamodel.SequenceI;
+import jalview.renderer.ResidueShaderI;
+
+public class SecondaryStructureConsensusThread extends AlignCalcWorker
+{
+ public SecondaryStructureConsensusThread(AlignViewportI alignViewport,
+ AlignmentViewPanel alignPanel)
+ {
+ super(alignViewport, alignPanel);
+ }
+
+ @Override
+ public void run()
+ {
+ if (calcMan.isPending(this))
+ {
+ return;
+ }
+ calcMan.notifyStart(this);
+ // long started = System.currentTimeMillis();
+ try
+ {
+ AlignmentAnnotation ssConsensus = getSSConsensusAnnotation();
+ AlignmentAnnotation gap = getGapAnnotation();
+ if ((ssConsensus == null && gap == null) || calcMan.isPending(this))
+ {
+ calcMan.workerComplete(this);
+ return;
+ }
+ while (!calcMan.notifyWorking(this))
+ {
+ try
+ {
+ if (ap != null)
+ {
+ ap.paintAlignment(false, false);
+ }
+ Thread.sleep(200);
+ } catch (Exception ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+ if (alignViewport.isClosed())
+ {
+ abortAndDestroy();
+ return;
+ }
+ AlignmentI alignment = alignViewport.getAlignment();
+
+ int aWidth = -1;
+
+ if (alignment == null || (aWidth = alignment.getWidth()) < 0)
+ {
+ calcMan.workerComplete(this);
+ return;
+ }
+
+ eraseSSConsensus(aWidth);
+ computeSSConsensus(alignment);
+ updateResultAnnotation(true);
+
+ if (ap != null)
+ {
+ ap.paintAlignment(true, true);
+ }
+ } catch (OutOfMemoryError error)
+ {
+ calcMan.disableWorker(this);
+ ap.raiseOOMWarning("calculating consensus", error);
+ } finally
+ {
+ /*
+ * e.g. ArrayIndexOutOfBoundsException can happen due to a race condition
+ * - alignment was edited at same time as calculation was running
+ */
+ calcMan.workerComplete(this);
+ }
+ }
+
+ /**
+ * Clear out any existing consensus annotations
+ *
+ * @param aWidth
+ * the width (number of columns) of the annotated alignment
+ */
+ protected void eraseSSConsensus(int aWidth)
+ {
+ AlignmentAnnotation ssConsensus = getSSConsensusAnnotation();
+ if (ssConsensus != null)
+ {
+ ssConsensus.annotations = new Annotation[aWidth];
+ }
+ AlignmentAnnotation gap = getGapAnnotation();
+ if (gap != null)
+ {
+ gap.annotations = new Annotation[aWidth];
+ }
+ }
+
+ /**
+ * @param alignment
+ */
+ protected void computeSSConsensus(AlignmentI alignment)
+ {
+
+ SequenceI[] aseqs = getSequences();
+ int width = alignment.getWidth();
+ ProfilesI hSSConsensus = AAFrequency.calculateSS(aseqs, width, 0, width,
+ true);
+
+ alignViewport.setSequenceSSConsensusHash(hSSConsensus);
+ setColourSchemeConsensus(hSSConsensus);
+ }
+
+ /**
+ * @return
+ */
+ protected SequenceI[] getSequences()
+ {
+ return alignViewport.getAlignment().getSequencesArray();
+ }
+
+ /**
+ * @param hconsensus
+ */
+ protected void setColourSchemeConsensus(ProfilesI hSSconsensus)
+ {
+ ResidueShaderI cs = alignViewport.getResidueShading();
+ if (cs != null)
+ {
+ cs.setSsConsensus(hSSconsensus);
+ }
+ }
+
+ /**
+ * Get the Consensus annotation for the alignment
+ *
+ * @return
+ */
+ protected AlignmentAnnotation getSSConsensusAnnotation()
+ {
+ return alignViewport.getAlignmentSecondaryStructureConsensusAnnotation();
+ }
+
+ /**
+ * Get the Gap annotation for the alignment
+ *
+ * @return
+ */
+ protected AlignmentAnnotation getGapAnnotation()
+ {
+ return alignViewport.getAlignmentGapAnnotation();
+ }
+
+ /**
+ * update the consensus annotation from the sequence profile data using
+ * current visualization settings.
+ */
+ @Override
+ public void updateAnnotation()
+ {
+ updateResultAnnotation(false);
+ }
+
+ public void updateResultAnnotation(boolean immediate)
+ {
+ AlignmentAnnotation ssConsensus = getSSConsensusAnnotation();
+ ProfilesI hSSConsensus = (ProfilesI) getViewportSSConsensus();
+ if (immediate || !calcMan.isWorking(this) && ssConsensus != null
+ && hSSConsensus != null)
+ {
+ deriveSSConsensus(ssConsensus, hSSConsensus);
+ AlignmentAnnotation gap = getGapAnnotation();
+ if (gap != null)
+ {
+ deriveGap(gap, hSSConsensus);
+ }
+ }
+ }
+
+ /**
+ * Convert the computed consensus data into the desired annotation for
+ * display.
+ *
+ * @param consensusAnnotation
+ * the annotation to be populated
+ * @param hconsensus
+ * the computed consensus data
+ */
+ protected void deriveSSConsensus(AlignmentAnnotation ssConsensusAnnotation,
+ ProfilesI hSSConsensus)
+ {
+
+ long nseq = getSequences().length;
+ AAFrequency.completeSSConsensus(ssConsensusAnnotation, hSSConsensus,
+ hSSConsensus.getStartColumn(), hSSConsensus.getEndColumn() + 1,
+ alignViewport.isIgnoreGapsConsensus(),
+ alignViewport.isShowSequenceLogo(), nseq);
+ }
+
+ /**
+ * Convert the computed consensus data into a gap annotation row for display.
+ *
+ * @param gapAnnotation
+ * the annotation to be populated
+ * @param hconsensus
+ * the computed consensus data
+ */
+ protected void deriveGap(AlignmentAnnotation gapAnnotation,
+ ProfilesI hconsensus)
+ {
+ long nseq = getSequences().length;
+ AAFrequency.completeGapAnnot(gapAnnotation, hconsensus,
+ hconsensus.getStartColumn(), hconsensus.getEndColumn() + 1,
+ nseq);
+ }
+
+ /**
+ * Get the consensus data stored on the viewport.
+ *
+ * @return
+ */
+ protected Object getViewportSSConsensus()
+ {
+ // TODO convert ComplementConsensusThread to use Profile
+ return alignViewport.getSequenceSSConsensusHash();
+ }
+}
import jalview.datamodel.Profiles;
import jalview.datamodel.ProfilesI;
import jalview.datamodel.ResidueCount;
+import jalview.datamodel.SecondaryStructureCount;
import jalview.datamodel.Sequence;
import jalview.datamodel.SequenceI;
import jalview.schemes.ColourSchemeI;
{
return 0;
}
+
+ @Override
+ public void setSSCounts(
+ SecondaryStructureCount secondaryStructureCount)
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public float getSSPercentageIdentity(boolean ignoreGaps)
+ {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public int getMaxSSCount()
+ {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public String getModalSS()
+ {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public SecondaryStructureCount getSSCounts()
+ {
+ // TODO Auto-generated method stub
+ return null;
+ }
};
}