types. Sequences with similar distributions of features of the
same type will be grouped together in trees computed with this
metric. <em>This measure was introduced in Jalview 2.9</em></li>
+
+ <li><strong>Secondary Structure Similarity</strong><br>Trees are
+ generated using a distance matrix, which is constructed from Jaccard
+ distances that specifically consider the secondary structure features
+ observed at each column of the alignment.
+ <ul>
+ <li>For secondary structure similarity analysis, at any given column
+ <em>i</em>, the range of unique secondary structures is between 0 and 2,
+ reflecting the presence of helices, sheets, coils and gaps.
+ <br>The similarity at column <em>i</em> = Total
+ number of unique secondary structures (which can range from 0 to 2)
+ - Sum of the number of secondary structures in common at column
+ <em>i</em> (which can be either 0 or 1)<br>The similarity scores are
+ summed across all columns and then divided by the total number of
+ columns to calculate an average similarity score.
+ </li>
+ </ul>
+ Distance calculations are based on the secondary structures
+ currently displayed. Sequences with similar distributions of secondary
+ structures will be grouped together in trees.<br>
+ <em>The distance between two sequences is maximum when one
+ sequence has a defined secondary structure annotation track and the
+ other does not, indicating complete dissimilarity between them.
+ Whereas, the distance between two sequences is minimum when both of
+ the sequences within the comparison do not have a defined secondary
+ structure annotation track.</em>
+ </li>
</ul>
<p>
<strong>Tree Construction Methods</strong>
label.score_model_conservation = Physicochemical property conservation
label.score_model_enhconservation = Physicochemical property conservation
label.status_bar = Status bar
+label.sequence_count = No. of sequences:
label.out_to_textbox = Output to Textbox
label.occupancy = Occupancy
# delete Clustal - use FileFormat name instead
label.hide_selected_annotations = Hide selected annotations
label.show_selected_annotations = Show selected annotations
label.group_consensus = Group Consensus
+label.group_ss_consensus = Group Secondary Structure Consensus
label.group_conservation = Group Conservation
label.show_consensus_histogram = Show 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.show_secondary_structure = Show Secondary Structure
+label.show_secondary_structure_consensus = Show Secondary Structure Consensus
label.show_first = Show first
label.show_last = Show last
label.struct_from_pdb = Process secondary structure from PDB
label.maximize_window = Maximize Window
label.conservation = Conservation
label.consensus = Consensus
+label.ssConsensus = Secondary Structure Consensus
label.histogram = Histogram
label.logo = Logo
label.non_positional_features = List Non-positional Features
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_label = Secondary Structure Consensus
+label.ssconsensus_descr = Secondary Structure Consensus
+option.ss_providers_all = All
+option.ss_providers_none = None
label.complement_consensus_descr = PID for cDNA
label.strucconsensus_descr = PID for base pairs
label.occupancy_descr = Number of aligned positions
--- /dev/null
+ScoreMatrix SECONDARYSTRUCTURE
+#
+# The SECONDARY STRUCTURE substitution matrix, as in <paper name>
+# The first line declares a ScoreMatrix with the name SECONDARYSTRUCTURE (shown in menus)
+#
+# Scores are not symbol case sensitive, unless column(s) are provided for lower case characters
+# The 'guide symbol' at the start of each row of score values is optional
+# Values may be integer or floating point, delimited by tab, space, comma or combinations
+#
+ E H C *
+E 1 0 0 0
+H 0 1 0 0
+C 0 0 1 0
+* 0 0 0 1
\ No newline at end of file
import jalview.datamodel.ProfilesI;
import jalview.datamodel.ResidueCount;
import jalview.datamodel.ResidueCount.SymbolCounts;
+import jalview.datamodel.SecondaryStructureCount;
+import jalview.datamodel.SeqCigar;
import jalview.datamodel.SequenceI;
import jalview.ext.android.SparseIntArray;
import jalview.util.Comparison;
+import jalview.util.Constants;
import jalview.util.Format;
import jalview.util.MappingUtils;
import jalview.util.QuickSort;
// jalview.bin.Console.outPrintln(elapsed);
}
+
+ public static final ProfilesI calculateSS(List<SequenceI> list, int start,
+ int end, String source)
+ {
+ return calculateSS(list, start, end, false, source);
+ }
+
+ public static final ProfilesI calculateSS(List<SequenceI> sequences,
+ int start, int end, boolean profile, String source)
+ {
+ 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, source);
+ return reply;
+ }
+ }
+
+ public static final ProfilesI calculateSS(final SequenceI[] sequences,
+ int width, int start, int end, boolean saveFullProfile, String source)
+ {
+
+ int seqCount = sequences.length;
+
+ int seqWithSSCount = 0;
+
+ ProfileI[] result = new ProfileI[width];
+
+ for (int column = start; column < end; column++)
+ {
+
+ 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);
+ List<AlignmentAnnotation> annots = AlignmentUtils.getAlignmentAnnotationForSource(sequences[row], source);
+ if(annots!=null) {
+ seqWithSSCount++;
+ for(AlignmentAnnotation aa:annots) {
+ if(aa!=null) {
+ ssCount++;
+ }
+
+ if (sequences[row].getLength() > column && !Comparison.isGap(c) && aa !=null)
+ {
+
+ int seqPosition = sequences[row].findPosition(column);
+
+ char ss = AlignmentUtils.findSSAnnotationForGivenSeqposition(
+ aa, seqPosition);
+ if(ss == '*') {
+ continue;
+ }
+ ssCounts.add(ss);
+ }
+ else if(Comparison.isGap(c) && aa!=null) {
+ ssCounts.addGap();
+ }
+ }
+ }
+ }
+
+ int maxSSCount = ssCounts.getModalCount();
+ String maxSS = ssCounts.getSSForCount(maxSSCount);
+ int gapCount = ssCounts.getGapCount();
+ ProfileI profile = new Profile(maxSS, ssCount, gapCount,
+ maxSSCount, seqWithSSCount);
+
+
+ if (saveFullProfile)
+ {
+ profile.setSSCounts(ssCounts);
+ }
+
+ result[column] = profile;
+ }
+ return new Profiles(result);
+ }
+
/**
* 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;
+ }
+
+ if(ssConsensus.getNoOfSequencesIncluded()<0) {
+ ssConsensus.setNoOfSequencesIncluded(profile.getSeqWithSSCount());
+ }
+
+ 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()
*/
package jalview.analysis;
+import java.awt.Color;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
+import java.util.Vector;
+import jalview.api.AlignCalcWorkerI;
import jalview.bin.Console;
import jalview.commands.RemoveGapColCommand;
import jalview.datamodel.AlignedCodon;
import jalview.datamodel.Alignment;
import jalview.datamodel.AlignmentAnnotation;
import jalview.datamodel.AlignmentI;
+import jalview.datamodel.Annotation;
import jalview.datamodel.ContactMatrixI;
import jalview.datamodel.DBRefEntry;
import jalview.datamodel.GeneLociI;
import jalview.datamodel.IncompleteCodonException;
import jalview.datamodel.Mapping;
+import jalview.datamodel.PDBEntry;
+import jalview.datamodel.SeqCigar;
import jalview.datamodel.Sequence;
import jalview.datamodel.SequenceFeature;
import jalview.datamodel.SequenceGroup;
import jalview.datamodel.SequenceI;
import jalview.datamodel.features.SequenceFeatures;
+import jalview.gui.AlignmentPanel;
import jalview.io.gff.SequenceOntologyI;
import jalview.schemes.ResidueProperties;
import jalview.util.Comparison;
+import jalview.util.Constants;
import jalview.util.DBRefUtils;
import jalview.util.IntRangeComparator;
import jalview.util.MapList;
import jalview.util.MappingUtils;
+import jalview.util.MessageManager;
+import jalview.workers.SecondaryStructureConsensusThread;
/**
* grab bag of useful alignment manipulation operations Expect these to be
{
private static final int CODON_LENGTH = 3;
- private static final String SEQUENCE_VARIANT = "sequence_variant:";
+ private static final String SEQUENCE_VARIANT = "sequence_variant:";
/*
* the 'id' attribute is provided for variant features fetched from
}
}
}
+
+
+ public static boolean isSSAnnotationPresent( Map<SequenceI, List<AlignmentAnnotation>> annotations) {
+
+ for (SequenceI seq : annotations.keySet())
+ {
+ if(isSecondaryStructurePresent(annotations.get(seq).toArray(new AlignmentAnnotation[0])))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
/**
* Make a copy of a reference annotation {@code ann} and add it to an
}
return true;
}
+
+
+ public static List<String> getSecondaryStructureSources(
+ AlignmentAnnotation[] annotations)
+ {
+
+ List<String> ssSources = new ArrayList<>();
+ Set<String> addedLabels = new HashSet<>(); // to keep track of added labels
+
+ for (AlignmentAnnotation annotation : annotations)
+ {
+ String label = annotation.label;
+ if (Constants.SECONDARY_STRUCTURE_LABELS.containsKey(label)
+ && !addedLabels.contains(label))
+ {
+ ssSources.add(Constants.SECONDARY_STRUCTURE_LABELS.get(label));
+ addedLabels.add(label); // Add the label to the set
+ }
+ }
+
+ return ssSources;
+ }
+
+ public static boolean isSecondaryStructurePresent(AlignmentAnnotation[] annotations)
+ {
+ boolean ssPresent = false;
+
+ for (AlignmentAnnotation aa : annotations)
+ {
+ if (ssPresent)
+ {
+ break;
+ }
+
+ if (Constants.SECONDARY_STRUCTURE_LABELS.containsKey(aa.label))
+ {
+ ssPresent = true;
+ break;
+ }
+ }
+
+ return ssPresent;
+
+ }
+
+ public static Color getSecondaryStructureAnnotationColour(char symbol)
+ {
+
+ if (symbol == Constants.COIL)
+ {
+ return Color.gray;
+ }
+ if (symbol == Constants.SHEET)
+ {
+ return Color.green;
+ }
+ if (symbol == Constants.HELIX)
+ {
+ return Color.red;
+ }
+
+ return Color.gray;
+ }
+
+ public static char findSSAnnotationForGivenSeqposition(AlignmentAnnotation aa,
+ int seqPosition)
+ {
+ char ss = '*';
+
+ if (aa != null)
+ {
+ if (aa.getAnnotationForPosition(seqPosition) != null)
+ {
+ Annotation a = aa.getAnnotationForPosition(seqPosition);
+ ss = a.secondaryStructure;
+
+ // There is no representation for coil and it can be either ' ' or null.
+ if (ss == ' ' || ss == '-')
+ {
+ ss = Constants.COIL;
+ }
+ }
+ else
+ {
+ ss = Constants.COIL;
+ }
+ }
+
+ return ss;
+ }
+
+
+ public static List<String> extractSSSourceInAlignmentAnnotation(
+ AlignmentAnnotation[] annotations)
+ {
+
+ List<String> ssSources = new ArrayList<>();
+ Set<String> addedSources = new HashSet<>(); // to keep track of added
+ // sources
+
+ if (annotations == null)
+ {
+ return ssSources;
+ }
+
+ for (AlignmentAnnotation aa : annotations)
+ {
+
+ String ssSource = extractSSSourceFromAnnotationDescription(aa);
+
+ if (ssSource != null && !addedSources.contains(ssSource))
+ {
+ ssSources.add(ssSource);
+ addedSources.add(ssSource);
+ }
+
+ }
+ Collections.sort(ssSources);
+
+ return ssSources;
+
+ }
+
+ public static String extractSSSourceFromAnnotationDescription(
+ AlignmentAnnotation aa)
+ {
+
+ for (String label : Constants.SECONDARY_STRUCTURE_LABELS.keySet())
+ {
+
+ if (label.equals(aa.label))
+ {
+
+ // For JPred
+ if (aa.label.equals(Constants.SS_ANNOTATION_FROM_JPRED_LABEL))
+ {
+
+ return (Constants.SECONDARY_STRUCTURE_LABELS.get(aa.label));
+
+ }
+
+ // For input with secondary structure
+ if (aa.label.equals(Constants.SS_ANNOTATION_LABEL)
+ && aa.description != null && aa.description.equals(Constants.SS_ANNOTATION_LABEL))
+ {
+
+ return (Constants.SECONDARY_STRUCTURE_LABELS.get(aa.label));
+
+ }
+
+ // For other sources
+ if (aa.sequenceRef == null)
+ {
+ return null;
+ }
+ else if (aa.sequenceRef.getDatasetSequence() == null)
+ {
+ return null;
+ }
+ Vector<PDBEntry> pdbEntries = aa.sequenceRef.getDatasetSequence()
+ .getAllPDBEntries();
+
+ for (PDBEntry entry : pdbEntries)
+ {
+
+ String entryProvider = entry.getProvider();
+ if (entryProvider == null)
+ {
+ entryProvider = "PDB";
+ }
+
+ // Trim the string from first occurrence of colon
+ String entryID = entry.getId();
+ int index = entryID.indexOf(':');
+
+ // Check if colon exists
+ if (index != -1)
+ {
+
+ // Trim the string from first occurrence of colon
+ entryID = entryID.substring(0, index);
+
+ }
+
+ if (entryProvider == "PDB" && aa.description.toLowerCase()
+ .contains("secondary structure for "
+ + entryID.toLowerCase()))
+ {
+
+ return entryProvider;
+
+ }
+
+ else if (entryProvider != "PDB" && aa.description.toLowerCase()
+ .contains(entryID.toLowerCase()))
+ {
+
+ return entryProvider;
+
+ }
+
+ }
+ }
+ }
+
+ return null;
+
+ }
+
+ //to do set priority for labels
+ public static List<AlignmentAnnotation> getAlignmentAnnotationForSource(
+ SequenceI seq, String ssSource)
+ {
+
+ List<AlignmentAnnotation> ssAnnots = new ArrayList<AlignmentAnnotation>();
+ for (String ssLabel : Constants.SECONDARY_STRUCTURE_LABELS.keySet())
+ {
+
+ AlignmentAnnotation[] aa = seq.getAnnotation(ssLabel);
+ if (aa != null)
+ {
+
+ if (ssSource.equals(MessageManager.getString("option.ss_providers_all")))
+ {
+ ssAnnots.addAll(Arrays.asList(aa));
+ continue;
+ }
+
+ for (AlignmentAnnotation annot : aa)
+ {
+
+ String ssSourceForAnnot = extractSSSourceFromAnnotationDescription(annot);
+ if (ssSourceForAnnot != null && ssSource
+ .equals(ssSourceForAnnot))
+ {
+ ssAnnots.add(annot);
+ }
+ }
+ }
+ }
+ if (ssAnnots.size() > 0)
+ {
+ return ssAnnots;
+ }
+
+ return null;
+
+ }
+
+ public static Map<SequenceI, ArrayList<AlignmentAnnotation>> getSequenceAssociatedAlignmentAnnotations(
+ AlignmentAnnotation[] alignAnnotList, String selectedSSSource)
+ {
+
+ Map<SequenceI, ArrayList<AlignmentAnnotation>> ssAlignmentAnnotationForSequences
+ = new HashMap<SequenceI, ArrayList<AlignmentAnnotation>>();
+ if (alignAnnotList == null || alignAnnotList.length == 0)
+ {
+ return ssAlignmentAnnotationForSequences;
+ }
+
+ for (AlignmentAnnotation aa : alignAnnotList)
+ {
+ if (aa.sequenceRef == null)
+ {
+ continue;
+ }
+
+ for (String label : Constants.SECONDARY_STRUCTURE_LABELS.keySet())
+ {
+
+ if (label.equals(aa.label))
+ {
+
+ if (selectedSSSource.equals(MessageManager.getString("option.ss_providers_all")))
+ {
+ ssAlignmentAnnotationForSequences
+ .computeIfAbsent(aa.sequenceRef.getDatasetSequence(),
+ k -> new ArrayList<>())
+ .add(aa);
+ break;
+ }
+
+ String ssSource = AlignmentUtils
+ .extractSSSourceFromAnnotationDescription(aa);
+ if (ssSource != null && ssSource.equals(selectedSSSource))
+ {
+
+ ssAlignmentAnnotationForSequences
+ .computeIfAbsent(aa.sequenceRef.getDatasetSequence(),
+ k -> new ArrayList<>())
+ .add(aa);
+ break;
+ }
+ }
+ }
+ }
+
+ return ssAlignmentAnnotationForSequences;
+
+ }
+
}
return similarities;
}
+
}
public boolean isProtein()
{
return true;
- }
+ }
@Override
public String toString()
private final ScoreMatrix PAM250;
private final ScoreMatrix DNA;
+
+ private final ScoreMatrix SECONDARYSTRUCTURE;
private static ScoreModels instance;
* <li>PAM250</li>
* <li>PID</li>
* <li>DNA</li>
- * <li>Sequence Feature Similarity</li>
+ * <li>Sequence Feature Similarity</li> *
+ * <li>Secondary Structure Similarity</li>
* </ul>
*/
private ScoreModels()
DNA = loadScoreMatrix("scoreModel/dna.scm");
registerScoreModel(new PIDModel());
registerScoreModel(new FeatureDistanceModel());
+ SECONDARYSTRUCTURE = loadScoreMatrix("scoreModel/secondarystructure.scm");
+ registerScoreModel(new SecondaryStructureDistanceModel());
+
}
/**
public void registerScoreModel(ScoreModelI sm)
{
+ if(sm.getName().equals("SECONDARYSTRUCTURE")) {
+ return;
+ }
ScoreModelI sm2 = models.get(sm.getName());
if (sm2 != null)
{
{
return PAM250;
}
+
+ public ScoreMatrix getSecondaryStructureMatrix()
+ {
+ return SECONDARYSTRUCTURE;
+ }
}
--- /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.analysis.scoremodels;
+
+import jalview.analysis.AlignmentUtils;
+import jalview.api.AlignmentViewPanel;
+import jalview.api.FeatureRenderer;
+import jalview.api.analysis.ScoreModelI;
+import jalview.api.analysis.SimilarityParamsI;
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.AlignmentView;
+import jalview.datamodel.SeqCigar;
+import jalview.datamodel.SequenceI;
+import jalview.math.Matrix;
+import jalview.math.MatrixI;
+import jalview.util.MessageManager;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/* This class contains methods to calculate distance score between
+ * secondary structure annotations of the sequences.
+ */
+public class SecondaryStructureDistanceModel extends DistanceScoreModel
+{
+ private static final String NAME = "Secondary Structure Similarity";
+
+ private ScoreMatrix ssRateMatrix;
+
+ private String description;
+
+ FeatureRenderer fr;
+
+
+ /**
+ * Constructor
+ */
+ public SecondaryStructureDistanceModel()
+ {
+
+ }
+
+ @Override
+ public ScoreModelI getInstance(AlignmentViewPanel view)
+ {
+ SecondaryStructureDistanceModel instance;
+ try
+ {
+ instance = this.getClass().getDeclaredConstructor().newInstance();
+ instance.configureFromAlignmentView(view);
+ return instance;
+ } catch (InstantiationException | IllegalAccessException e)
+ {
+ jalview.bin.Console.errPrintln("Error in " + getClass().getName()
+ + ".getInstance(): " + e.getMessage());
+ return null;
+ } catch (ReflectiveOperationException roe)
+ {
+ return null;
+ }
+ }
+
+ boolean configureFromAlignmentView(AlignmentViewPanel view)
+
+ {
+ fr = view.cloneFeatureRenderer();
+ return true;
+ }
+
+ /**
+ * Calculates distance score [i][j] between each pair of protein sequences
+ * based on their secondary structure annotations (H, E, C).
+ * The final score is normalised by the number of
+ * alignment columns processed, providing an average similarity score.
+ * <p>
+ * The parameters argument can include settings for handling gap-residue aligned
+ * positions and may determine if the score calculation is based on the longer or shorter
+ * sequence in each pair. This can be important for handling partial alignments or
+ * sequences of significantly different lengths.
+ *
+ * @param seqData The aligned sequence data including secondary structure annotations.
+ * @param params Additional parameters for customising the scoring process, such as gap
+ * handling and sequence length consideration.
+ */
+ @Override
+ public MatrixI findDistances(AlignmentView seqData,
+ SimilarityParamsI params)
+ {
+
+ SeqCigar[] seqs = seqData.getSequences();
+ int noseqs = seqs.length; //no of sequences
+ int cpwidth = 0;
+ double[][] similarities = new double[noseqs][noseqs]; //matrix to store similarity score
+ //secondary structure source parameter selected by the user from the drop down.
+ String ssSource = params.getSecondaryStructureSource();
+ if(ssSource == null || ssSource == "") {
+ ssSource = MessageManager.getString("option.ss_providers_all");
+ }
+ ssRateMatrix = ScoreModels.getInstance().getSecondaryStructureMatrix();
+
+ // need to get real position for view position
+ int[] viscont = seqData.getVisibleContigs();
+
+
+ AlignmentAnnotation[] alignAnnotList = fr.getViewport().getAlignment()
+ .getAlignmentAnnotation();
+
+
+ /*
+ * Add secondary structure annotations that are added to the annotation track
+ * to the map
+ */
+ Map<SequenceI, ArrayList<AlignmentAnnotation>> ssAlignmentAnnotationForSequences
+ = AlignmentUtils.getSequenceAssociatedAlignmentAnnotations(alignAnnotList, ssSource);
+
+ /*
+ * scan each column, compute and add to each similarity[i, j]
+ * the number of secondary structure annotation that seqi
+ * and seqj do not share
+ */
+ for (int vc = 0; vc < viscont.length; vc += 2)
+ {
+ //Iterates for each column position
+ for (int cpos = viscont[vc]; cpos <= viscont[vc + 1]; cpos++)
+ {
+ cpwidth++; //used to normalise the similarity score
+
+ /*
+ * get set of sequences without gap in the current column
+ */
+ Set<SeqCigar> seqsWithoutGapAtCol = findSeqsWithoutGapAtColumn(seqs, cpos);
+
+ /*
+ * calculate similarity score for each secondary structure annotation on i'th and j'th
+ * sequence and add this measure to the similarities matrix
+ * for [i, j] for j > i
+ */
+ for (int i = 0; i < (noseqs - 1); i++)
+ {
+ //Iterates for each sequences
+ for (int j = i + 1; j < noseqs; j++)
+ {
+
+ //check if ss is defined
+ boolean undefinedSS1 = ssAlignmentAnnotationForSequences.get(seqs[i].getRefSeq()) == null;
+ boolean undefinedSS2 = ssAlignmentAnnotationForSequences.get(seqs[j].getRefSeq()) == null;
+
+ // Set similarity to max score if both SS are not defined
+ if (undefinedSS1 && undefinedSS2) {
+ similarities[i][j] += ssRateMatrix.getMaximumScore();
+ continue;
+ }
+
+ // Set similarity to minimum score if either one SS is not defined
+ else if(undefinedSS1 || undefinedSS2) {
+ similarities[i][j] += ssRateMatrix.getMinimumScore();
+ continue;
+ }
+
+ //check if the sequence contains gap in the current column
+ boolean gap1 = !seqsWithoutGapAtCol.contains(seqs[i]);
+ boolean gap2 = !seqsWithoutGapAtCol.contains(seqs[j]);
+
+ //Variable to store secondary structure at the current column
+ char ss1 = '*';
+ char ss2 = '*';
+
+ //secondary structure is fetched only if the current column is not
+ //gap for the sequence
+ if(!gap1 && !undefinedSS1) {
+ //fetch the position in sequence for the column and finds the
+ //corresponding secondary structure annotation
+ //TO DO - consider based on priority and displayed
+ int seqPosition = seqs[i].findPosition(cpos);
+ AlignmentAnnotation aa = ssAlignmentAnnotationForSequences.get(seqs[i].getRefSeq()).get(0);
+ if(aa!=null)
+ ss1 =
+ AlignmentUtils.findSSAnnotationForGivenSeqposition(aa, seqPosition);
+ }
+
+ if(!gap2 && !undefinedSS2) {
+ int seqPosition = seqs[j].findPosition(cpos);
+ AlignmentAnnotation aa = ssAlignmentAnnotationForSequences.get(seqs[j].getRefSeq()).get(0);
+ if(aa!=null)
+ ss2 =
+ AlignmentUtils.findSSAnnotationForGivenSeqposition(aa, seqPosition);
+ }
+
+ if ((!gap1 && !gap2) || params.includeGaps())
+ {
+ // Calculate similarity score based on the substitution matrix
+ double similarityScore = ssRateMatrix.getPairwiseScore(ss1, ss2);
+ similarities[i][j] += similarityScore;
+ }
+ }
+ }
+ }
+ }
+
+ /*
+ * normalise the similarity scores (summed over columns) by the
+ * number of visible columns used in the calculation
+ * and fill in the bottom half of the matrix
+ */
+ // TODO JAL-2424 cpwidth may be out by 1 - affects scores but not tree shape
+
+ for (int i = 0; i < noseqs; i++)
+ {
+ for (int j = i + 1; j < noseqs; j++)
+ {
+ similarities[i][j] /= cpwidth;
+ similarities[j][i] = similarities[i][j];
+ }
+ }
+ return ssRateMatrix.similarityToDistance(new Matrix(similarities));
+
+ }
+
+ /**
+ * Builds and returns a set containing sequences (SeqCigar) which do not
+ * have a gap at the given column position.
+ *
+ * @param seqs
+ * @param columnPosition
+ * (0..)
+ * @return
+ */
+ private Set<SeqCigar> findSeqsWithoutGapAtColumn(
+ SeqCigar[] seqs, int columnPosition)
+ {
+ Set<SeqCigar> seqsWithoutGapAtCol = new HashSet<>();
+ for (SeqCigar seq : seqs)
+ {
+ int spos = seq.findPosition(columnPosition);
+ if (spos != -1)
+ {
+ /*
+ * position is not a gap
+ */
+ seqsWithoutGapAtCol.add(seq);
+ }
+ }
+ return seqsWithoutGapAtCol;
+ }
+
+
+ @Override
+ public String getName()
+ {
+ return NAME;
+ }
+
+ @Override
+ public String getDescription()
+ {
+ return description;
+ }
+
+ @Override
+ public boolean isDNA()
+ {
+ return false;
+ }
+
+ @Override
+ public boolean isProtein()
+ {
+ return false;
+ }
+
+ @Override
+ public boolean isSecondaryStructure()
+ {
+ return true;
+ }
+
+ @Override
+ public String toString()
+ {
+ return "Score between sequences based on similarity between binary "
+ + "vectors marking secondary structure displayed at each column";
+ }
+}
\ No newline at end of file
private boolean includeGaps;
private boolean denominateByShortestLength;
+
+ private String secondaryStructureSource;
/**
* Constructor
}
return true;
}
+
+ @Override
+ public String getSecondaryStructureSource()
+ {
+ return secondaryStructureSource;
+ }
+
+ @Override
+ public void setSecondaryStructureSource(String secondaryStructureSource)
+ {
+ this.secondaryStructureSource = secondaryStructureSource;
+ }
}
boolean isValidCharWidth();
boolean isShowConsensusHistogram();
-
+
boolean isShowSequenceLogo();
-
+
boolean isNormaliseSequenceLogo();
ColourSchemeI getGlobalColourScheme();
* @return
*/
AlignmentAnnotation getAlignmentConsensusAnnotation();
+
+ List<AlignmentAnnotation> getAlignmentSecondaryStructureConsensusAnnotation();
+
/**
* get the container for alignment gap annotation
* @param hconsensus
*/
void setSequenceConsensusHash(ProfilesI hconsensus);
+
+ void setSequenceSSConsensusHash(Map<String, ProfilesI> hSSConsesnusProfileMap);
+
/**
* Set the cDNA complement consensus for the viewport
* @return contact matrix or NULL
*/
ContactMatrixI getContactMatrix(AlignmentAnnotation alignmentAnnotation);
+
+ Map<String, ProfilesI> getSequenceSSConsensusHash();
+
+ List<String> getSecondaryStructureSources();
+
+ void setSecondaryStructureSources(List<String> secondaryStructureSources);
+
}
package jalview.api;
import java.awt.Color;
+import java.util.List;
public interface ViewStyleI
{
* @return
*/
void setProteinFontAsCdna(boolean b);
+
+ void setSecondaryStructureSources(List<String> secondaryStructureSources);
+
+ List<String> getSecondaryStructureSources();
}
// TODO getName, isDNA, isProtein can be static methods in Java 8
+
+ default public boolean isSecondaryStructure()
+ {
+ return false;
+ }
+
+ /**
+ * Answers false by default
+ * Answers true if the data has secondary structure (so should be
+ * shown in menus in that context)
+ *
+ * @return
+ */
+
+
/**
* Returns a distance score for the given sequence regions, that is, a matrix
* whose value [i][j] is the distance of sequence i from sequence j by some
* @return
*/
boolean denominateByShortestLength();
+
+ String getSecondaryStructureSource();
+
+ void setSecondaryStructureSource(String secondaryStructureSource);
}
applyAutoAnnotationSettings.setState(true);
Menu autoAnnMenu = new Menu(
MessageManager.getString("label.autocalculated_annotation"));
+
+ Menu selectSS = new Menu(
+ MessageManager.getString("label.select_secondary_structure_source"));
showGroupConsensus.addItemListener(this);
showGroupConservation.addItemListener(this);
showConsensusHistogram.addItemListener(this);
* 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
public Hashtable alignmentProperties;
private List<AlignedCodonFrame> codonFrameList;
-
+
private void initAlignment(SequenceI[] seqs)
{
groups = Collections.synchronizedList(new ArrayList<SequenceGroup>());
nucleotide = Comparison.isNucleotide(seqs);
sequences = Collections.synchronizedList(new ArrayList<SequenceI>());
+
for (int i = 0; i < seqs.length; i++)
{
sequences.add(seqs[i]);
}
-
+
}
/**
cmholder.addContactListFor(annotation, cm);
}
+
}
public static final int CDNA_PROFILE = 2;
private static long counter = 0;
+
+ private long noOfSequencesIncluded = -1;
/**
* If true, this annotations is calculated every edit, eg consensus, quality
showGroups ? "" : "nogroups");
}
+ public long getNoOfSequencesIncluded()
+ {
+ return noOfSequencesIncluded;
+ }
+
+ public void setNoOfSequencesIncluded(long noOfSequencesIncluded)
+ {
+ this.noOfSequencesIncluded = noOfSequencesIncluded;
+ }
+
}
private static final String MODELPAGE = "PROVIDERPAGE";
+ private static final String PROVIDERCATEGORY = "PROVIDERCATEGORY";
+
/**
* Permanent URI for retrieving the original structure data
*
{
return sf != null && sf.inFile != null && sf.inFile.exists();
}
+
+ public void setProviderCategory(String providerCategory)
+ {
+ setProperty(PROVIDERCATEGORY, providerCategory);
+ }
+
+ public String getProviderCategory()
+ {
+ return (String) getProperty(PROVIDERCATEGORY);
+ }
+
+ public boolean hasProviderCategory()
+ {
+ return _hasProperty(PROVIDERCATEGORY);
+ }
+
}
* an object holding counts of symbols in the profile
*/
private ResidueCount counts;
+
+ private SecondaryStructureCount ssCounts;
+
+ private int seqWithSSCount = -1;
/*
* 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, int seqWithSSCount)
+ {
+ this.height = ssCount;
+ this.gapped = gaps;
+ this.maxSSCount = maxSSCount;
+ this.modalSS = modalSS;
+ this.setSeqWithSSCount(seqWithSSCount);
+ }
/* (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()
{
return height - gapped;
}
+
+ public int getSeqWithSSCount()
+ {
+ return seqWithSSCount;
+ }
+
+ public void setSeqWithSSCount(int seqWithSSCount)
+ {
+ this.seqWithSSCount = seqWithSSCount;
+ }
}
* @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 getHeight();
+
+ public abstract int getSeqWithSSCount();
/**
* Returns the number of sequences in the profile which had a gap character
* @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();
+ }
+}
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
import jalview.analysis.AAFrequency;
+import jalview.analysis.AlignmentUtils;
import jalview.analysis.Conservation;
import jalview.renderer.ResidueShader;
import jalview.renderer.ResidueShaderI;
import jalview.schemes.ColourSchemeI;
+import jalview.util.MessageManager;
/**
* Collects a set contiguous ranges on a set of sequences
* 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;
+
+
+ List<AlignmentAnnotation> ssConsensus = null;
AlignmentAnnotation conservation = null;
private boolean showConsensusHistogram;
+
+ private boolean showSSConsensusHistogram;
private AnnotatedCollectionI context;
+
+ public Map<String, ProfilesI> hSSConsensusProfileMap;
/**
* Creates a new SequenceGroup object.
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;
}
+
+ hSSConsensusProfileMap = new HashMap<String, ProfilesI>();
+ List <String> ssSources = new ArrayList<String>();
+ AnnotatedCollectionI aa = this.getContext();
+
+ if(aa !=null )
+ {
+ ssSources = AlignmentUtils.extractSSSourceInAlignmentAnnotation(aa.getAlignmentAnnotation());
+ }
+ if(ssSources != null) {
+ ssSources.add(MessageManager.getString("option.ss_providers_all"));
+
+ for(String ssSource : ssSources) {
+ ProfilesI hSSConsensus = AAFrequency.calculateSS(sequences, startRes, endRes + 1, showSequenceLogo,
+ ssSource);
+ hSSConsensusProfileMap.put(ssSource, hSSConsensus);
+ }
+ }
+
+
+ if (ssConsensus != null)
+ {
+ _updateSSConsensusRow(hSSConsensusProfileMap, sequences.size());
+ upd = true;
+ }
+
+ if (cs != null)
+ {
+ cs.setSSConsensusProfileMap(hSSConsensusProfileMap);
+ upd = true;
+ }
+
if ((conservation != null)
|| (cs != null && cs.conservationApplied()))
// for
// ignoreGapsInConsensusCalculation);
}
+
+ public ProfilesI ssConsensusData = null;
+
+ private void _updateSSConsensusRow(Map<String, ProfilesI> hSSConsensusProfileMap, long nseq)
+ {
+ List<String> ssSources = new ArrayList<>(hSSConsensusProfileMap.keySet());
+
+ Collections.sort(ssSources);
+ if (ssConsensus == null)
+ {
+ getSSConsensus(ssSources);
+ }
+ for (AlignmentAnnotation aa : ssConsensus) {
+ ProfilesI profile = null;
+ String ssSource = null;
+ for(String source : ssSources) {
+ if(aa.description.startsWith(source)) {
+ profile = hSSConsensusProfileMap.get(source);
+ ssSource = source;
+ }
+ }
+ if(profile == null) {
+ continue;
+ }
+
+ aa.label = MessageManager.getString("label.ssconsensus_label") + " " + ssSource + " " + getName();
+ aa.description = ssSource + MessageManager.getString("label.ssconsensus_label") +" for " + getName();
+ ssConsensusData = profile;
+ // preserve width if already set
+ int aWidth = (aa.annotations != null)
+ ? (endRes < aa.annotations.length
+ ? aa.annotations.length
+ : endRes + 1)
+ : endRes + 1;
+ aa.annotations = null;
+ aa.annotations = new Annotation[aWidth]; // should be alignment width
+
+ AAFrequency.completeSSConsensus(aa, profile, startRes, endRes + 1,
+ ignoreGapsInConsensus, showSequenceLogo, nseq); // TODO: setting
+ // container
+ }
+ // for
+ // ignoreGapsInConsensusCalculation);
+ }
/**
* @param s
}
return consensus;
}
+
+ public List<AlignmentAnnotation> getSSConsensus(List<String> ssSources)
+ {
+ // 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 && ssSources!=null)
+ {
+ ssConsensus = new ArrayList<AlignmentAnnotation>();
+
+ for(String ssSource : ssSources) {
+ AlignmentAnnotation aa = new AlignmentAnnotation("", "", new Annotation[1], 0f,
+ 100f, AlignmentAnnotation.BAR_GRAPH);
+ aa.hasText = true;
+ aa.autoCalculated = true;
+ aa.groupRef = this;
+
+ aa.label = MessageManager.getString("label.ssconsensus_label") + " " + ssSource + " " + getName();
+ aa.description = ssSource + MessageManager.getString("label.ssconsensus_label") +" for " + getName();
+ ssConsensus.add(aa);
+ }
+
+ }
+ 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
import java.util.Arrays;
import java.util.Deque;
import java.util.Enumeration;
+import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import java.util.Locale;
+import java.util.Map;
import java.util.Vector;
import javax.swing.ButtonGroup;
import jalview.schemes.ColourSchemes;
import jalview.schemes.ResidueColourScheme;
import jalview.schemes.TCoffeeColourScheme;
+import jalview.util.Constants;
import jalview.util.HttpUtils;
import jalview.util.ImageMaker.TYPE;
import jalview.util.MessageManager;
}
ap.av.updateConservation(ap);
ap.av.updateConsensus(ap);
+ ap.av.updateSecondaryStructureConsensus(ap);
ap.av.updateStrucConsensus(ap);
}
}
viewport.setShowUnconserved(showNonconservedMenuItem.getState());
alignPanel.paintAlignment(false, false);
}
+
+ @Override
+ protected void updateShowSecondaryStructureMenu(JMenu showSS, ButtonGroup ssButtonGroup){
+
+ List<String> ssSources = new ArrayList<String>();
+ AlignmentAnnotation[] anns = alignPanel.getAlignment()
+ .getAlignmentAnnotation();
+ Map<String, JCheckBoxMenuItem> checkboxMap = getCheckboxesInMenu(showSS);
+
+ ssSources = AlignmentUtils.extractSSSourceInAlignmentAnnotation(anns);
+
+ if(ssSources == null) {
+ showSS.removeAll();
+ ssButtonGroup.clearSelection();
+ return;
+ }
+
+ List<String> selectedCheckBoxes = getSelectedOptions(checkboxMap);
+
+ // Add checkboxes for categories
+ for (String ssSource : ssSources) {
+
+ if(checkboxMap.get(ssSource)== null) {
+ JCheckBoxMenuItem checkBox = new JCheckBoxMenuItem(ssSource);
+ checkBox.setSelected(false);
+
+ checkBox.addItemListener(e -> {
+ if (e.getStateChange() == ItemEvent.SELECTED) {
+
+ showOrHideSecondaryStructureForSource(ssSource, true);
+
+ } else {
+
+ showOrHideSecondaryStructureForSource(ssSource, false);
+
+ }
+ });
+ showSS.add(checkBox);
+ }
+ }
+ // Iterate over the keys of checkboxMap
+ for (String key : checkboxMap.keySet()) {
+ // Check if the key is not in ssSources
+ if (!ssSources.contains(key)) {
+ showSS.remove(checkboxMap.get(key));
+ checkboxMap.remove(key);
+ selectedCheckBoxes.remove(key);
+ }
+ if(selectedCheckBoxes.contains(key)){
+ checkboxMap.get(key).setSelected(true);
+ }
+ else {
+ checkboxMap.get(key).setSelected(false);
+ }
+
+ ssButtonGroup.clearSelection();
+ }
+
+ }
+
+ private List<String> getSelectedOptions(Map<String, JCheckBoxMenuItem> checkboxMap) {
+ List<String> selectedOptions = new ArrayList<>();
+ for (String key : checkboxMap.keySet()) {
+ JCheckBoxMenuItem checkbox = checkboxMap.get(key);
+ if (checkbox.isSelected()) {
+ selectedOptions.add(key);
+ }
+ }
+ return selectedOptions;
+ }
+
+ private Map<String, JCheckBoxMenuItem> getCheckboxesInMenu(JMenu menu) {
+ Map<String, JCheckBoxMenuItem> checkboxMap = new HashMap<>();
+ for (Component component : menu.getMenuComponents()) {
+ if (component instanceof JCheckBoxMenuItem) {
+ JCheckBoxMenuItem checkbox = (JCheckBoxMenuItem) component;
+ checkboxMap.put(checkbox.getText(), checkbox);
+ }
+ }
+ return checkboxMap;
+}
+
+ @Override
+ protected void showOrHideSecondaryStructureForSource(String ssSourceSelection, boolean visible){
+
+ String noneOption = MessageManager.getString("option.ss_providers_none");
+ String allOption = MessageManager.getString("option.ss_providers_all");
+
+ AlignmentAnnotation[] annotations = alignPanel.getAlignment()
+ .getAlignmentAnnotation();
+
+ for (AlignmentAnnotation aa: annotations) {
+
+ boolean isSSConsensus = aa.label.startsWith(MessageManager.getString("label.ssconsensus_label"));
+ boolean matchesSSSourceSelection = aa.description.startsWith(ssSourceSelection);
+
+ if(isSSConsensus && (matchesSSSourceSelection || ssSourceSelection.equals(noneOption))) {
+
+ if (ssSourceSelection.equals(allOption)) {
+ aa.visible = true;
+ break;
+ }
+
+ if(!aa.description.startsWith(allOption))
+ aa.visible = visible;
+
+ }
+
+ for (String label : Constants.SECONDARY_STRUCTURE_LABELS.keySet()) {
+
+ if (label.equals(aa.label)) {
+
+ String ssSource = AlignmentUtils.extractSSSourceFromAnnotationDescription(aa);
+
+ if(ssSource != null && (ssSource.equals(ssSourceSelection) || ssSourceSelection.equals(noneOption))) {
+ aa.visible = visible;
+ }
+ }
+ }
+
+ }
+
+ PaintRefresher.Refresh(this, viewport.getSequenceSetId());
+ alignPanel.updateAnnotation();
+ alignPanel.paintAlignment(true, true);
+
+ }
+
+ protected void showSSConsensus_actionPerformed(ActionEvent e)
+ {
+ viewport.setShowSSConsensus(showSSConsensus.getState());
+ alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
+
+ }
+
/*
* (non-Javadoc)
}
+ @Override
+ protected void showGroupSSConsensus_actionPerformed(ActionEvent e)
+ {
+ viewport.setShowGroupSSConsensus(showGroupSSConsensus.getState());
+ alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
+
+ }
/*
* (non-Javadoc)
*
viewport.setShowConsensusHistogram(showConsensusHistogram.getState());
alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
}
-
+
/*
* (non-Javadoc)
*
}
showConsensusHistogram = Cache.getDefault("SHOW_CONSENSUS_HISTOGRAM",
true);
- showSequenceLogo = Cache.getDefault("SHOW_CONSENSUS_LOGO", false);
+ showSequenceLogo = Cache.getDefault("SHOW_CONSENSUS_LOGO", true);
normaliseSequenceLogo = Cache.getDefault("NORMALISE_CONSENSUS_LOGO",
false);
showGroupConsensus = Cache.getDefault("SHOW_GROUP_CONSENSUS", false);
showConsensus = Cache.getDefault("SHOW_IDENTITY", true);
+
+ showSSConsensus = Cache.getDefault("SHOW_SS_CONSENSUS", false);
showOccupancy = Cache.getDefault(Preferences.SHOW_OCCUPANCY, true);
}
if (residueShading != null)
{
residueShading.setConsensus(hconsensus);
+ residueShading.setSSConsensusProfileMap(hSSConsensusProfileMap);
}
setColourAppliesToAllGroups(true);
}
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
+import java.util.List;
import java.util.Locale;
import javax.swing.JCheckBoxMenuItem;
import jalview.analysis.AlignSeq;
import jalview.analysis.AlignmentUtils;
+import jalview.api.AlignCalcWorkerI;
import jalview.bin.Cache;
import jalview.bin.Jalview;
import jalview.datamodel.Alignment;
import jalview.io.FileFormat;
import jalview.io.FormatAdapter;
import jalview.util.Comparison;
+import jalview.util.Constants;
import jalview.util.MessageManager;
import jalview.util.Platform;
+import jalview.workers.SecondaryStructureConsensusThread;
/**
* The panel that holds the labels for alignment annotations, providing
{
ap.av.getAlignment().deleteAnnotation(aa[selectedRow]);
ap.av.getCalcManager().removeWorkerForAnnotation(aa[selectedRow]);
+
+
+ List<AlignCalcWorkerI> workers = ap.av.getCalcManager()
+ .getRegisteredWorkersOfClass(SecondaryStructureConsensusThread.class);
+ if (!workers.isEmpty()) {
+
+ ap.alignFrame.getViewport().getCalcManager().startWorker(workers.remove(0));
+
+ }
}
else if (SHOWALL.equals(action))
{
{
msg.append(aa.sequenceRef.getName()).append(" : ");
}
-
+
if (aa.graphGroup == -1)
{
msg.append(aa.label);
+ if(aa.getNoOfSequencesIncluded()>=0)
+ {
+ msg.append(" (");
+ msg.append(MessageManager.getString("label.sequence_count"));
+ msg.append(aa.getNoOfSequencesIncluded());
+ msg.append(")");
+ }
}
+
else if (anns != null)
{
boolean first = true;
// jalview.gui.SeqPanel.mouseMoved(..) that formats sequence feature
// tooltips
String desc = aa.getDescription(true).trim();
+ if(aa.getNoOfSequencesIncluded()>=0) {
+ desc += " (" + MessageManager.getString("label.sequence_count")
+ + aa.getNoOfSequencesIncluded()
+ + ")";
+ }
if (!desc.toLowerCase(Locale.ROOT).startsWith(HTML_START_TAG))
{
tooltip.append(HTML_START_TAG);
import javax.swing.event.InternalFrameAdapter;
import javax.swing.event.InternalFrameEvent;
+import jalview.analysis.AlignmentUtils;
import jalview.analysis.TreeBuilder;
import jalview.analysis.scoremodels.ScoreModels;
import jalview.analysis.scoremodels.SimilarityParams;
import jalview.api.analysis.ScoreModelI;
import jalview.api.analysis.SimilarityParamsI;
import jalview.bin.Cache;
+import jalview.datamodel.AlignmentAnnotation;
import jalview.datamodel.SequenceGroup;
import jalview.util.MessageManager;
private static final int MIN_TREE_SELECTION = 3;
private static final int MIN_PCA_SELECTION = 4;
+
+ private String secondaryStructureModelName;
+
+ private void getSecondaryStructureModelName() {
+
+ ScoreModels scoreModels = ScoreModels.getInstance();
+ for (ScoreModelI sm : scoreModels.getModels())
+ {
+ if (sm.isSecondaryStructure())
+ {
+ secondaryStructureModelName = sm.getName();
+ }
+ }
+
+ }
AlignFrame af;
JRadioButton averageDistance;
JComboBox<String> modelNames;
+
+ JComboBox<String> ssSourceDropdown;
JButton calculate;
this.af = alignFrame;
init();
af.alignPanel.setCalculationDialog(this);
+
}
/**
*/
void init()
{
+ getSecondaryStructureModelName();
setLayout(new BorderLayout());
frame = new JInternalFrame();
frame.setFrameIcon(null);
pca.addActionListener(calcChanged);
neighbourJoining.addActionListener(calcChanged);
averageDistance.addActionListener(calcChanged);
+
+
+ //to do
+ ssSourceDropdown = buildSSSourcesOptionsList();
+ ssSourceDropdown.setVisible(false); // Initially hide the dropdown
/*
* score models drop-down - with added tooltips!
*/
modelNames = buildModelOptionsList();
+
+ // Step 3: Show or Hide Dropdown Based on Selection
+ modelNames.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ String selectedModel = modelNames.getSelectedItem().toString();
+
+ if (selectedModel.equals(secondaryStructureModelName)) {
+ ssSourceDropdown.setVisible(true);
+ } else {
+ ssSourceDropdown.setVisible(false);
+ }
+ }
+ });
+
JPanel scoreModelPanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
scoreModelPanel.setOpaque(false);
scoreModelPanel.add(modelNames);
-
+ scoreModelPanel.add(ssSourceDropdown);
+
/*
* score model parameters
*/
paramsPanel.add(matchGaps);
paramsPanel.add(includeGappedColumns);
paramsPanel.add(shorterSequence);
-
+
/*
* OK / Cancel buttons
*/
}
this.add(actionPanel, BorderLayout.SOUTH);
- int width = 350;
+ int width = 375;
int height = includeParams ? 420 : 240;
setMinimumSize(new Dimension(325, height - 10));
return scoreModelsCombo;
}
+
+
+ private JComboBox<String> buildSSSourcesOptionsList()
+ {
+ final JComboBox<String> comboBox = new JComboBox<>();
+ Object curSel = comboBox.getSelectedItem();
+ DefaultComboBoxModel<String> sourcesModel = new DefaultComboBoxModel<>();
+
+ List<String> ssSources = getApplicableSecondaryStructureSources();
+
+ if(ssSources == null) {
+ return comboBox;
+ }
+ ssSources.add(0, MessageManager.getString("option.ss_providers_all"));
+ boolean selectedIsPresent = false;
+ for (String source : ssSources)
+ {
+ if (curSel != null && source.equals(curSel))
+ {
+ selectedIsPresent = true;
+ curSel = source;
+ }
+ sourcesModel.addElement(source);
+
+ }
+
+ if (selectedIsPresent)
+ {
+ sourcesModel.setSelectedItem(curSel);
+ }
+ comboBox.setModel(sourcesModel);
+
+ return comboBox;
+ }
+
+
private void updateScoreModels(JComboBox<String> comboBox,
List<String> toolTips)
{
* select the score models applicable to the alignment type
*/
boolean nucleotide = af.getViewport().getAlignment().isNucleotide();
- List<ScoreModelI> models = getApplicableScoreModels(nucleotide,
- pca.isSelected());
+ AlignmentAnnotation[] alignmentAnnotations = af.getViewport().getAlignment().getAlignmentAnnotation();
+
+ boolean ssPresent = AlignmentUtils.isSecondaryStructurePresent(alignmentAnnotations);
+
+ List<ScoreModelI> models = getApplicableScoreModels(nucleotide, pca.isSelected(),
+ ssPresent);
/*
* now we can actually add entries to the combobox,
}
// finally, update the model
comboBox.setModel(model);
+
}
/**
* @return
*/
protected static List<ScoreModelI> getApplicableScoreModels(
- boolean nucleotide, boolean forPca)
+ boolean nucleotide, boolean forPca, boolean ssPresent)
{
List<ScoreModelI> filtered = new ArrayList<>();
ScoreModels scoreModels = ScoreModels.getInstance();
for (ScoreModelI sm : scoreModels.getModels())
{
- if (!nucleotide && sm.isProtein() || nucleotide && sm.isDNA())
+ if (!nucleotide && sm.isProtein() || nucleotide && sm.isDNA()
+ || ssPresent && sm.isSecondaryStructure())
{
filtered.add(sm);
}
{
filtered.add(scoreModels.getBlosum62());
}
-
+
return filtered;
}
+
+ protected List<String> getApplicableSecondaryStructureSources()
+ {
+ AlignmentAnnotation[] annotations = af.getViewport().getAlignment().getAlignmentAnnotation();
+
+ //List<String> ssSources = AlignmentUtils.getSecondaryStructureSources(annotations);
+ List<String> ssSources = AlignmentUtils.extractSSSourceInAlignmentAnnotation(annotations);
+
+
+ return ssSources;
+ }
+
/**
* Open and calculate the selected tree or PCA on 'OK'
*/
{
boolean doPCA = pca.isSelected();
String modelName = modelNames.getSelectedItem().toString();
- SimilarityParamsI params = getSimilarityParameters(doPCA);
+ String ssSource = null;
+
+ if (modelName.equals(secondaryStructureModelName)) {
+ Object selectedItem = ssSourceDropdown.getSelectedItem();
+ if (selectedItem != null) {
+ ssSource = selectedItem.toString();
+ }
+ }
+ SimilarityParams params = getSimilarityParameters(doPCA);
+ params.setSecondaryStructureSource(ssSource);
+
if (doPCA)
{
openPcaPanel(modelName, params);
* @param doPCA
* @return
*/
- protected SimilarityParamsI getSimilarityParameters(boolean doPCA)
+ protected SimilarityParams getSimilarityParameters(boolean doPCA)
{
// commented out: parameter choices read from gui widgets
// SimilarityParamsI params = new SimilarityParams(
import java.awt.print.PrinterJob;
import javax.swing.ButtonGroup;
+import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JRadioButtonMenuItem;
+import javax.swing.SwingConstants;
import javax.swing.event.InternalFrameAdapter;
import javax.swing.event.InternalFrameEvent;
PaintRefresher.Register(this, av.getSequenceSetId());
setRotatableCanvas(new RotatableCanvas(alignPanel));
+
+ if(params.getSecondaryStructureSource()!=null ) {
+ // Initialize and set subtitle text
+ JLabel subtitleLabel = new JLabel(" Secondary Structure Provider : "
+ + params.getSecondaryStructureSource(), SwingConstants.LEFT);
+ this.getContentPane().add(subtitleLabel, BorderLayout.NORTH);
+
+ }
this.getContentPane().add(getRotatableCanvas(), BorderLayout.CENTER);
addKeyListener(getRotatableCanvas());
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);
- refresh();
+
+ if(AlignmentUtils.isSSAnnotationPresent(candidates)) {
+
+ restartSSConsensusWorker();
+ ap.validateAnnotationDimensions(true);
+ ap.fontChanged();
+ ap.av.alignmentChanged(ap);
+ ap.adjustAnnotationHeight();
+ restartSSConsensusWorker();
+ //ap.alignFrame.getViewport().getCalcManager().restartWorkers();
+ }
+
+ }
+
+
+ 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)
{
conservation.setSelected(Cache.getDefault("SHOW_CONSERVATION", true));
quality.setSelected(Cache.getDefault("SHOW_QUALITY", true));
identity.setSelected(Cache.getDefault("SHOW_IDENTITY", true));
+ ssConsensus.setSelected(Cache.getDefault("SHOW_SS_CONSENSUS", false));
openoverv.setSelected(Cache.getDefault("SHOW_OVERVIEW", false));
showUnconserved
.setSelected(Cache.getDefault("SHOW_UNCONSERVED", false));
Cache.applicationProperties.setProperty("SHOW_IDENTITY",
Boolean.toString(identity.isSelected()));
+ Cache.applicationProperties.setProperty("SHOW_SS_CONSENSUS",
+ Boolean.toString(ssConsensus.isSelected()));
+
Cache.applicationProperties.setProperty("GAP_SYMBOL",
gapSymbolCB.getSelectedItem().toString());
conservation.setEnabled(annotations.isSelected());
quality.setEnabled(annotations.isSelected());
identity.setEnabled(annotations.isSelected());
+ ssConsensus.setEnabled(annotations.isSelected());
showOccupancy.setEnabled(annotations.isSelected());
showGroupConsensus.setEnabled(annotations.isSelected());
showGroupConservation.setEnabled(annotations.isSelected());
*/
package jalview.gui;
+import java.awt.BorderLayout;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.util.Locale;
import javax.swing.ButtonGroup;
+import javax.swing.JLabel;
import javax.swing.JMenuItem;
+import javax.swing.JPanel;
import javax.swing.JRadioButtonMenuItem;
+import javax.swing.SwingConstants;
import javax.swing.event.InternalFrameAdapter;
import javax.swing.event.InternalFrameEvent;
TreeModel tree;
private AlignViewport av;
+
+
+ // New JLabel for subtitle
+ private JLabel subtitleLabel;
/**
* Creates a new TreePanel object.
treeCanvas = new TreeCanvas(this, ap, scrollPane);
scrollPane.setViewportView(treeCanvas);
+
+ if(this.similarityParams!=null)
+ if(this.similarityParams.getSecondaryStructureSource()!=null ) {
+
+ subtitleLabel = new JLabel(" Secondary Structure Provider : "
+ + this.similarityParams.getSecondaryStructureSource(), SwingConstants.LEFT);
+
+ JPanel panel = new JPanel(new BorderLayout());
+ panel.add(subtitleLabel, BorderLayout.NORTH);
+ panel.add(scrollPane, BorderLayout.CENTER);
+
+ this.add(panel);
+ }
if (columnWise)
{
int typeColumnIndex = restable.getColumn("Provider").getModelIndex();
int humanUrl = restable.getColumn("Page URL").getModelIndex();
int modelformat = restable.getColumn("Model Format").getModelIndex();
+ int idx_mcat = restable.getColumn("Model Category").getModelIndex();
+
final int up_start_idx = restable.getColumn("Uniprot Start")
.getModelIndex();
final int up_end_idx = restable.getColumn("Uniprot End")
.toString();
String modelPage = humanUrl < 1 ? null
: (String) restable.getValueAt(row, humanUrl);
+
+ String modelCategory = idx_mcat < 1 ? null :(String) restable.getValueAt(row,idx_mcat);
+
String strucFormat = restable.getValueAt(row, modelformat).toString();
SequenceI selectedSeq = (SequenceI) restable.getValueAt(row,
{
pdbEntry.setProviderPage(modelPage);
}
+ pdbEntry.setProviderCategory(modelCategory);
selectedSeq.getDatasetSequence().addPDBId(pdbEntry);
}
pdbEntriesToView[count++] = pdbEntry;
import java.awt.BorderLayout;
import java.awt.Color;
+import java.awt.Component;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import javax.swing.BorderFactory;
protected JMenuItem gatherViews = new JMenuItem();
protected JMenuItem expandViews = new JMenuItem();
+
+ protected JCheckBoxMenuItem showSSConsensus = new JCheckBoxMenuItem();
+ protected JCheckBoxMenuItem showGroupSSConsensus = new JCheckBoxMenuItem();
+
protected JCheckBoxMenuItem showGroupConsensus = new JCheckBoxMenuItem();
protected JCheckBoxMenuItem showGroupConservation = new JCheckBoxMenuItem();
- protected JCheckBoxMenuItem showConsensusHistogram = new JCheckBoxMenuItem();
+ protected JCheckBoxMenuItem showConsensusHistogram = new JCheckBoxMenuItem();
protected JCheckBoxMenuItem showSequenceLogo = new JCheckBoxMenuItem();
});
+ showSSConsensus
+ .setText(MessageManager.getString("label.show_secondary_structure_consensus"));
+ showSSConsensus.addActionListener(new ActionListener()
+ {
+
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ showSSConsensus_actionPerformed(e);
+ }
+
+ });
+
+ showGroupSSConsensus
+ .setText(MessageManager.getString("label.group_ss_consensus"));
+ showGroupSSConsensus.addActionListener(new ActionListener()
+ {
+
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ showGroupSSConsensus_actionPerformed(e);
+ }
+
+ });
+
showGroupConsensus
.setText(MessageManager.getString("label.group_consensus"));
showGroupConsensus.addActionListener(new ActionListener()
showConsensusHistogram_actionPerformed(e);
}
- });
+ });
showSequenceLogo
.setText(MessageManager.getString("label.show_consensus_logo"));
showSequenceLogo.addActionListener(new ActionListener()
addMenuActionAndAccelerator(keyStroke, copyHighlighted, al);
copyHighlighted.addActionListener(al);
+ ButtonGroup ssButtonGroup = new ButtonGroup();
+
JMenu tooltipSettingsMenu = new JMenu(
MessageManager.getString("label.sequence_id_tooltip"));
JMenu autoAnnMenu = new JMenu(
MessageManager.getString("label.autocalculated_annotation"));
+ JMenu showSS = new JMenu(
+ MessageManager.getString("label.show_secondary_structure"));
+
+ JRadioButtonMenuItem radioButtonAllSS = new JRadioButtonMenuItem(MessageManager.getString("option.ss_providers_all"));
+ radioButtonAllSS.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ showOrHideSecondaryStructureForSource(MessageManager.getString("option.ss_providers_all"), true);
+ // Select all checkboxes if "All" is selected
+ Component[] components = showSS.getMenuComponents();
+ for (Component component : components) {
+ if (component instanceof JCheckBoxMenuItem) {
+ ((JCheckBoxMenuItem) component).setSelected(true);
+ }
+ }
+ }
+ });
+ ssButtonGroup.add(radioButtonAllSS);
+ showSS.add(radioButtonAllSS);
+
+ JRadioButtonMenuItem radioButtonNoneSS = new JRadioButtonMenuItem(MessageManager.getString("option.ss_providers_none"));
+ radioButtonNoneSS.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ showOrHideSecondaryStructureForSource(MessageManager.getString("option.ss_providers_none"), false);
+ // Remove selection of all checkboxes if "None" is selected
+ Component[] components = showSS.getMenuComponents();
+ for (Component component : components) {
+ if (component instanceof JCheckBoxMenuItem) {
+ ((JCheckBoxMenuItem) component).setSelected(false);
+ }
+ }
+ }
+ });
+ ssButtonGroup.add(radioButtonNoneSS);
+ showSS.add(radioButtonNoneSS);
+ showSS.addSeparator();
+
+ annotationsMenu.addMouseListener(new MouseAdapter() {
+
+ @Override
+ public void mouseEntered(MouseEvent e) {
+
+ updateShowSecondaryStructureMenu(showSS, ssButtonGroup); // Update radio buttons every time the menu is clicked
+
+ }
+ });
+
JMenu exportImageMenu = new JMenu(
MessageManager.getString("label.export_image"));
JMenu fileMenu = new JMenu(MessageManager.getString("action.file"));
annotationsMenu.add(sortAnnBySequence);
annotationsMenu.add(sortAnnByLabel);
annotationsMenu.addSeparator();
+ annotationsMenu.add(showSS);
+ annotationsMenu.addSeparator();
autoAnnMenu.add(showAutoFirst);
autoAnnMenu.add(showAutoLast);
autoAnnMenu.addSeparator();
autoAnnMenu.add(showConsensusHistogram);
autoAnnMenu.add(showSequenceLogo);
autoAnnMenu.add(normaliseSequenceLogo);
+ //autoAnnMenu.add(showSSConsensus);
autoAnnMenu.addSeparator();
autoAnnMenu.add(showGroupConservation);
autoAnnMenu.add(showGroupConsensus);
+ autoAnnMenu.add(showGroupSSConsensus);
annotationsMenu.add(autoAnnMenu);
sort.add(sortIDMenuItem);
// selectMenu.add(listenToViewSelections);
}
+ protected void showSSConsensus_actionPerformed(ActionEvent e)
+ {
+ // TODO Auto-generated method stub
+
+ }
+
protected void createPNG_actionPerformed(ActionEvent object)
{
// TODO Auto-generated method stub
// TODO Auto-generated method stub
}
+
+ protected void showGroupSSConsensus_actionPerformed(ActionEvent e)
+ {
+ // TODO Auto-generated method stub
+
+ }
protected void showGroupConservation_actionPerformed(ActionEvent e)
{
}
- protected void jpred_actionPerformed(ActionEvent e)
- {
- }
-
protected void scaleAbove_actionPerformed(ActionEvent e)
{
}
protected void showComplement_actionPerformed(boolean complement)
{
}
+
+ protected List<String> updateShowSSRadioButtons()
+ {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ protected void showOrHideSecondaryStructureForSource(String ssSourceSelection, boolean visible)
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+ protected void updateShowSecondaryStructureMenu(JMenu showSS,
+ ButtonGroup ssButtonGroup)
+ {
+ // TODO Auto-generated method stub
+
+ }
}
protected JCheckBox conservation = new JCheckBox();
- protected JCheckBox identity = new JCheckBox();
+ protected JCheckBox identity = new JCheckBox();
+
+ protected JCheckBox ssConsensus = new JCheckBox();
protected JCheckBox showGroupConsensus = new JCheckBox();
identity.setHorizontalTextPosition(SwingConstants.LEFT);
identity.setSelected(true);
identity.setText(MessageManager.getString("label.consensus"));
+ ssConsensus.setEnabled(false);
+ ssConsensus.setFont(LABEL_FONT);
+ ssConsensus.setHorizontalAlignment(SwingConstants.RIGHT);
+ ssConsensus.setHorizontalTextPosition(SwingConstants.LEFT);
+ ssConsensus.setSelected(false);
+ ssConsensus.setText(MessageManager.getString("label.ssConsensus"));
showOccupancy.setFont(LABEL_FONT);
showOccupancy.setEnabled(false);
showOccupancy.setHorizontalAlignment(SwingConstants.RIGHT);
sortAutocalc.setBounds(new Rectangle(290, 285, 165, 21));
JPanel annsettingsPanel = new JPanel();
- annsettingsPanel.setBounds(new Rectangle(173, 13, 320, 96));
+ annsettingsPanel.setBounds(new Rectangle(173, 13, 320, 101));
annsettingsPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
annsettingsPanel.setBorder(new EtchedBorder());
visualTab.add(annsettingsPanel);
quality.setBorder(jb);
conservation.setBorder(jb);
identity.setBorder(jb);
+ ssConsensus.setBorder(jb);
showConsensbits.setBorder(jb);
showGroupbits.setBorder(jb);
showGroupConsensus.setBorder(jb);
// second row of autoannotation box
autoAnnotSettings = new JPanel();
annsettingsPanel.add(autoAnnotSettings);
+ autoAnnotSettings.setLayout(new GridLayout(0, 1));
+ autoAnnotSettings.add(ssConsensus);
+
+ // third row of autoannotation box
+ autoAnnotSettings = new JPanel();
+ annsettingsPanel.add(autoAnnotSettings);
autoAnnotSettings.setLayout(new GridLayout(0, 3));
autoAnnotSettings.add(conservation);
view.isIgnoreGapsinConsensus());
viewport.getResidueShading()
.setConsensus(viewport.getSequenceConsensusHash());
+ viewport.getResidueShading()
+ .setSSConsensusProfileMap(viewport.getSequenceSSConsensusHash());
if (safeBoolean(view.isConservationSelected()) && cs != null)
{
viewport.getResidueShading()
import java.awt.image.ImageObserver;
import java.util.BitSet;
import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
import org.jfree.graphics2d.svg.SVGGraphics2D;
import org.jibble.epsgraphics.EpsGraphics2D;
import jalview.analysis.AAFrequency;
+import jalview.analysis.AlignmentUtils;
import jalview.analysis.CodingUtils;
import jalview.analysis.Rna;
import jalview.analysis.StructureFrequency;
import jalview.schemes.NucleotideColourScheme;
import jalview.schemes.ResidueProperties;
import jalview.schemes.ZappoColourScheme;
+import jalview.util.MessageManager;
import jalview.util.Platform;
public class AnnotationRenderer
private HiddenColumns hiddenColumns;
private ProfilesI hconsensus;
+
+ private Map<String, 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(MessageManager.getString("label.ssconsensus_label")))
{
+
+ if(aa.groupRef != null && aa.groupRef.hSSConsensusProfileMap != null
+ && aa.groupRef.isShowSequenceLogo()) {
+ for (String source : aa.groupRef.hSSConsensusProfileMap.keySet()) {
+ if(aa.description.startsWith(source)) {
+
+ return AAFrequency.extractProfile(
+ aa.groupRef.hSSConsensusProfileMap.get(source).get(column),
+ aa.groupRef.getIgnoreGapsConsensus());
+ }
+ }
+ }
+
+ if(hSSconsensus!=null && aa.groupRef == null) {
+ for (String source : hSSconsensus.keySet()) {
+ if(aa.description.startsWith(source)) {
+
+ return AAFrequency.extractProfile(
+ hSSconsensus.get(source).get(column),
+ av_ignoreGapsConsensus);
+ }
+ }
+ }
+
+ }
+
if (aa.autoCalculated && aa.label.startsWith("StrucConsensus"))
{
// TODO implement group structure consensus
av_ignoreGapsConsensus);
}
}
- }
+
return null;
}
.getAlignmentStrucConsensusAnnotation();
final AlignmentAnnotation complementConsensusAnnot = av
.getComplementConsensusAnnotation();
+ final List<AlignmentAnnotation> ssConsensusAnnot = av
+ .getAlignmentSecondaryStructureConsensusAnnotation();
BitSet graphGroupDrawn = new BitSet();
int charOffset = 0; // offset for a label
// settings appropriately
// TODO: generalise this to have render styles for consensus/profile
// data
- if (row.groupRef != null && row == row.groupRef.getConsensus())
+ if (row.groupRef != null &&
+ (row == row.groupRef.getConsensus() || row.groupRef.getSSConsensus(null).contains(row)))
{
renderHistogram = row.groupRef.isShowConsensusHistogram();
renderProfile = row.groupRef.isShowSequenceLogo();
normaliseProfile = row.groupRef.isNormaliseSequenceLogo();
}
else if (row == consensusAnnot || row == structConsensusAnnot
- || row == complementConsensusAnnot)
+ || row == complementConsensusAnnot || (ssConsensusAnnot!=null && ssConsensusAnnot.contains(row)))
{
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)
colour = profcolour.findColour(codonTranslation.charAt(0),
column, null);
}
+ if(_aa.label.startsWith(MessageManager.getString("label.ssconsensus_label"))) {
+ colour = AlignmentUtils.getSecondaryStructureAnnotationColour(dc[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 ss consensus data for each column for each source
+ */
+
+ private Map<String, ProfilesI> ssConsensusProfileMap;
/*
* if true, apply shading of colour by conservation
this.conservationIncrement = rs.conservationIncrement;
this.ignoreGaps = rs.ignoreGaps;
this.pidThreshold = rs.pidThreshold;
+ this.ssConsensusProfileMap = rs.ssConsensusProfileMap;
}
/**
public void setConsensus(ProfilesI cons)
{
consensus = cons;
+
}
/**
return colour;
}
+
+ @Override
+ public Color findSSColour(char symbol, int position, SequenceI seq, String source)
+ {
+ if (colourScheme == null)
+ {
+ return Color.white; // Colour is 'None'
+ }
+
+ /*
+ * get 'base' colour
+ */
+ ProfileI profile = ssConsensusProfileMap.get(source) == null ? null : ssConsensusProfileMap.get(source).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
{
colourScheme = cs;
}
+
+ public Map<String, ProfilesI> getSSConsensusProfileMap()
+ {
+ return ssConsensusProfileMap;
+ }
+
+ public void setSSConsensusProfileMap(Map<String, ProfilesI> ssConsensusProfileMap)
+ {
+ this.ssConsensusProfileMap = ssConsensusProfileMap;
+ }
}
{
public abstract void setConsensus(ProfilesI cons);
+
+ public abstract void setSSConsensusProfileMap(Map<String, ProfilesI> ssConsensusProfileMap);
public abstract boolean conservationApplied();
public abstract void setColourScheme(ColourSchemeI cs);
+ Color findSSColour(char symbol, int position, SequenceI seq,
+ String source);
+
}
\ No newline at end of file
public static final int[] nucleotideIndex;
public static final int[] purinepyrimidineIndex;
+
+ public static final int[] secondaryStructureIndex;
public static final Map<String, Integer> aa3Hash = new HashMap<>();
purinepyrimidineIndex['N'] = 2;
purinepyrimidineIndex['n'] = 2;
}
+
+ static
+ {
+ secondaryStructureIndex = new int[255];
+ for (int i = 0; i < 255; i++)
+ {
+ secondaryStructureIndex[i] = 3;
+ }
+
+ secondaryStructureIndex['H'] = 0;
+ secondaryStructureIndex['E'] = 1;
+ secondaryStructureIndex['C'] = 2;
+ }
private static final Integer ONE = Integer.valueOf(1);
Color.white, // all other nucleotides
Color.white // Gap
};
+
+ //Secondary structure
+ public static final Color[] secondarystructure = { Color.red, // H
+ Color.green, // E
+ Color.gray // C
+ };
// Zappo
public static final Color[] zappo = { Color.pink, // A
--- /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.util;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A class to hold constants relating to Url links used in Jalview
+ */
+public class Constants
+{
+
+ //character used to represent secondary structures
+ public static final char HELIX = 'H';
+ public static final char SHEET = 'E';
+ public static final char COIL = 'C';
+
+ //label in secondary structure annotation data model from 3d structures
+ public static final String SS_ANNOTATION_LABEL = "Secondary Structure";
+
+ //label in secondary structure annotation data model from JPred
+ public static final String SS_ANNOTATION_FROM_JPRED_LABEL = "jnetpred";
+
+ public static final Map<String, String> SECONDARY_STRUCTURE_LABELS = new HashMap<>();
+ static {
+ SECONDARY_STRUCTURE_LABELS.put(SS_ANNOTATION_LABEL, "3D Structures");
+ SECONDARY_STRUCTURE_LABELS.put(SS_ANNOTATION_FROM_JPRED_LABEL, "JPred");
+ // Add other secondary structure labels here if needed
+ }
+}
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.BitSet;
+import java.util.Collections;
import java.util.Deque;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import jalview.analysis.AnnotationSorter.SequenceAnnotationOrder;
+import jalview.analysis.AlignmentUtils;
import jalview.analysis.Conservation;
import jalview.analysis.TreeModel;
import jalview.api.AlignCalcManagerI;
import jalview.workers.AlignCalcManager;
import jalview.workers.ComplementConsensusThread;
import jalview.workers.ConsensusThread;
+import jalview.workers.SecondaryStructureConsensusThread;
import jalview.workers.StrucConsensusThread;
/**
}
protected AlignmentAnnotation consensus;
+
+ protected List<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 Map<String, ProfilesI> hSSConsensusProfileMap = null;
+
+
/**
* results of cDNA complement consensus visible portion of view
{
hconservation = cons;
}
+
+ @Override
+ public List<String> getSecondaryStructureSources()
+ {
+ return viewStyle.getSecondaryStructureSources();
+ }
+
+ @Override
+ public void setSecondaryStructureSources(
+ List<String> secondaryStructureSources)
+ {
+ viewStyle.setSecondaryStructureSources(secondaryStructureSources);
+ }
+
+ protected void setSecondaryStructureSources(AlignmentAnnotation[] aa)
+ {
+ List<String> sources = null;
+
+ if(aa!=null) {
+ sources = AlignmentUtils.extractSSSourceInAlignmentAnnotation(aa);
+ if(sources != null) {
+ sources.add(0,MessageManager.getString("option.ss_providers_all"));
+ viewStyle.setSecondaryStructureSources(sources);
+ }
+ }
+ }
/**
* percentage gaps allowed in a column before all amino acid properties should
{
this.hconsensus = hconsensus;
}
-
+
+ @Override
+ public void setSequenceSSConsensusHash(Map<String, ProfilesI> hSSConsensusProfileMap)
+ {
+ this.hSSConsensusProfileMap = hSSConsensusProfileMap;
+ }
+
@Override
public void setComplementConsensusHash(
Hashtable<String, Object>[] hconsensus)
}
@Override
+ public Map<String, ProfilesI> getSequenceSSConsensusHash()
+ {
+ return hSSConsensusProfileMap;
+ }
+
+
+ @Override
public Hashtable<String, Object>[] getComplementConsensusHash()
{
return hcomplementConsensus;
return consensus;
}
+
+ @Override
+ public List<AlignmentAnnotation> getAlignmentSecondaryStructureConsensusAnnotation()
+ {
+ return secondaryStructureConsensus;
+ }
+
+
@Override
public AlignmentAnnotation getAlignmentGapAnnotation()
{
}
}
}
+
+
+
+
+ /**
+ * trigger update of Secondary Structure consensus annotation
+ */
+ public void updateSecondaryStructureConsensus(final AlignmentViewPanel ap)
+ {
+ // see note in mantis : issue number 8585
+ if (secondaryStructureConsensus == null || !autoCalculateConsensus)
+ {
+ return;
+ }
+ List<String> ssSources = viewStyle.getSecondaryStructureSources();
+ if (secondaryStructureConsensus.size() != ssSources.size()) {
+
+ for(String source : ssSources) {
+ boolean ssConsensusForSourcePresent = false;
+ for(AlignmentAnnotation aa : secondaryStructureConsensus) {
+ if(aa.description.startsWith(source)) {
+ ssConsensusForSourcePresent = true;
+ break;
+ }
+ }
+
+ if(!ssConsensusForSourcePresent) {
+ AlignmentAnnotation ssConsensus = new AlignmentAnnotation(MessageManager.getString("label.ssconsensus_label") + " "+source,
+ source + " " + MessageManager.getString("label.ssconsensus_descr"),
+ new Annotation[1], 0f, 100f, AlignmentAnnotation.BAR_GRAPH);
+
+ ssConsensus.hasText = true;
+ ssConsensus.autoCalculated = true;
+ secondaryStructureConsensus.add(ssConsensus);
+ if (showSSConsensus)
+ {
+ ssConsensus.visible = true;
+ alignment.addAnnotation(ssConsensus);
+
+ }
+ }
+ }
+ }
+ if (calculator
+ .getRegisteredWorkersOfClass(SecondaryStructureConsensusThread.class) == null)
+ {
+ calculator.registerWorker(new SecondaryStructureConsensusThread(this, ap));
+ }
+ ap.adjustAnnotationHeight();
+
+
+ }
// --------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 rows be shown for groups
*/
protected boolean showGroupConsensus = false;
+
+
+ protected boolean showGroupSSConsensus = false;
/**
* should consensus profile be rendered by default
*/
protected boolean showSequenceLogo = false;
-
+
/**
* should consensus profile be rendered normalised to row height
*/
* should consensus histograms be rendered by default
*/
protected boolean showConsensusHistogram = true;
-
+
/**
* @return the showConsensusProfile
*/
{
return showSequenceLogo;
}
-
+
/**
* @param showSequenceLogo
* the new value
calculator.updateAnnotationFor(ConsensusThread.class);
calculator.updateAnnotationFor(ComplementConsensusThread.class);
calculator.updateAnnotationFor(StrucConsensusThread.class);
+
+ //to do
+
+ calculator.updateAnnotationFor(SecondaryStructureConsensusThread.class);
}
this.showSequenceLogo = showSequenceLogo;
}
-
+
/**
* @param showConsensusHistogram
* the showConsensusHistogram to set
{
return showGroupConsensus;
}
+
+ public boolean isShowGroupSSConsensus()
+ {
+ return showGroupSSConsensus;
+ }
+
/**
* @param showGroupConsensus
{
this.showGroupConsensus = showGroupConsensus;
}
-
+
+ public void setShowGroupSSConsensus(boolean showGroupSSConsensus)
+ {
+ this.showGroupSSConsensus = showGroupSSConsensus;
+ }
+
+ /**
+ * @param showSSConsensus
+ * the showSSConsensus to set
+ */
+ public void setShowSSConsensus(boolean showSSConsensus)
+ {
+ this.showSSConsensus = showSSConsensus;
+ }
+
/**
*
* @return flag to indicate if the consensus histogram should be rendered by
if (ap != null)
{
updateConsensus(ap);
+ updateSecondaryStructureConsensus(ap);
if (residueShading != null)
{
residueShading.setThreshold(residueShading.getThreshold(),
protected boolean showQuality = true;
- protected boolean showConsensus = true;
+ protected boolean showConsensus = true;
+
+ protected boolean showSSConsensus = true;
protected boolean showOccupancy = true;
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);
+ setSecondaryStructureSources(alignment.getAlignmentAnnotation());
+ List<String> secondaryStructureSources = getSecondaryStructureSources();
+
+ if(secondaryStructureSources!=null) {
+
+ secondaryStructureConsensus = new ArrayList<AlignmentAnnotation>();
+ for (String ssSource : secondaryStructureSources) {
+
+ AlignmentAnnotation ssConsensus = new AlignmentAnnotation(MessageManager.getString("label.ssconsensus_label") + " "+ssSource,
+ ssSource + " " + MessageManager.getString("label.ssconsensus_descr"),
+ new Annotation[1], 0f, 100f, AlignmentAnnotation.BAR_GRAPH);
+ secondaryStructureConsensus.add(ssConsensus);
+ }
+
+ }
+
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(List<AlignmentAnnotation> secondaryStructureConsensuses)
+ {
+ if(secondaryStructureConsensuses == null) {
+ return;
+ }
+ for(AlignmentAnnotation aa : secondaryStructureConsensuses) {
+ aa.hasText = true;
+ aa.autoCalculated = true;
+
+ if (showSSConsensus)
+ {
+ alignment.addAnnotation(aa);
+ }
+
+ }
+ }
// these should be extracted from the view model - style and settings for
// derived annotation
boolean updateCalcs = false;
boolean conv = isShowGroupConservation();
boolean cons = isShowGroupConsensus();
+ boolean sscons = isShowGroupSSConsensus();
boolean showprf = isShowSequenceLogo();
boolean showConsHist = isShowConsensusHistogram();
boolean normLogo = isNormaliseSequenceLogo();
updateCalcs = true;
alignment.addAnnotation(sg.getConsensus(), 0);
}
+ if(sscons)
+ {
+ updateCalcs = true;
+ List<String> secondaryStructureSources = getSecondaryStructureSources();
+ if(secondaryStructureSources !=null) {
+ List<AlignmentAnnotation> ssAa = sg.getSSConsensus(secondaryStructureSources);
+ if(ssAa != null) {
+ for(AlignmentAnnotation aa : ssAa) {
+ alignment.addAnnotation(aa, 0);
+ }
+ }
+ }
+ }
// refresh the annotation rows
if (updateCalcs)
{
+ ((ignoreGapsInConsensusCalculation) ? " without gaps" : ""));
return sq;
}
+
+ //to do jal-4386
+ 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.viewmodel.styles;
import java.awt.Color;
+import java.util.List;
import jalview.api.ViewStyleI;
setUpperCasebold(vs.isUpperCasebold());
setWrapAlignment(vs.getWrapAlignment());
setWrappedWidth(vs.getWrappedWidth());
+ setSecondaryStructureSources(vs.getSecondaryStructureSources());
// ViewStyle.configureFrom(this, viewStyle);
}
&& getThresholdTextColour() == vs.getThresholdTextColour()
&& isUpperCasebold() == vs.isUpperCasebold()
&& getWrapAlignment() == vs.getWrapAlignment()
- && getWrappedWidth() == vs.getWrappedWidth());
+ && getWrappedWidth() == vs.getWrappedWidth()
+ && getSecondaryStructureSources() == vs.getSecondaryStructureSources());
/*
* and compare non-primitive types; syntax below will match null with null
* values
private boolean showComplementFeatures;
private boolean showComplementFeaturesOnTop;
+
+ /**
+ * secondary structure annotation rows shown in the view
+ */
+ private List<String> secondaryStructureSources = List.of( new String[0] );
/**
* GUI state
{
return showComplementFeaturesOnTop;
}
+
+ @Override
+ public List<String> getSecondaryStructureSources()
+ {
+ return secondaryStructureSources;
+ }
+
+ @Override
+ public void setSecondaryStructureSources(List<String> secondaryStructureSources)
+ {
+ this.secondaryStructureSources = secondaryStructureSources;
+ }
}
*/
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 java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import jalview.analysis.AAFrequency;
+import jalview.analysis.AlignmentUtils;
+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;
+import jalview.util.MessageManager;
+
+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
+ {
+ List<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;
+ }
+
+ setSecondaryStructureSources();
+ 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)
+ {
+ List<AlignmentAnnotation> ssConsensuses = getSSConsensusAnnotation();
+ for(AlignmentAnnotation ssConsensus : ssConsensuses) {
+ 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();
+ Map<String, ProfilesI> hSSConsensusProfileMap = new HashMap<String, ProfilesI>();
+ List <String> ssSources = getSecondaryStructureSources();
+ for(String ssSource : ssSources) {
+ ProfilesI hSSConsensus = AAFrequency.calculateSS(aseqs, width, 0, width,
+ true, ssSource);
+ hSSConsensusProfileMap.put(ssSource, hSSConsensus);
+ }
+
+
+ alignViewport.setSequenceSSConsensusHash(hSSConsensusProfileMap);
+ setColourSchemeConsensus(hSSConsensusProfileMap);
+ }
+
+ /**
+ * @return
+ */
+ protected SequenceI[] getSequences()
+ {
+ return alignViewport.getAlignment().getSequencesArray();
+ }
+
+ /**
+ * @param hconsensus
+ */
+ protected void setColourSchemeConsensus(Map<String, ProfilesI> ssConsensusProfileMap)
+ {
+ ResidueShaderI cs = alignViewport.getResidueShading();
+ if (cs != null)
+ {
+ cs.setSSConsensusProfileMap(ssConsensusProfileMap);
+ }
+ }
+
+ /**
+ * Get the Consensus annotation for the alignment
+ *
+ * @return
+ */
+ protected List<AlignmentAnnotation> getSSConsensusAnnotation()
+ {
+ return alignViewport.getAlignmentSecondaryStructureConsensusAnnotation();
+ }
+
+ /**
+ * Get the Consensus annotation for the alignment
+ *
+ * @return
+ */
+ protected void setSecondaryStructureSources()
+ {
+ List<String> sources = null;
+ AlignmentAnnotation[] aa = alignViewport.getAlignment().getAlignmentAnnotation();
+ if(aa!=null) {
+ sources = AlignmentUtils.extractSSSourceInAlignmentAnnotation(aa);
+ if(sources != null) {
+ sources.add(0, MessageManager.getString("option.ss_providers_all"));
+ alignViewport.setSecondaryStructureSources(sources);
+ }
+ }
+ }
+
+ protected List<String> getSecondaryStructureSources()
+ {
+ return alignViewport.getSecondaryStructureSources();
+ }
+
+ /**
+ * 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)
+ {
+ List<AlignmentAnnotation> ssConsensuses = getSSConsensusAnnotation();
+ Map<String, ProfilesI> ssConsensusProfileMap = getViewportSSConsensus();
+ for(AlignmentAnnotation ssConsensus : ssConsensuses) {
+ ProfilesI ssConsensusProfile = null;
+ for(String source: ssConsensusProfileMap.keySet()) {
+ if(ssConsensus.description.startsWith(source)) {
+ ssConsensusProfile = ssConsensusProfileMap.get(source);
+ break;
+ }
+ }
+ if(ssConsensusProfile==null) {
+ continue;
+ }
+ if (immediate || !calcMan.isWorking(this) && ssConsensus != null
+ && ssConsensusProfile != null)
+ {
+ if(ssConsensusProfile.get(0)!=null)
+ ssConsensus.setNoOfSequencesIncluded(ssConsensusProfile.get(0).getSeqWithSSCount());
+ deriveSSConsensus(ssConsensus, ssConsensusProfile);
+ AlignmentAnnotation gap = getGapAnnotation();
+ if (gap != null)
+ {
+ deriveGap(gap, ssConsensusProfile);
+ }
+ }
+ }
+ }
+
+ /**
+ * 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 ssConsensus,
+ ProfilesI hSSConsensus)
+ {
+
+ long nseq = getSequences().length;
+ AAFrequency.completeSSConsensus(ssConsensus, 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 Map<String, ProfilesI> getViewportSSConsensus()
+ {
+ // TODO convert ComplementConsensusThread to use Profile
+ return alignViewport.getSequenceSSConsensusHash();
+ }
+}
import static org.testng.AssertJUnit.assertSame;
import static org.testng.AssertJUnit.assertTrue;
+import java.awt.Color;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
+import org.testng.Assert;
import org.testng.annotations.BeforeClass;
+import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import jalview.datamodel.AlignedCodonFrame;
{
JvOptionPane.setInteractiveMode(false);
JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
+
+ AlignmentAnnotation ann1 = new AlignmentAnnotation("Secondary Structure", "Secondary Structure",
+ new Annotation[] {});
+ AlignmentAnnotation ann2 = new AlignmentAnnotation("jnetpred", "jnetpred",
+ new Annotation[] {});
+ AlignmentAnnotation ann3 = new AlignmentAnnotation("Temp", "Temp",
+ new Annotation[] {});
+ AlignmentAnnotation ann4 = new AlignmentAnnotation("Temp", "Temp",
+ new Annotation[] {});
+
+ AlignmentAnnotation[] anns1 = new AlignmentAnnotation[] {ann1, ann3, ann4};
+
+ AlignmentAnnotation[] anns2 = new AlignmentAnnotation[] {ann2, ann3, ann4};
+
+ AlignmentAnnotation[] anns3 = new AlignmentAnnotation[] {ann3, ann4};
+
+ AlignmentAnnotation[] anns4 = new AlignmentAnnotation[0];
+
+ AlignmentAnnotation[] anns5 = new AlignmentAnnotation[] {ann1, ann2, ann3, ann4};
}
@Test(groups = { "Functional" })
&& al.getAlignmentAnnotation().length == 2);
}
+
+ @Test(groups = "Functional", dataProvider = "SecondaryStructureAnnotations")
+ public void testSecondaryStructurePresentAndSources(AlignmentAnnotation[] annotations, boolean expectedSSPresent, ArrayList<String> expectedSSSources) {
+ Assert.assertEquals(expectedSSPresent, AlignmentUtils.isSecondaryStructurePresent(annotations));
+ Assert.assertEquals(expectedSSSources, AlignmentUtils.getSecondaryStructureSources(annotations));
+ }
+
+ @DataProvider(name = "SecondaryStructureAnnotations")
+ public static Object[][] provideSecondaryStructureAnnotations() {
+ AlignmentAnnotation ann1 = new AlignmentAnnotation("Secondary Structure", "Secondary Structure", new Annotation[]{});
+ AlignmentAnnotation ann2 = new AlignmentAnnotation("jnetpred", "jnetpred", new Annotation[]{});
+ AlignmentAnnotation ann3 = new AlignmentAnnotation("Temp", "Temp", new Annotation[]{});
+ AlignmentAnnotation ann4 = new AlignmentAnnotation("Temp", "Temp", new Annotation[]{});
+
+ List<String> ssSources1 = new ArrayList<>(Arrays.asList("3D Structures"));
+ List<String> ssSources2 = new ArrayList<>(Arrays.asList("JPred"));
+ List<String> ssSources3 = new ArrayList<>(Arrays.asList("3D Structures", "JPred"));
+ List<String> ssSources4 = new ArrayList<>();
+
+ return new Object[][]{
+ {new AlignmentAnnotation[]{ann1, ann3, ann4}, true, ssSources1},
+ {new AlignmentAnnotation[]{ann2, ann3, ann4}, true, ssSources2},
+ {new AlignmentAnnotation[]{ann3, ann4}, false, ssSources4},
+ {new AlignmentAnnotation[]{}, false, ssSources4},
+ {new AlignmentAnnotation[]{ann1, ann2, ann3, ann4}, true, ssSources3}
+ };
+ }
+
+ @Test(dataProvider = "SecondaryStructureAnnotationColours")
+ public void testSecondaryStructureAnnotationColour(char symbol, Color expectedColor) {
+ Color actualColor = AlignmentUtils.getSecondaryStructureAnnotationColour(symbol);
+ Assert.assertEquals(actualColor, expectedColor);
+ }
+
+ @DataProvider(name = "SecondaryStructureAnnotationColours")
+ public static Object[][] provideSecondaryStructureAnnotationColours() {
+ return new Object[][]{
+ {'C', Color.gray},
+ {'E', Color.green},
+ {'H', Color.red},
+ {'-', Color.gray}
+ };
+ }
+
+ @Test(dataProvider = "SSAnnotationPresence")
+ public void testIsSSAnnotationPresent(Map<SequenceI, List<AlignmentAnnotation>> annotations, boolean expectedPresence) {
+ boolean actualPresence = AlignmentUtils.isSSAnnotationPresent(annotations);
+ Assert.assertEquals(actualPresence, expectedPresence);
+ }
+
+ @DataProvider(name = "SSAnnotationPresence")
+ public static Object[][] provideSSAnnotationPresence() {
+ Map<SequenceI, List<AlignmentAnnotation>> annotations1 = new HashMap<>();
+ SequenceI seq1 = new Sequence("Seq1", "ASD---ASD---ASD", 37, 45);
+ List<AlignmentAnnotation> annotationsList1 = new ArrayList<>();
+ annotationsList1.add(new AlignmentAnnotation("Secondary Structure", "Secondary Structure", new Annotation[]{}));
+ annotations1.put(seq1, annotationsList1); // Annotation present secondary structure for seq1
+
+ Map<SequenceI, List<AlignmentAnnotation>> annotations2 = new HashMap<>();
+ SequenceI seq2 = new Sequence("Seq2", "ASD---ASD------", 37, 42);
+ List<AlignmentAnnotation> annotationsList2 = new ArrayList<>();
+ annotationsList2.add(new AlignmentAnnotation("Other Annotation", "Other Annotation", new Annotation[]{}));
+ annotations2.put(seq2, annotationsList2); // Annotation not related to any of secondary structure for seq2
+
+ Map<SequenceI, List<AlignmentAnnotation>> annotations3 = new HashMap<>();
+ // Empty annotation map
+
+ Map<SequenceI, List<AlignmentAnnotation>> annotations4 = new HashMap<>();
+ SequenceI seq4 = new Sequence("Seq4", "ASD---ASD---AS-", 37, 44);
+ List<AlignmentAnnotation> annotationsList4 = new ArrayList<>();
+ annotationsList4.add(new AlignmentAnnotation("jnetpred", "jnetpred", new Annotation[]{}));
+ annotations4.put(seq4, annotationsList4); // Annotation present from JPred for seq4
+
+
+ return new Object[][]{
+ {annotations1, true}, // Annotations present secondary structure present
+ {annotations2, false}, // No annotations related to any of the secondary structure present
+ {annotations3, false}, // Empty annotation map
+ {annotations4, true}, // Annotations present from JPred secondary structure present
+ };
+ }
+
+ @Test
+ public void testGetSSSourceFromAnnotationDescription(AlignmentAnnotation[] annotations, String expectedSSSource) {
+ List<String> actualSSSource = AlignmentUtils.extractSSSourceInAlignmentAnnotation(annotations);
+ Assert.assertEquals(actualSSSource, expectedSSSource);
+ }
+
+ @DataProvider(name = "SSSourceFromAnnotationDescription")
+ public static Object[][] provideSSSourceFromAnnotationDescription() {
+ Map<SequenceI, List<AlignmentAnnotation>> annotations1 = new HashMap<>();
+ SequenceI seq1 = new Sequence("Seq1", "ASD---ASD---ASD", 37, 45);
+ List<AlignmentAnnotation> annotationsList1 = new ArrayList<>();
+ annotationsList1.add(new AlignmentAnnotation("jnetpred", "JPred Output", new Annotation[]{}));
+ annotations1.put(seq1, annotationsList1); // Annotation present from JPred for seq1
+
+ Map<SequenceI, List<AlignmentAnnotation>> annotations2 = new HashMap<>();
+ SequenceI seq2 = new Sequence("Seq2", "ASD---ASD------", 37, 42);
+ List<AlignmentAnnotation> annotationsList2 = new ArrayList<>();
+ annotationsList2.add(new AlignmentAnnotation("Secondary Structure",
+ "Secondary Structure for af-q43517-f1A", new Annotation[]{}));
+ annotations2.put(seq2, annotationsList2); // Annotation present secondary structure from Alphafold for seq2
+
+ Map<SequenceI, List<AlignmentAnnotation>> annotations3 = new HashMap<>();
+ // Empty annotation map
+
+ Map<SequenceI, List<AlignmentAnnotation>> annotations4 = new HashMap<>();
+ SequenceI seq4 = new Sequence("Seq4", "ASD---ASD---AS-", 37, 44);
+ List<AlignmentAnnotation> annotationsList4 = new ArrayList<>();
+ annotationsList4.add(new AlignmentAnnotation("Secondary Structure",
+ "Secondary Structure for 4zhpA", new Annotation[]{}));
+ annotations4.put(seq4, annotationsList4); // Annotation present secondary structure from pdb for seq4
+
+ Map<SequenceI, List<AlignmentAnnotation>> annotations5 = new HashMap<>();
+ SequenceI seq5 = new Sequence("Seq5", "ASD---ASD---AS-", 37, 44);
+ List<AlignmentAnnotation> annotationsList5 = new ArrayList<>();
+ annotationsList5.add(new AlignmentAnnotation("Secondary Structure",
+ "Secondary Structure for p09911_54-147__3a7wzn.1.p3502557454997462030P",
+ new Annotation[]{}));
+ annotations5.put(seq5, annotationsList5); // Annotation present secondary structure from Swiss model for seq5
+
+
+ //JPred Output - JPred
+ //Secondary Structure for af-q43517-f1A - Alphafold
+ //Secondary Structure for 4zhpA - Experimental
+ //Secondary Structure for p09911_54-147__3a7wzn.1.p3502557454997462030P - Swiss Model
+
+ return new Object[][]{
+ {annotations1, "JPred"},
+ {annotations2, "Alphafold"},
+ {annotations3, null},
+ {annotations4, "PDB"},
+ {annotations5, "Swiss Model"}
+ };
+ }
+
}
assertFalse(sm instanceof PairwiseScoreModelI);
assertTrue(sm instanceof DistanceScoreModel);
assertEquals(sm.getName(), "Sequence Feature Similarity");
+
+ sm = models.next();
+ assertFalse(sm instanceof SimilarityScoreModel);
+ assertFalse(sm instanceof PairwiseScoreModelI);
+ assertTrue(sm instanceof DistanceScoreModel);
+ assertEquals(sm.getName(), "Secondary Structure Similarity");
}
/**
--- /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.analysis.scoremodels;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import jalview.api.analysis.ScoreModelI;
+import jalview.api.analysis.SimilarityParamsI;
+import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.AlignmentView;
+import jalview.datamodel.Annotation;
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceFeature;
+import jalview.datamodel.SequenceI;
+import jalview.gui.AlignFrame;
+import jalview.gui.AlignViewport;
+import jalview.gui.JvOptionPane;
+import jalview.io.DataSourceType;
+import jalview.io.FileLoader;
+import jalview.math.MatrixI;
+
+import org.testng.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+// This class tests methods in Class SecondaryStructureDistanceModel
+public class SecondaryStructureDistanceModelTest
+{
+
+ /**
+ * Verify computed distances of sequences with gap
+ */
+ @Test(groups = "Functional")
+ public void testFindDistances_withGap()
+ {
+ AlignFrame af = setupAlignmentViewWithGap();
+ AlignViewport viewport = af.getViewport();
+ AlignmentView view = viewport.getAlignmentView(false);
+
+ ScoreModelI sm = new SecondaryStructureDistanceModel();
+ sm = ScoreModels.getInstance().getScoreModel(sm.getName(),
+ af.alignPanel);
+
+ /*
+ * feature distance model always normalises by region width
+ * gap-gap is always included (but scores zero)
+ * the only variable parameter is 'includeGaps'
+ */
+
+ /*
+ * include gaps
+ * score = 0 + 0 + 1 + 0 = 1/4
+ */
+ SimilarityParamsI params = new SimilarityParams(false, true, true, true);
+ params.setSecondaryStructureSource("3D Structures");
+ MatrixI distances = sm.findDistances(view, params);
+ assertEquals(distances.getValue(0, 0), 1d);
+ assertEquals(distances.getValue(1, 1), 1d);
+ assertEquals(distances.getValue(0, 1), 0d);
+ assertEquals(distances.getValue(1, 0), 0d);
+
+ /*
+ * exclude gaps
+ * score = 0 + 0 + 0 + 0 = 0/4
+ */
+
+ SimilarityParamsI params2 = new SimilarityParams(false, true, false, true);
+ params2.setSecondaryStructureSource("3D Structures");
+ MatrixI distances2 = sm.findDistances(view, params2);
+ assertEquals(distances2.getValue(0, 1), 0d);
+ assertEquals(distances2.getValue(1, 0), 0d);
+ }
+
+
+ /**
+ * Verify computed distances of sequences with gap
+ */
+ @Test(groups = "Functional")
+ public void testFindDistances_withSSUndefinedInEitherOneSeq()
+ {
+ AlignFrame af = setupAlignmentViewWithoutSS("either");
+ AlignViewport viewport = af.getViewport();
+ AlignmentView view = viewport.getAlignmentView(false);
+
+ ScoreModelI sm = new SecondaryStructureDistanceModel();
+ sm = ScoreModels.getInstance().getScoreModel(sm.getName(),
+ af.alignPanel);
+
+ /*
+ * feature distance model always normalises by region width
+ * gap-gap is always included (but scores zero)
+ * the only variable parameter is 'includeGaps'
+ */
+
+ /*
+ * include gaps
+ * score = 0 + 0 + 2 + 2 = 2/4
+ */
+ SimilarityParamsI params = new SimilarityParams(false, true, true, true);
+ params.setSecondaryStructureSource("3D Structures");
+ MatrixI distances = sm.findDistances(view, params);
+ assertEquals(distances.getValue(0, 0), 1d);
+ assertEquals(distances.getValue(1, 1), 1d);
+ assertEquals(distances.getValue(0, 1), 0d);
+ assertEquals(distances.getValue(1, 0), 0d);
+
+ /*
+ * exclude gaps
+ * score = 0 + 0 + 2 + 2 = 2/4
+ */
+
+ SimilarityParamsI params2 = new SimilarityParams(false, true, false, true);
+ params2.setSecondaryStructureSource("3D Structures");
+ MatrixI distances2 = sm.findDistances(view, params2);
+ assertEquals(distances2.getValue(0, 1), 0d);
+ assertEquals(distances2.getValue(1, 0), 0d);
+ }
+
+
+ /**
+ * Verify computed distances of sequences with gap
+ */
+ @Test(groups = "Functional")
+ public void testFindDistances_withSSUndefinedInBothSeqs()
+ {
+ AlignFrame af = setupAlignmentViewWithoutSS("both");
+ AlignViewport viewport = af.getViewport();
+ AlignmentView view = viewport.getAlignmentView(false);
+
+ ScoreModelI sm = new SecondaryStructureDistanceModel();
+ sm = ScoreModels.getInstance().getScoreModel(sm.getName(),
+ af.alignPanel);
+
+ /*
+ * feature distance model always normalises by region width
+ * gap-gap is always included (but scores zero)
+ * the only variable parameter is 'includeGaps'
+ */
+
+ /*
+ * include gaps
+ * score = 0 + 0 + 2 + 2 = 2/4
+ */
+ SimilarityParamsI params = new SimilarityParams(false, true, true, true);
+ params.setSecondaryStructureSource("3D Structures");
+ MatrixI distances = sm.findDistances(view, params);
+ assertEquals(distances.getValue(0, 0), 1d);
+ assertEquals(distances.getValue(1, 1), 1d);
+ assertEquals(distances.getValue(0, 1), 0d);
+ assertEquals(distances.getValue(1, 0), 0d);
+
+ /*
+ * exclude gaps
+ * score = 0 + 0 + 2 + 2 = 2/4
+ */
+
+ SimilarityParamsI params2 = new SimilarityParams(false, true, false, true);
+ params2.setSecondaryStructureSource("3D Structures");
+ MatrixI distances2 = sm.findDistances(view, params2);
+ assertEquals(distances2.getValue(0, 1), 0d);
+ assertEquals(distances2.getValue(1, 0), 0d);
+ }
+
+
+
+ /**
+ * <pre>
+ * Set up
+ * column 1 2 3 4
+ * seq s1 F R K S
+ *
+ * seq s2 F S J L
+ * </pre>
+ *
+ * @return
+ */
+ protected AlignFrame setupAlignmentView(String similar)
+ {
+ /*
+ * sequences without gaps
+ */
+ SequenceI s1 = new Sequence("s1", "FRKS");
+ SequenceI s2 = new Sequence("s2", "FSJL");
+
+ s1.addSequenceFeature(
+ new SequenceFeature("chain", null, 1, 4, 0f, null));
+ s1.addSequenceFeature(
+ new SequenceFeature("domain", null, 1, 4, 0f, null));
+ s2.addSequenceFeature(
+ new SequenceFeature("chain", null, 1, 4, 0f, null));
+ s2.addSequenceFeature(
+ new SequenceFeature("metal", null, 1, 4, 0f, null));
+ s2.addSequenceFeature(
+ new SequenceFeature("Pfam", null, 1, 4, 0f, null));
+
+
+ /*
+ * Set up secondary structure annotations
+ */
+ Annotation ssE = new Annotation("","",'E',0);
+ Annotation ssH = new Annotation("","",'H',0);
+ Annotation ssC = new Annotation(".","",' ',0);
+
+ Annotation[] anns1;
+ Annotation[] anns2;
+
+ /* All secondary structure annotations are similar for each column
+ * Set up
+ * column 1 2 3 4
+ * seq s1 F R K S
+ * ss E H S E
+ *
+ * seq s2 F S J L
+ * ss E H S E
+ */
+ if(similar == "All Similar") {
+
+ anns1 = new Annotation[] { ssE, ssH, ssC, ssE};
+ anns2 = new Annotation[] { ssE, ssH, ssC, ssE};
+
+ }
+
+ /* All secondary structure annotations are dissimilar for each column
+ * Set up
+ * column 1 2 3 4
+ * seq s1 F R K S
+ * ss E E C E
+ *
+ * seq s2 F S J L
+ * ss H E E C
+ */
+ else if(similar == "Not Similar") {
+
+ anns1 = new Annotation[] { ssE, ssE, ssC, ssE};
+ anns2 = new Annotation[] { ssH, ssH, ssE, ssC};
+
+ }
+
+ /* All secondary structure annotations are dissimilar for each column
+ * Set up
+ * column 1 2 3 4
+ * seq s1 F R K S
+ * ss E E C E
+ *
+ * seq s2 F S J L
+ * ss H E E C
+ */
+ else if(similar == "With Coil") {
+
+ anns1 = new Annotation[] { ssE, ssE, null, ssE};
+ anns2 = new Annotation[] { ssH, ssH, ssE, null};
+
+ }
+
+ /* Set up
+ * column 1 2 3 4
+ * seq s1 F R K S
+ * ss H E C E
+ *
+ * seq s2 F S J L
+ * ss H E E C
+ */
+ else {
+
+ anns1 = new Annotation[] { ssH, ssE, ssC, ssE};
+ anns2 = new Annotation[] { ssH, ssE, ssE, ssC};
+ }
+
+
+ AlignmentAnnotation ann1 = new AlignmentAnnotation("Secondary Structure",
+ "Secondary Structure", anns1);
+ AlignmentAnnotation ann2 = new AlignmentAnnotation("Secondary Structure",
+ "Secondary Structure", anns2);
+
+ s1.addAlignmentAnnotation(ann1);
+ s2.addAlignmentAnnotation(ann2);
+
+ AlignmentI al = new Alignment(new SequenceI[] { s1, s2 });
+ AlignFrame af = new AlignFrame(al, 300, 300);
+ af.setShowSeqFeatures(true);
+ af.getFeatureRenderer().findAllFeatures(true);
+ return af;
+ }
+
+
+ /**
+ * <pre>
+ * Set up
+ * column 1 2 3 4
+ * seq s1 F R S
+ * SS H E C
+ *
+ * seq s2 F S J L
+ * ss H E E C
+ * </pre>
+ *
+ * @return
+ */
+ protected AlignFrame setupAlignmentViewWithGap()
+ {
+
+ SequenceI s1 = new Sequence("s1", "FR S");
+ SequenceI s2 = new Sequence("s2", "FSJL");
+
+ s1.addSequenceFeature(
+ new SequenceFeature("chain", null, 1, 3, 0f, null));
+ s1.addSequenceFeature(
+ new SequenceFeature("domain", null, 1, 3, 0f, null));
+ s2.addSequenceFeature(
+ new SequenceFeature("chain", null, 1, 4, 0f, null));
+ s2.addSequenceFeature(
+ new SequenceFeature("metal", null, 1, 4, 0f, null));
+ s2.addSequenceFeature(
+ new SequenceFeature("Pfam", null, 1, 4, 0f, null));
+
+
+ Annotation ssE = new Annotation("","",'E',0);
+ Annotation ssH = new Annotation("","",'H',0);
+ Annotation ssC = new Annotation(".","",' ',0);
+
+ Annotation[] anns1;
+ Annotation[] anns2;
+
+ anns1 = new Annotation[] { ssH, ssE, ssC};
+ anns2 = new Annotation[] { ssH, ssE, ssE, ssC};
+
+ AlignmentAnnotation ann1 = new AlignmentAnnotation("Secondary Structure",
+ "Secondary Structure", anns1);
+ AlignmentAnnotation ann2 = new AlignmentAnnotation("Secondary Structure",
+ "Secondary Structure", anns2);
+
+ s1.addAlignmentAnnotation(ann1);
+ s2.addAlignmentAnnotation(ann2);
+
+ AlignmentI al = new Alignment(new SequenceI[] { s1, s2 });
+ AlignFrame af = new AlignFrame(al, 300, 300);
+ af.setShowSeqFeatures(true);
+ af.getFeatureRenderer().findAllFeatures(true);
+
+ return af;
+ }
+
+ protected AlignFrame setupAlignmentViewWithoutSS(String type) {
+
+ SequenceI s1 = new Sequence("s1", "FR S");
+ SequenceI s2 = new Sequence("s2", "FSJL");
+
+ s1.addSequenceFeature(
+ new SequenceFeature("chain", null, 1, 3, 0f, null));
+ s1.addSequenceFeature(
+ new SequenceFeature("domain", null, 1, 3, 0f, null));
+ s2.addSequenceFeature(
+ new SequenceFeature("chain", null, 1, 4, 0f, null));
+ s2.addSequenceFeature(
+ new SequenceFeature("metal", null, 1, 4, 0f, null));
+ s2.addSequenceFeature(
+ new SequenceFeature("Pfam", null, 1, 4, 0f, null));
+
+ if(!type.equals("both")) {
+ Annotation ssE = new Annotation("","",'E',0);
+ Annotation ssH = new Annotation("","",'H',0);
+ Annotation ssC = new Annotation(".","",' ',0);
+
+ Annotation[] anns1;
+
+ anns1 = new Annotation[] { ssH, ssE, ssC};
+
+ AlignmentAnnotation ann1 = new AlignmentAnnotation("Secondary Structure",
+ "Secondary Structure", anns1);
+
+ s1.addAlignmentAnnotation(ann1);
+ }
+
+ AlignmentI al = new Alignment(new SequenceI[] { s1, s2 });
+ AlignFrame af = new AlignFrame(al, 300, 300);
+ af.setShowSeqFeatures(true);
+ af.getFeatureRenderer().findAllFeatures(true);
+ return af;
+ }
+
+
+ @DataProvider(name = "testData")
+ public Object[][] testData() {
+ return new Object[][] {
+ {"All Similar", 1d, 1d, 0d, 0d / 4},
+ {"Partially Similar", 1d, 1d, 0d, 0d},
+ {"Not Similar", 1d, 1d, 0d, 0d},
+ {"With Coil", 1d, 1d, 0d, 0d},
+ };
+ }
+
+ @Test(dataProvider = "testData")
+ public void testFindDistances(String scenario, double expectedValue00, double expectedValue11,
+ double expectedValue01, double expectedValue10) {
+ AlignFrame af = setupAlignmentView(scenario);
+ AlignViewport viewport = af.getViewport();
+ AlignmentView view = viewport.getAlignmentView(false);
+
+ ScoreModelI sm = new SecondaryStructureDistanceModel();
+ sm = ScoreModels.getInstance().getScoreModel(sm.getName(),
+ af.alignPanel);
+
+ SimilarityParamsI params = new SimilarityParams(false, true, true, true);
+ params.setSecondaryStructureSource("3D Structures");
+ MatrixI distances = sm.findDistances(view, params);
+
+ assertEquals(distances.getValue(0, 0), expectedValue00);
+ assertEquals(distances.getValue(1, 1), expectedValue11);
+ assertEquals(distances.getValue(0, 1), expectedValue01);
+ assertEquals(distances.getValue(1, 0), expectedValue10);
+ }
+
+
+}
* peptide models for PCA
*/
List<ScoreModelI> filtered = CalculationChooser
- .getApplicableScoreModels(false, true);
- assertEquals(filtered.size(), 4);
+ .getApplicableScoreModels(false, true, true);
+ assertEquals(filtered.size(), 5);
assertSame(filtered.get(0), blosum62);
assertSame(filtered.get(1), pam250);
assertEquals(filtered.get(2).getName(), "PID");
assertEquals(filtered.get(3).getName(), "Sequence Feature Similarity");
+ assertEquals(filtered.get(4).getName(), "Secondary Structure Similarity");
/*
* peptide models for Tree are the same
*/
- filtered = CalculationChooser.getApplicableScoreModels(false, false);
- assertEquals(filtered.size(), 4);
+ filtered = CalculationChooser.getApplicableScoreModels(false, false, true);
+ assertEquals(filtered.size(), 5);
assertSame(filtered.get(0), blosum62);
assertSame(filtered.get(1), pam250);
assertEquals(filtered.get(2).getName(), "PID");
assertEquals(filtered.get(3).getName(), "Sequence Feature Similarity");
+ assertEquals(filtered.get(4).getName(), "Secondary Structure Similarity");
/*
* nucleotide models for PCA
*/
- filtered = CalculationChooser.getApplicableScoreModels(true, true);
+ filtered = CalculationChooser.getApplicableScoreModels(true, true, false);
assertEquals(filtered.size(), 3);
assertSame(filtered.get(0), dna);
assertEquals(filtered.get(1).getName(), "PID");
/*
* nucleotide models for Tree are the same
*/
- filtered = CalculationChooser.getApplicableScoreModels(true, false);
+ filtered = CalculationChooser.getApplicableScoreModels(true, false, false);
assertEquals(filtered.size(), 3);
assertSame(filtered.get(0), dna);
assertEquals(filtered.get(1).getName(), "PID");
/*
* nucleotide models for Tree are unchanged
*/
- filtered = CalculationChooser.getApplicableScoreModels(true, false);
- assertEquals(filtered.size(), 3);
+ filtered = CalculationChooser.getApplicableScoreModels(true, false, true);
+ assertEquals(filtered.size(), 4);
assertSame(filtered.get(0), dna);
assertEquals(filtered.get(1).getName(), "PID");
assertEquals(filtered.get(2).getName(), "Sequence Feature Similarity");
+ assertEquals(filtered.get(3).getName(), "Secondary Structure Similarity");
/*
* nucleotide models for PCA add BLOSUM62 as last option
*/
- filtered = CalculationChooser.getApplicableScoreModels(true, true);
+ filtered = CalculationChooser.getApplicableScoreModels(true, true, false);
assertEquals(filtered.size(), 4);
assertSame(filtered.get(0), dna);
assertEquals(filtered.get(1).getName(), "PID");
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;
+ }
+
+ @Override
+ public int getSeqWithSSCount()
+ {
+ // TODO Auto-generated method stub
+ return 0;
+ }
};
}
import jalview.gui.JvOptionPane;
import java.awt.Color;
+import java.awt.Container;
import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Random;
import org.testng.AssertJUnit;
field.set(vs,
Color.RED.equals(field.get(vs)) ? Color.BLACK : Color.RED);
}
+ else if (type.equals(java.util.List.class))
+ {
+ List<?> list = (List<?>) field.get(vs);
+ List<Object> mutableList = new ArrayList<>(list);
+ mutableList.add("All");
+ field.set(vs, mutableList);
+ }
else
{
AssertJUnit.fail("Unhandled field type (add to test): "