From 9f21fcf9df545f0900a0f86250a14f15c448e30a Mon Sep 17 00:00:00 2001 From: Renia Correya Date: Mon, 13 May 2024 10:23:02 +0100 Subject: [PATCH] JAL-4386 - Implementation of substitution matrix and test cases. --- resources/lang/Messages.properties | 1 + resources/scoreModel/secondarystructure.scm | 14 ++ src/jalview/analysis/AAFrequency.java | 60 ++---- src/jalview/analysis/AlignmentUtils.java | 76 +++++-- src/jalview/analysis/scoremodels/ScoreModels.java | 11 +- .../SecondaryStructureDistanceModel.java | 219 +++++--------------- src/jalview/appletgui/AlignFrame.java | 3 + src/jalview/gui/CalculationChooser.java | 8 +- src/jalview/jbgui/GAlignFrame.java | 10 + src/jalview/renderer/AnnotationRenderer.java | 4 + src/jalview/schemes/ResidueProperties.java | 21 ++ src/jalview/util/Constants.java | 49 +++++ test/jalview/analysis/AlignmentUtilsTests.java | 159 ++++++++++++++ .../SecondaryStructureDistanceModelTest.java | 206 +++--------------- test/jalview/bin/CommandsTest2.java | 12 +- test/jalview/gui/AnnotationChooserTest.java | 67 +++--- test/jalview/gui/AnnotationRowFilterTest.java | 2 +- test/jalview/gui/StructureChooserTest.java | 12 +- 18 files changed, 491 insertions(+), 443 deletions(-) create mode 100644 resources/scoreModel/secondarystructure.scm create mode 100644 src/jalview/util/Constants.java diff --git a/resources/lang/Messages.properties b/resources/lang/Messages.properties index 195eb1f..349340f 100644 --- a/resources/lang/Messages.properties +++ b/resources/lang/Messages.properties @@ -283,6 +283,7 @@ 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.select_secondary_structure_preference = Secondary Structure Preference label.show_first = Show first label.show_last = Show last label.struct_from_pdb = Process secondary structure from PDB diff --git a/resources/scoreModel/secondarystructure.scm b/resources/scoreModel/secondarystructure.scm new file mode 100644 index 0000000..f56986f --- /dev/null +++ b/resources/scoreModel/secondarystructure.scm @@ -0,0 +1,14 @@ +ScoreMatrix SECONDARYSTRUCTURE +# +# The SECONDARY STRUCTURE substitution matrix, as in +# 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 diff --git a/src/jalview/analysis/AAFrequency.java b/src/jalview/analysis/AAFrequency.java index 796625a..ea02228 100755 --- a/src/jalview/analysis/AAFrequency.java +++ b/src/jalview/analysis/AAFrequency.java @@ -31,9 +31,11 @@ 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; @@ -55,8 +57,6 @@ import java.util.List; public class AAFrequency { public static final String PROFILE = "P"; - private static final String SS_ANNOTATION_LABEL = "Secondary Structure"; - private static final char COIL = 'C'; /* * Quick look-up of String value of char 'A' to 'Z' @@ -231,23 +231,13 @@ public class AAFrequency public static final ProfilesI calculateSS(final SequenceI[] sequences, int width, int start, int end, boolean saveFullProfile) { - // long now = System.currentTimeMillis(); + int seqCount = sequences.length; ProfileI[] result = new ProfileI[width]; for (int column = start; column < end; column++) { - /* - * Apply a heuristic to detect nucleotide data (which can - * be counted in more compact arrays); here we test for - * more than 90% nucleotide; recheck every 10 columns in case - * of misleading data e.g. highly conserved Alanine in peptide! - * Mistakenly guessing nucleotide has a small performance cost, - * as it will result in counting in sparse arrays. - * Mistakenly guessing peptide has a small space cost, - * as it will use a larger than necessary array to hold counts. - */ int ssCount = 0; @@ -263,39 +253,27 @@ public class AAFrequency } char c = sequences[row].getCharAt(column); + AlignmentAnnotation[] aa = sequences[row].getAnnotation(Constants.SS_ANNOTATION_LABEL); + if(aa == null) { + aa = sequences[row].getAnnotation(Constants.SS_ANNOTATION_FROM_JPRED_LABEL); + } + if(aa!=null) { + ssCount++; + } - if (sequences[row].getLength() > column && !Comparison.isGap(c)) + if (sequences[row].getLength() > column && !Comparison.isGap(c) && aa !=null) { - AlignmentAnnotation[] aa = sequences[row].getAnnotation(SS_ANNOTATION_LABEL); - if(aa == null) { - continue; - } int seqPosition = sequences[row].findPosition(column); - char ss; - if (aa[0].getAnnotationForPosition(seqPosition) != null) { - ss = aa[0].getAnnotationForPosition(seqPosition).secondaryStructure; - - //There is no representation for coil and it can be either ' ' or null. - if (ss == ' ') { - ss = COIL; - } - } - else { - ss = COIL; - } - - //secondaryStructures[row][column] = ss; - - ssCounts.add(ss); - ssCount++; + char ss = AlignmentUtils.findSSAnnotationForGivenSeqposition( + aa, seqPosition); + if(ss == '*') { + continue; + } + ssCounts.add(ss); } - else - { - /* - * count a gap if the sequence doesn't reach this column - */ + else if(Comparison.isGap(c) && aa!=null) { ssCounts.addGap(); } } @@ -314,8 +292,6 @@ public class AAFrequency result[column] = profile; } return new Profiles(result); - // long elapsed = System.currentTimeMillis() - now; - // jalview.bin.Console.outPrintln(elapsed); } /** diff --git a/src/jalview/analysis/AlignmentUtils.java b/src/jalview/analysis/AlignmentUtils.java index d88950c..798b4bc 100644 --- a/src/jalview/analysis/AlignmentUtils.java +++ b/src/jalview/analysis/AlignmentUtils.java @@ -20,6 +20,7 @@ */ package jalview.analysis; +import java.awt.Color; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -46,11 +47,13 @@ import jalview.datamodel.AlignedCodonFrame.SequenceToSequenceMapping; 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.SeqCigar; import jalview.datamodel.Sequence; import jalview.datamodel.SequenceFeature; import jalview.datamodel.SequenceGroup; @@ -60,6 +63,7 @@ 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; @@ -77,18 +81,7 @@ public class AlignmentUtils { private static final int CODON_LENGTH = 3; - private static final String SEQUENCE_VARIANT = "sequence_variant:"; - - - private static final Map SECONDARY_STRUCTURE_LABELS = new HashMap<>(); - - static { - SECONDARY_STRUCTURE_LABELS.put("Secondary Structure", "3D Structures"); - SECONDARY_STRUCTURE_LABELS.put("jnetpred", "JPred"); - // Add other secondary structure labels here if needed - } - - private static final String SS_ANNOTATION_LABEL = "Secondary Structure"; + private static final String SEQUENCE_VARIANT = "sequence_variant:"; /* * the 'id' attribute is provided for variant features fetched from @@ -1552,11 +1545,9 @@ public class AlignmentUtils for (SequenceI seq : annotations.keySet()) { - for (AlignmentAnnotation ann : annotations.get(seq)) + if(isSecondaryStructurePresent(annotations.get(seq).toArray(new AlignmentAnnotation[0]))) { - if(ann.getDescription(false).startsWith(SS_ANNOTATION_LABEL)) { - return true; - } + return true; } } return false; @@ -2868,8 +2859,8 @@ public class AlignmentUtils for (AlignmentAnnotation annotation : annotations) { String label = annotation.label; - if (SECONDARY_STRUCTURE_LABELS.containsKey(label) && !addedLabels.contains(label)) { - ssSources.add(SECONDARY_STRUCTURE_LABELS.get(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 } } @@ -2887,7 +2878,7 @@ public class AlignmentUtils break; } - if (SECONDARY_STRUCTURE_LABELS.containsKey(aa.label)) { + if (Constants.SECONDARY_STRUCTURE_LABELS.containsKey(aa.label)) { ssPresent = true; break; } @@ -2896,4 +2887,51 @@ public class AlignmentUtils 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[0].getAnnotationForPosition(seqPosition) != null) { + Annotation a = aa[0].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 String getSSSourceFromAnnotationDescription(AlignmentAnnotation[] annotations) + { + String ssSource = null; + + return ssSource; + + } + } diff --git a/src/jalview/analysis/scoremodels/ScoreModels.java b/src/jalview/analysis/scoremodels/ScoreModels.java index dd1bc9d..1c47968 100644 --- a/src/jalview/analysis/scoremodels/ScoreModels.java +++ b/src/jalview/analysis/scoremodels/ScoreModels.java @@ -40,6 +40,8 @@ public class ScoreModels private final ScoreMatrix PAM250; private final ScoreMatrix DNA; + + private final ScoreMatrix SECONDARYSTRUCTURE; private static ScoreModels instance; @@ -83,7 +85,9 @@ public class ScoreModels DNA = loadScoreMatrix("scoreModel/dna.scm"); registerScoreModel(new PIDModel()); registerScoreModel(new FeatureDistanceModel()); - registerScoreModel(new SecondaryStructureDistanceModel()); + SECONDARYSTRUCTURE = loadScoreMatrix("scoreModel/secondarystructure.scm"); + registerScoreModel(new SecondaryStructureDistanceModel()); + } /** @@ -180,4 +184,9 @@ public class ScoreModels { return PAM250; } + + public ScoreMatrix getSecondaryStructureMatrix() + { + return SECONDARYSTRUCTURE; + } } diff --git a/src/jalview/analysis/scoremodels/SecondaryStructureDistanceModel.java b/src/jalview/analysis/scoremodels/SecondaryStructureDistanceModel.java index 1dcf297..5b0f242 100644 --- a/src/jalview/analysis/scoremodels/SecondaryStructureDistanceModel.java +++ b/src/jalview/analysis/scoremodels/SecondaryStructureDistanceModel.java @@ -20,6 +20,7 @@ */ package jalview.analysis.scoremodels; +import jalview.analysis.AlignmentUtils; import jalview.api.AlignmentViewPanel; import jalview.api.FeatureRenderer; import jalview.api.analysis.ScoreModelI; @@ -30,6 +31,7 @@ import jalview.datamodel.Annotation; import jalview.datamodel.SeqCigar; import jalview.math.Matrix; import jalview.math.MatrixI; +import jalview.util.Constants; import jalview.util.SetUtils; import java.util.HashMap; @@ -38,51 +40,27 @@ import java.util.Map; import java.util.Set; /* This class contains methods to calculate distance score between - * secondary structure annotations of the sequences. The inverse of - * the score is later calculated for similarity score. + * secondary structure annotations of the sequences. */ public class SecondaryStructureDistanceModel extends DistanceScoreModel { private static final String NAME = "Secondary Structure Similarity"; - - //label in secondary structure annotation data model from 3d structures - private static final String SS_ANNOTATION_LABEL = "Secondary Structure"; - - //label in secondary structure annotation data model from JPred - private static final String SS_ANNOTATION_FROM_JPRED_LABEL = "jnetpred"; - //label in secondary structure annotation data model from JPred - private static final String JPRED_WEBSERVICE = "JPred"; - - private String description; - - //maximum distance score is defined as 2 as the possible number of unique secondary structure is 2. - private static final int MAX_SCORE = 2; + private ScoreMatrix ssRateMatrix; - //minimum distance score is defined as 2 as the possible number of unique secondary structure is 2. - private static final int MIN_SCORE = 0; - - //character used to represent coil in secondary structure - private static final char COIL = 'C'; + private String description; FeatureRenderer fr; - /* - * Annotation label for available sources of secondary structure - */ - private static final String[] SS_ANNOTATION_LABELS = { - SS_ANNOTATION_LABEL, - SS_ANNOTATION_FROM_JPRED_LABEL - }; - + /** * Constructor */ public SecondaryStructureDistanceModel() { - + } - + @Override public ScoreModelI getInstance(AlignmentViewPanel view) { @@ -109,28 +87,11 @@ public class SecondaryStructureDistanceModel extends DistanceScoreModel fr = view.cloneFeatureRenderer(); return true; } - - /** - * Calculates a distance measure [i][j] between each pair of sequences as the - * average number of features they have but do not share. That is, find the - * features each sequence pair has at each column, ignore feature types they - * have in common, and count the rest. The totals are normalised by the number - * of columns processed. - *

- * The parameters argument provides settings for treatment of gap-residue - * aligned positions, and whether the score is over the longer or shorter of - * each pair of sequences - * - * @param seqData - * @param params - */ /** * Calculates distance score [i][j] between each pair of protein sequences - * based on their secondary structure annotations (H, E, C). That is, find the - * secondary structures each sequence has at each column and scores positively for - * each non similar secondary structure annotations. Scores 0 for similar secondary - * structure annotations. The final score is normalized by the number of + * 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. *

* The parameters argument can include settings for handling gap-residue aligned @@ -139,7 +100,7 @@ public class SecondaryStructureDistanceModel extends DistanceScoreModel * sequences of significantly different lengths. * * @param seqData The aligned sequence data including secondary structure annotations. - * @param params Additional parameters for customizing the scoring process, such as gap + * @param params Additional parameters for customising the scoring process, such as gap * handling and sequence length consideration. */ @Override @@ -150,16 +111,18 @@ public class SecondaryStructureDistanceModel extends DistanceScoreModel SeqCigar[] seqs = seqData.getSequences(); int noseqs = seqs.length; //no of sequences int cpwidth = 0; // = seqData.getWidth(); - double[][] distances = new double[noseqs][noseqs]; //matrix to store distance score - double[][] substitutionMatrix = getSubstitutionMatrix(); + 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(); + ssRateMatrix = ScoreModels.getInstance().getSecondaryStructureMatrix(); //defining the default value for secondary structure source as 3d structures //or JPred if user selected JPred - String selectedSSSource = SS_ANNOTATION_LABEL; - if(ssSource.equals(JPRED_WEBSERVICE)) - selectedSSSource = SS_ANNOTATION_FROM_JPRED_LABEL; + String selectedSSSource = Constants.SS_ANNOTATION_LABEL; + if(ssSource.equals(Constants.SECONDARY_STRUCTURE_LABELS.get(Constants.SS_ANNOTATION_FROM_JPRED_LABEL))) + { + selectedSSSource = Constants.SS_ANNOTATION_FROM_JPRED_LABEL; + } // need to get real position for view position int[] viscont = seqData.getVisibleContigs(); @@ -196,7 +159,7 @@ public class SecondaryStructureDistanceModel extends DistanceScoreModel = findSeqsWithUndefinedSS(seqs, ssAlignmentAnnotationForSequences); /* - * scan each column, compute and add to each distance[i, j] + * scan each column, compute and add to each similarity[i, j] * the number of secondary structure annotation that seqi * and seqj do not share */ @@ -205,7 +168,7 @@ public class SecondaryStructureDistanceModel extends DistanceScoreModel //Iterates for each column position for (int cpos = viscont[vc]; cpos <= viscont[vc + 1]; cpos++) { - cpwidth++; //used to normalise the distance score + cpwidth++; //used to normalise the similarity score /* * get set of sequences without gap in the current column @@ -213,8 +176,8 @@ public class SecondaryStructureDistanceModel extends DistanceScoreModel Set seqsWithoutGapAtCol = findSeqsWithoutGapAtColumn(seqs, cpos); /* - * count score for each dissimilar secondary structure annotation on i'th and j'th - * sequence. Igonre if similar and add this 'distance' measure to the total + * 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++) @@ -230,15 +193,15 @@ public class SecondaryStructureDistanceModel extends DistanceScoreModel boolean undefinedSS1 = seqsWithUndefinedSS.contains(sc1); boolean undefinedSS2 = seqsWithUndefinedSS.contains(sc2); - // Set distance to 0 if both SS are not defined + // Set similarity to max score if both SS are not defined if (undefinedSS1 && undefinedSS2) { - distances[i][j] += MIN_SCORE; + similarities[i][j] += ssRateMatrix.getMaximumScore(); continue; } - // Set distance to maximum score if either one SS is not defined + // Set similarity to minimum score if either one SS is not defined else if(undefinedSS1 || undefinedSS2) { - distances[i][j] += MAX_SCORE; + similarities[i][j] += ssRateMatrix.getMinimumScore(); continue; } @@ -247,31 +210,33 @@ public class SecondaryStructureDistanceModel extends DistanceScoreModel boolean gap2 = !seqsWithoutGapAtCol.contains(sc2); //Variable to store secondary structure at the current column - char ss1 = 'G', ss2 = 'G'; + char ss1 = '*'; + char ss2 = '*'; //secondary structure is fetched only if the current column is not //gap for the sequence - if(!gap1 && !undefinedSS1) { + if(!gap1 && !undefinedSS1) { + //fetch the position in sequence for the column and finds the + //corresponding secondary structure annotation + //TO DO - consider based on priority + int seqPosition = seqs[i].findPosition(cpos); + AlignmentAnnotation[] aa = seqs[i].getRefSeq().getAnnotation(selectedSSSource); ss1 = - findSSAnnotationForGivenSeqAndCol(seqs[i], cpos); + AlignmentUtils.findSSAnnotationForGivenSeqposition(aa, seqPosition); } if(!gap2 && !undefinedSS2) { - ss2 = - findSSAnnotationForGivenSeqAndCol(seqs[j], cpos); + int seqPosition = seqs[j].findPosition(cpos); + AlignmentAnnotation[] aa = seqs[j].getRefSeq().getAnnotation(selectedSSSource); + ss2 = + AlignmentUtils.findSSAnnotationForGivenSeqposition(aa, seqPosition); } - /* - * gap-gap scores zero - * similar ss-ss scores zero - * different ss-ss scores 1 - * gap-ss scores 1 if params say to do so - */ if ((!gap1 && !gap2) || params.includeGaps()) { - // Calculate distance score based on the substitution matrix - double seqDistance = substitutionMatrix[getSubstitutionMatrixIndex(ss1)][getSubstitutionMatrixIndex(ss2)]; - distances[i][j] += seqDistance; + // Calculate similarity score based on the substitution matrix + double similarityScore = ssRateMatrix.getPairwiseScore(ss1, ss2); + similarities[i][j] += similarityScore; } } } @@ -279,20 +244,22 @@ public class SecondaryStructureDistanceModel extends DistanceScoreModel } /* - * normalise the distance scores (summed over columns) by the + * 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++) - { - distances[i][j] /= cpwidth; - distances[j][i] = distances[i][j]; + { + similarities[i][j] /= cpwidth; + similarities[j][i] = similarities[i][j]; } } - return new Matrix(distances); + return ssRateMatrix.similarityToDistance(new Matrix(similarities)); + } /** @@ -304,7 +271,7 @@ public class SecondaryStructureDistanceModel extends DistanceScoreModel * (0..) * @return */ - protected Set findSeqsWithoutGapAtColumn( + private Set findSeqsWithoutGapAtColumn( SeqCigar[] seqs, int columnPosition) { Set seqsWithoutGapAtCol = new HashSet<>(); @@ -335,7 +302,7 @@ public class SecondaryStructureDistanceModel extends DistanceScoreModel * @param ssAlignmentAnnotationForSequences * @return */ - protected Set findSeqsWithUndefinedSS(SeqCigar[] seqs, + private Set findSeqsWithUndefinedSS(SeqCigar[] seqs, Map> ssAlignmentAnnotationForSequences) { Set seqsWithUndefinedSS = new HashSet<>(); for (SeqCigar seq : seqs) { @@ -361,103 +328,27 @@ public class SecondaryStructureDistanceModel extends DistanceScoreModel */ private boolean isSSUndefinedOrNotAdded(SeqCigar seq, Map> ssAlignmentAnnotationForSequences) { - for (String label : SS_ANNOTATION_LABELS) { + for (String label : Constants.SECONDARY_STRUCTURE_LABELS.keySet()) { AlignmentAnnotation[] annotations = seq.getRefSeq().getAnnotation(label); if (annotations != null) { for (AlignmentAnnotation annotation : annotations) { HashSet descriptionSet = ssAlignmentAnnotationForSequences .get(annotation.sequenceRef.getName()); if (descriptionSet != null) + { if (descriptionSet.contains(annotation.description)) { // Secondary structure annotation is present and //added to the track, no need to add seq return false; } + } } } } // Either annotations are undefined or not added to the track return true; } - - - /** - * Finds secondary structure annotation for a given sequence (SeqCigar) - * and column position corresponding to the sequence. - * - * @param seq - * @param columnPosition - * (0..) - * @return - */ - private char findSSAnnotationForGivenSeqAndCol( - SeqCigar seq, int columnPosition) - { - char ss = 'G'; - - //fetch the position in sequence for the column and finds the - //corresponding secondary structure annotation - //TO DO - consider based on priority - int seqPosition = seq.findPosition(columnPosition); - AlignmentAnnotation[] aa = seq.getRefSeq().getAnnotation(SS_ANNOTATION_LABEL); - - if(aa == null) { - aa = seq.getRefSeq().getAnnotation(SS_ANNOTATION_FROM_JPRED_LABEL); - } - - if (aa != null) { - if (aa[0].getAnnotationForPosition(seqPosition) != null) { - Annotation a = aa[0].getAnnotationForPosition(seqPosition); - ss = a.secondaryStructure; - - //There is no representation for coil and it can be either ' ' or null. - if (ss == ' ' || ss == '-') { - ss = COIL; - } - } - else { - ss = COIL; - } - - } - - return ss; - } - - /** - * Retrieve the substitution matrix. - * - * @return The substitution matrix. - */ - private double[][] getSubstitutionMatrix() { - // Defining the substitution matrix - // This matrix map distance scores between secondary structure symbols - return new double[][]{ - // C E H G - {0.0, 1.0, 1.0, 1.0}, // C - COIL - {1.0, 0.0, 1.0, 1.0}, // E - SHEET - {1.0, 1.0, 0.0, 1.0}, // H - HELIX - {1.0, 1.0, 1.0, 0.0} // G - GAP - - }; - } - - private int getSubstitutionMatrixIndex(char ss) { - switch (ss) { - case 'C': - return 0; - case 'E': - return 1; - case 'H': - return 2; - case 'G': - return 3; - default: - throw new IllegalArgumentException("Invalid secondary structure character: " + ss); - } - } - @Override public String getName() { @@ -491,7 +382,7 @@ public class SecondaryStructureDistanceModel extends DistanceScoreModel @Override public String toString() { - return "Score between sequences based on hamming distance between binary " + return "Score between sequences based on similarity between binary " + "vectors marking secondary structure displayed at each column"; } } \ No newline at end of file diff --git a/src/jalview/appletgui/AlignFrame.java b/src/jalview/appletgui/AlignFrame.java index f502952..55a5364 100644 --- a/src/jalview/appletgui/AlignFrame.java +++ b/src/jalview/appletgui/AlignFrame.java @@ -3431,6 +3431,9 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener, 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); diff --git a/src/jalview/gui/CalculationChooser.java b/src/jalview/gui/CalculationChooser.java index 7747a6b..d05aa03 100644 --- a/src/jalview/gui/CalculationChooser.java +++ b/src/jalview/gui/CalculationChooser.java @@ -605,10 +605,16 @@ public class CalculationChooser extends JPanel { boolean doPCA = pca.isSelected(); String modelName = modelNames.getSelectedItem().toString(); - String ssSource = ssSourceDropdown.getSelectedItem().toString(); + String ssSource = ""; + Object selectedItem = ssSourceDropdown.getSelectedItem(); + if (selectedItem != null) { + ssSource = selectedItem.toString(); + } SimilarityParams params = getSimilarityParameters(doPCA); if(ssSource.length()>0) + { params.setSecondaryStructureSource(ssSource); + } if (doPCA) { openPcaPanel(modelName, params); diff --git a/src/jalview/jbgui/GAlignFrame.java b/src/jalview/jbgui/GAlignFrame.java index da35bd4..dd66811 100755 --- a/src/jalview/jbgui/GAlignFrame.java +++ b/src/jalview/jbgui/GAlignFrame.java @@ -23,6 +23,7 @@ package jalview.jbgui; import java.awt.BorderLayout; import java.awt.Color; import java.awt.GridLayout; +import java.awt.Menu; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.FocusAdapter; @@ -193,6 +194,10 @@ public class GAlignFrame extends JInternalFrame protected JMenuItem gatherViews = new JMenuItem(); protected JMenuItem expandViews = new JMenuItem(); + + protected JCheckBoxMenuItem threeDStructure = new JCheckBoxMenuItem(); + + protected JCheckBoxMenuItem jPred = new JCheckBoxMenuItem(); protected JCheckBoxMenuItem showGroupConsensus = new JCheckBoxMenuItem(); @@ -1799,6 +1804,9 @@ public class GAlignFrame extends JInternalFrame JMenu autoAnnMenu = new JMenu( MessageManager.getString("label.autocalculated_annotation")); + JMenu selectSS = new JMenu( + MessageManager.getString("label.select_secondary_structure_preference")); + JMenu exportImageMenu = new JMenu( MessageManager.getString("label.export_image")); JMenu fileMenu = new JMenu(MessageManager.getString("action.file")); @@ -1911,6 +1919,8 @@ public class GAlignFrame extends JInternalFrame autoAnnMenu.add(showGroupConservation); autoAnnMenu.add(showGroupConsensus); annotationsMenu.add(autoAnnMenu); + selectSS.add(threeDStructure); + selectSS.add(jPred); sort.add(sortIDMenuItem); sort.add(sortLengthMenuItem); diff --git a/src/jalview/renderer/AnnotationRenderer.java b/src/jalview/renderer/AnnotationRenderer.java index 015db5c..a56f06c 100644 --- a/src/jalview/renderer/AnnotationRenderer.java +++ b/src/jalview/renderer/AnnotationRenderer.java @@ -38,6 +38,7 @@ 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; @@ -1617,6 +1618,9 @@ public class AnnotationRenderer colour = profcolour.findColour(codonTranslation.charAt(0), column, null); } + if(_aa.label == "SecondaryStructureConsensus") { + colour = AlignmentUtils.getSecondaryStructureAnnotationColour(dc[0]); + } else { diff --git a/src/jalview/schemes/ResidueProperties.java b/src/jalview/schemes/ResidueProperties.java index e297ff6..2fcb95f 100755 --- a/src/jalview/schemes/ResidueProperties.java +++ b/src/jalview/schemes/ResidueProperties.java @@ -41,6 +41,8 @@ public class ResidueProperties public static final int[] nucleotideIndex; public static final int[] purinepyrimidineIndex; + + public static final int[] secondaryStructureIndex; public static final Map aa3Hash = new HashMap<>(); @@ -195,6 +197,19 @@ public class ResidueProperties 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); @@ -383,6 +398,12 @@ public class ResidueProperties 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 diff --git a/src/jalview/util/Constants.java b/src/jalview/util/Constants.java new file mode 100644 index 0000000..bced9c8 --- /dev/null +++ b/src/jalview/util/Constants.java @@ -0,0 +1,49 @@ +/* + * 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 . + * 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 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 + } +} diff --git a/test/jalview/analysis/AlignmentUtilsTests.java b/test/jalview/analysis/AlignmentUtilsTests.java index f017662..eee5e87 100644 --- a/test/jalview/analysis/AlignmentUtilsTests.java +++ b/test/jalview/analysis/AlignmentUtilsTests.java @@ -28,16 +28,20 @@ import static org.testng.AssertJUnit.assertNull; 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.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; @@ -78,6 +82,25 @@ public class AlignmentUtilsTests { 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" }) @@ -2751,4 +2774,140 @@ public class AlignmentUtilsTests && al.getAlignmentAnnotation().length == 2); } + + @Test(groups = "Functional", dataProvider = "SecondaryStructureAnnotations") + public void testSecondaryStructurePresentAndSources(AlignmentAnnotation[] annotations, boolean expectedSSPresent, ArrayList 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 ssSources1 = new ArrayList<>(Arrays.asList("3D Structures")); + List ssSources2 = new ArrayList<>(Arrays.asList("JPred")); + List ssSources3 = new ArrayList<>(Arrays.asList("3D Structures", "JPred")); + List 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> annotations, boolean expectedPresence) { + boolean actualPresence = AlignmentUtils.isSSAnnotationPresent(annotations); + Assert.assertEquals(actualPresence, expectedPresence); + } + + @DataProvider(name = "SSAnnotationPresence") + public static Object[][] provideSSAnnotationPresence() { + Map> annotations1 = new HashMap<>(); + SequenceI seq1 = new Sequence("Seq1", "ASD---ASD---ASD", 37, 45); + List annotationsList1 = new ArrayList<>(); + annotationsList1.add(new AlignmentAnnotation("Secondary Structure", "Secondary Structure", new Annotation[]{})); + annotations1.put(seq1, annotationsList1); // Annotation present secondary structure for seq1 + + Map> annotations2 = new HashMap<>(); + SequenceI seq2 = new Sequence("Seq2", "ASD---ASD------", 37, 42); + List 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> annotations3 = new HashMap<>(); + // Empty annotation map + + Map> annotations4 = new HashMap<>(); + SequenceI seq4 = new Sequence("Seq4", "ASD---ASD---AS-", 37, 44); + List 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(dataProvider = "SSSourceFromAnnotationDescription") +// public void testGetSSSourceFromAnnotationDescription(Map> annotations, String expectedSSSource) { +// String actualSSSource = AlignmentUtils.getSSSourceFromAnnotationDescription(annotations); +// Assert.assertEquals(actualSSSource, expectedSSSource); +// } + + @DataProvider(name = "SSSourceFromAnnotationDescription") + public static Object[][] provideSSSourceFromAnnotationDescription() { + Map> annotations1 = new HashMap<>(); + SequenceI seq1 = new Sequence("Seq1", "ASD---ASD---ASD", 37, 45); + List annotationsList1 = new ArrayList<>(); + annotationsList1.add(new AlignmentAnnotation("jnetpred", "JPred Output", new Annotation[]{})); + annotations1.put(seq1, annotationsList1); // Annotation present from JPred for seq1 + + Map> annotations2 = new HashMap<>(); + SequenceI seq2 = new Sequence("Seq2", "ASD---ASD------", 37, 42); + List 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> annotations3 = new HashMap<>(); + // Empty annotation map + + Map> annotations4 = new HashMap<>(); + SequenceI seq4 = new Sequence("Seq4", "ASD---ASD---AS-", 37, 44); + List 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> annotations5 = new HashMap<>(); + SequenceI seq5 = new Sequence("Seq5", "ASD---ASD---AS-", 37, 44); + List 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"} + }; + } + } diff --git a/test/jalview/analysis/scoremodels/SecondaryStructureDistanceModelTest.java b/test/jalview/analysis/scoremodels/SecondaryStructureDistanceModelTest.java index 68c740c..f250525 100644 --- a/test/jalview/analysis/scoremodels/SecondaryStructureDistanceModelTest.java +++ b/test/jalview/analysis/scoremodels/SecondaryStructureDistanceModelTest.java @@ -42,183 +42,12 @@ 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 { - - @BeforeClass(alwaysRun = true) - public void setUpJvOptionPane() - { - JvOptionPane.setInteractiveMode(false); - JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION); - } - - public static String alntestFile = "FER1_MESCR/72-76 DVYIL\nFER1_SPIOL/71-75 DVYIL\nFER3_RAPSA/21-25 DVYVL\nFER1_MAIZE/73-77 DVYIL\n"; - - int[] sf1 = new int[] { 74, 74, 73, 73, 23, 23, -1, -1 }; - - int[] sf2 = new int[] { -1, -1, 74, 75, -1, -1, 76, 77 }; - - int[] sf3 = new int[] { -1, -1, -1, -1, -1, -1, 76, 77 }; - - /** - *

-   * Load test alignment and add features to sequences: 
-   *      FER1_MESCR FER1_SPIOL FER3_RAPSA FER1_MAIZE 
-   *  sf1     X          X          X  
-   *  sf2                X                     X 
-   *  sf3                                      X
-   * 
- * - * @return - */ - public AlignFrame getTestAlignmentFrame() - { - AlignFrame alf = new FileLoader(false) - .LoadFileWaitTillLoaded(alntestFile, DataSourceType.PASTE); - AlignmentI al = alf.getViewport().getAlignment(); - Assert.assertEquals(al.getHeight(), 4); - Assert.assertEquals(al.getWidth(), 5); - for (int i = 0; i < 4; i++) - { - SequenceI ds = al.getSequenceAt(i).getDatasetSequence(); - if (sf1[i * 2] > 0) - { - ds.addSequenceFeature(new SequenceFeature("sf1", "sf1", sf1[i * 2], - sf1[i * 2 + 1], "sf1")); - } - if (sf2[i * 2] > 0) - { - ds.addSequenceFeature(new SequenceFeature("sf2", "sf2", sf2[i * 2], - sf2[i * 2 + 1], "sf2")); - } - if (sf3[i * 2] > 0) - { - ds.addSequenceFeature(new SequenceFeature("sf3", "sf3", sf3[i * 2], - sf3[i * 2 + 1], "sf3")); - } - } - alf.setShowSeqFeatures(true); - alf.getFeatureRenderer().setVisible("sf1"); - alf.getFeatureRenderer().setVisible("sf2"); - alf.getFeatureRenderer().setVisible("sf3"); - alf.getFeatureRenderer().findAllFeatures(true); - Assert.assertEquals( - alf.getFeatureRenderer().getDisplayedFeatureTypes().size(), 3, - "Number of feature types"); - assertTrue(alf.getCurrentView().areFeaturesDisplayed()); - return alf; - } - - - - /** - * Verify computed distances of sequences with similar secondary structures - */ - @Test(groups = "Functional") - public void testFindDistances_AllSimilar() - { - AlignFrame af = setupAlignmentView("All Similar"); - 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 - */ - - SimilarityParamsI params = new SimilarityParams(false, true, true, true); - params.setSecondaryStructureSource("3D Structures"); - MatrixI distances = sm.findDistances(view, params); - assertEquals(distances.getValue(0, 0), 0d); - assertEquals(distances.getValue(1, 1), 0d); - assertEquals(distances.getValue(0, 1), 0d / 4); - assertEquals(distances.getValue(1, 0), 0d / 4); - } - - /** - * Verify computed distances of sequences with partially similar secondary structures - */ - @Test(groups = "Functional") - public void testFindDistances_PartiallySimilar() - { - AlignFrame af = setupAlignmentView("Partially Similar"); - AlignViewport viewport = af.getViewport(); - AlignmentView view = viewport.getAlignmentView(false); - - ScoreModelI sm = new SecondaryStructureDistanceModel(); - sm = ScoreModels.getInstance().getScoreModel(sm.getName(), - af.alignPanel); - - /* - * score = 0 + 0 + 2 + 2 = 4/4 - */ - SimilarityParamsI params = new SimilarityParams(false, true, true, true); - params.setSecondaryStructureSource("3D Structures"); - MatrixI distances = sm.findDistances(view, params); - assertEquals(distances.getValue(0, 0), 0d); - assertEquals(distances.getValue(1, 1), 0d); - assertEquals(distances.getValue(0, 1), 1d); - assertEquals(distances.getValue(1, 0), 1d); - } - - /** - * Verify computed distances of sequences with dissimilar secondary structures - */ - @Test(groups = "Functional") - public void testFindDistances_notSimilar() - { - AlignFrame af = setupAlignmentView("Not Similar"); - AlignViewport viewport = af.getViewport(); - AlignmentView view = viewport.getAlignmentView(false); - - ScoreModelI sm = new SecondaryStructureDistanceModel(); - sm = ScoreModels.getInstance().getScoreModel(sm.getName(), - af.alignPanel); - - /* - * score = 2 + 2 + 2 + 2 = 8/4 - */ - SimilarityParamsI params = new SimilarityParams(false, true, true, true); - params.setSecondaryStructureSource("3D Structures"); - MatrixI distances = sm.findDistances(view, params); - assertEquals(distances.getValue(0, 0), 0d); - assertEquals(distances.getValue(1, 1), 0d); - assertEquals(distances.getValue(0, 1), 2d); - assertEquals(distances.getValue(1, 0), 2d); - } - - /** - * Verify computed distances of sequences with dissimilar secondary structures - * with coil structure represented as null - */ - @Test(groups = "Functional") - public void testFindDistances_withCoil() - { - AlignFrame af = setupAlignmentView("With Coil"); - AlignViewport viewport = af.getViewport(); - AlignmentView view = viewport.getAlignmentView(false); - - ScoreModelI sm = new SecondaryStructureDistanceModel(); - sm = ScoreModels.getInstance().getScoreModel(sm.getName(), - af.alignPanel); - - /* - * score = 2 + 2 + 2 + 2 = 8/4 - */ - SimilarityParamsI params = new SimilarityParams(false, true, true, true); - params.setSecondaryStructureSource("3D Structures"); - MatrixI distances = sm.findDistances(view, params); - assertEquals(distances.getValue(0, 0), 0d); - assertEquals(distances.getValue(1, 1), 0d); - assertEquals(distances.getValue(0, 1), 2d); - assertEquals(distances.getValue(1, 0), 2d); - } /** * Verify computed distances of sequences with gap @@ -569,5 +398,38 @@ public class SecondaryStructureDistanceModelTest af.getFeatureRenderer().findAllFeatures(true); return af; } + + + @DataProvider(name = "testData") + public Object[][] testData() { + return new Object[][] { + {"All Similar", 0d, 0d, 0d, 0d / 4}, + {"Partially Similar", 0d, 0d, 1d, 1d}, + {"Not Similar", 0d, 0d, 2d, 2d}, + {"With Coil", 0d, 0d, 2d, 2d}, + }; + } + @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); + } + + } diff --git a/test/jalview/bin/CommandsTest2.java b/test/jalview/bin/CommandsTest2.java index aa3c834..a732254 100644 --- a/test/jalview/bin/CommandsTest2.java +++ b/test/jalview/bin/CommandsTest2.java @@ -167,14 +167,14 @@ public class CommandsTest2 + "--structure=[seqid=FER1_SPIOL]examples/AlphaFold/AF-P00221-F1-model_v4.cif " + "--paematrix=examples/AlphaFold/AF-P00221-F1-predicted_aligned_error_v4.json " + "--props=test/jalview/bin/commandsTest2.jvprops1 ", - 15, 7, 1 }, + 15, 8, 1 }, { "--gui --nonews --nosplash --debug " + "--append=examples/uniref50.fa " + "--colour=gecos-flower " + "--structure=[seqid=FER1_SPIOL]examples/AlphaFold/AF-P00221-F1-model_v4.cif " + "--paematrix=examples/AlphaFold/AF-P00221-F1-predicted_aligned_error_v4.json " + "--props=test/jalview/bin/commandsTest2.jvprops2 ", - 15, 4, 1 }, + 15, 5, 1 }, { "--gui --nonews --nosplash --debug " + "--append=examples/uniref50.fa " + "--colour=gecos-flower " @@ -182,7 +182,7 @@ public class CommandsTest2 + "--paematrix=examples/AlphaFold/AF-P00221-F1-predicted_aligned_error_v4.json " + "--noshowssannotations " + "--props=test/jalview/bin/commandsTest2.jvprops1 ", - 15, 4, 1 }, + 15, 5, 1 }, { "--gui --nonews --nosplash --debug " + "--append=examples/uniref50.fa " + "--colour=gecos-flower " @@ -208,7 +208,7 @@ public class CommandsTest2 + "--props=test/jalview/bin/commandsTest2.jvprops1 ", 15, 0, 1 }, { "--gui --nonews --nosplash --debug --nowebservicediscovery --props=test/jalview/bin/commandsTest.jvprops --argfile=test/jalview/bin/commandsTest2.argfile1 ", - 16, 19, 3 }, + 16, 20, 3 }, { "--gui --nonews --nosplash --debug --nowebservicediscovery --props=test/jalview/bin/commandsTest.jvprops --argfile=test/jalview/bin/commandsTest2.argfile2 ", 16, 0, 2 }, { "--gui --nonews --nosplash --debug --nowebservicediscovery --props=test/jalview/bin/commandsTest.jvprops --open=./examples/test_fab41.result/sample.a2m " @@ -217,14 +217,14 @@ public class CommandsTest2 + "--structureviewer=none " + "--structure=./examples/test_fab41.result/test_fab41_unrelaxed_rank_2_model_4.pdb " + "--structure=./examples/test_fab41.result/test_fab41_unrelaxed_rank_3_model_2.pdb", - 16, 10, 0 }, + 16, 11, 0 }, { "--gui --nonews --nosplash --debug --nowebservicediscovery --props=test/jalview/bin/commandsTest.jvprops --open=./examples/test_fab41.result/sample.a2m " + "--allstructures " + "--structure=./examples/test_fab41.result/test_fab41_unrelaxed_rank_1_model_3.pdb " + "--noallstructures " + "--structureviewer=none " + "--structure=./examples/test_fab41.result/test_fab41_unrelaxed_rank_2_model_4.pdb " + "--structure=./examples/test_fab41.result/test_fab41_unrelaxed_rank_3_model_2.pdb", - 16, 10, 2 }, + 16, 11, 2 }, /* */ // diff --git a/test/jalview/gui/AnnotationChooserTest.java b/test/jalview/gui/AnnotationChooserTest.java index f3c0dee..c8208ca 100644 --- a/test/jalview/gui/AnnotationChooserTest.java +++ b/test/jalview/gui/AnnotationChooserTest.java @@ -325,7 +325,7 @@ public class AnnotationChooserTest types = AnnotationChooser.getAnnotationTypes(parentPanel.getAlignment(), false); - assertEquals("Not six annotation types", 7, types.size()); + assertEquals("Not six annotation types", 8, types.size()); assertTrue("IUPRED missing", types.contains("IUPRED")); assertTrue("JMol missing", types.contains("JMol")); assertTrue("Beauty missing", types.contains("Beauty")); @@ -365,12 +365,13 @@ public class AnnotationChooserTest assertTrue(anns[0].visible); // Conservation assertTrue(anns[1].visible); // Quality assertTrue(anns[2].visible); // Consensus - assertTrue(anns[3].visible); // Occupancy - assertTrue(anns[4].visible); // IUPred for seq0 - assertTrue(anns[5].visible); // Beauty - assertFalse(anns[6].visible); // JMol for seq3 - not selected but hidden - assertTrue(anns[7].visible); // IUPRED for seq2 - assertFalse(anns[8].visible); // JMol for seq1 - selected and hidden + assertTrue(anns[3].visible); // SS Consensus + assertTrue(anns[4].visible); // Occupancy + assertTrue(anns[5].visible); // IUPred for seq0 + assertTrue(anns[6].visible); // Beauty + assertFalse(anns[7].visible); // JMol for seq3 - not selected but hidden + assertTrue(anns[8].visible); // IUPRED for seq2 + assertFalse(anns[9].visible); // JMol for seq1 - selected and hidden } /** @@ -404,12 +405,13 @@ public class AnnotationChooserTest assertTrue(anns[0].visible); // Conservation assertTrue(anns[1].visible); // Quality assertTrue(anns[2].visible); // Consensus - assertTrue(anns[3].visible); // Occupancy - assertTrue(anns[4].visible); // IUPred for seq0 - assertTrue(anns[5].visible); // Beauty - assertTrue(anns[6].visible); // JMol for seq3 not in selection group - assertTrue(anns[7].visible); // IUPRED for seq2 - assertFalse(anns[8].visible); // JMol for seq1 in selection group + assertTrue(anns[3].visible); // SS ßConsensus + assertTrue(anns[4].visible); // Occupancy + assertTrue(anns[5].visible); // IUPred for seq0 + assertTrue(anns[6].visible); // Beauty + assertTrue(anns[7].visible); // JMol for seq3 not in selection group + assertTrue(anns[8].visible); // IUPRED for seq2 + assertFalse(anns[9].visible); // JMol for seq1 in selection group } /** @@ -615,12 +617,13 @@ public class AnnotationChooserTest assertTrue(anns[0].visible); // Conservation assertTrue(anns[1].visible); // Quality assertTrue(anns[2].visible); // Consensus - assertTrue(anns[3].visible); // Occupancy - assertTrue(anns[4].visible); // IUPred for seq0 - assertTrue(anns[5].visible); // Beauty - assertFalse(anns[6].visible); // JMol for seq3 - assertTrue(anns[7].visible); // IUPRED for seq2 - assertFalse(anns[8].visible); // JMol for seq1 + assertTrue(anns[3].visible); // Consensus + assertTrue(anns[4].visible); // Occupancy + assertTrue(anns[5].visible); // IUPred for seq0 + assertTrue(anns[6].visible); // Beauty + assertFalse(anns[7].visible); // JMol for seq3 + assertTrue(anns[8].visible); // IUPRED for seq2 + assertFalse(anns[9].visible); // JMol for seq1 } /** @@ -658,12 +661,13 @@ public class AnnotationChooserTest assertTrue(anns[0].visible); // Conservation assertTrue(anns[1].visible); // Quality assertTrue(anns[2].visible); // Consensus - assertTrue(anns[3].visible); // Occupancy - assertTrue(anns[4].visible); // IUPred for seq0 - assertTrue(anns[5].visible); // Beauty - assertTrue(anns[6].visible); // JMol for seq3 not in selection group - assertTrue(anns[7].visible); // IUPRED for seq2 - assertFalse(anns[8].visible); // JMol for seq1 in selection group + assertTrue(anns[3].visible); // Consensus + assertTrue(anns[4].visible); // Occupancy + assertTrue(anns[5].visible); // IUPred for seq0 + assertTrue(anns[6].visible); // Beauty + assertTrue(anns[7].visible); // JMol for seq3 not in selection group + assertTrue(anns[8].visible); // IUPRED for seq2 + assertFalse(anns[9].visible); // JMol for seq1 in selection group } /** @@ -805,12 +809,13 @@ public class AnnotationChooserTest assertTrue(anns[0].visible); // Conservation assertTrue(anns[1].visible); // Quality assertTrue(anns[2].visible); // Consensus - assertTrue(anns[3].visible); // Occupancy - assertFalse(anns[4].visible); // IUPRED - assertTrue(anns[5].visible); // Beauty (not seq-related) - assertFalse(anns[6].visible); // JMol - assertFalse(anns[7].visible); // IUPRED - assertFalse(anns[8].visible); // JMol + assertTrue(anns[3].visible); // SS Consensus + assertTrue(anns[4].visible); // Occupancy + assertFalse(anns[5].visible); // IUPRED + assertTrue(anns[6].visible); // Beauty (not seq-related) + assertFalse(anns[7].visible); // JMol + assertFalse(anns[8].visible); // IUPRED + assertFalse(anns[9].visible); // JMol // reset - should all be visible testee.resetOriginalState(); diff --git a/test/jalview/gui/AnnotationRowFilterTest.java b/test/jalview/gui/AnnotationRowFilterTest.java index 8e5c06b..8960b97 100644 --- a/test/jalview/gui/AnnotationRowFilterTest.java +++ b/test/jalview/gui/AnnotationRowFilterTest.java @@ -121,7 +121,7 @@ public class AnnotationRowFilterTest */ Vector items = testee.getAnnotationItems(false); assertEquals(items.toString(), - "[Conservation, Quality, Consensus, Occupancy, ann1Label, Significance, Significance_1, Jronn_FER_CAPAA, Jronn_FER_BRANA, Jnet_FER_BRANA, Jnet_FER_BRANA_2]"); + "[Conservation, Quality, Consensus, SecondaryStructureConsensus, Occupancy, ann1Label, Significance, Significance_1, Jronn_FER_CAPAA, Jronn_FER_BRANA, Jnet_FER_BRANA, Jnet_FER_BRANA_2]"); assertEquals(testee.getAnnotationMenuLabel(ann1), "ann1Label"); assertEquals(testee.getAnnotationMenuLabel(ann2), "Significance"); assertEquals(testee.getAnnotationMenuLabel(ann2a), "Significance_1"); diff --git a/test/jalview/gui/StructureChooserTest.java b/test/jalview/gui/StructureChooserTest.java index dd5cd4c..91c8bbc 100644 --- a/test/jalview/gui/StructureChooserTest.java +++ b/test/jalview/gui/StructureChooserTest.java @@ -394,27 +394,27 @@ public class StructureChooserTest { "examples/uniref50.fa", "FER1_SPIOL", "examples/AlphaFold/AF-P00221-F1-model_v4.cif", TFType.DEFAULT, "examples/AlphaFold/AF-P00221-F1-predicted_aligned_error_v4.json", - true, false, null, 15, 7, 0, null }, + true, false, null, 15, 8, 0, null }, { "examples/uniref50.fa", "FER1_SPIOL", "examples/AlphaFold/AF-P00221-F1-model_v4.cif", TFType.PLDDT, "examples/AlphaFold/AF-P00221-F1-predicted_aligned_error_v4.json", - true, false, null, 15, 7, 0, null }, + true, false, null, 15, 8, 0, null }, { "examples/uniref50.fa", "FER1_SPIOL", "examples/AlphaFold/AF-P00221-F1-model_v4.cif", TFType.PLDDT, "examples/AlphaFold/AF-P00221-F1-predicted_aligned_error_v4.json", - false, false, null, 15, 4, 0, null }, + false, false, null, 15, 5, 0, null }, { "examples/uniref50.fa", "FER1_SPIOL", "examples/AlphaFold/AF-P00221-F1-model_v4.cif", TFType.DEFAULT, "examples/AlphaFold/AF-P00221-F1-predicted_aligned_error_v4.json", - true, false, ViewerType.JMOL, 15, 7, 1, null }, + true, false, ViewerType.JMOL, 15, 8, 1, null }, { "examples/uniref50.fa", "FER1_SPIOL", "examples/AlphaFold/AF-P00221-F1-model_v4.cif", TFType.PLDDT, "examples/AlphaFold/AF-P00221-F1-predicted_aligned_error_v4.json", - true, false, ViewerType.JMOL, 15, 7, 1, null }, + true, false, ViewerType.JMOL, 15, 8, 1, null }, { "examples/uniref50.fa", "FER1_SPIOL", "examples/AlphaFold/AF-P00221-F1-model_v4.cif", TFType.PLDDT, "examples/AlphaFold/AF-P00221-F1-predicted_aligned_error_v4.json", - false, false, ViewerType.JMOL, 15, 4, 1, null }, }; + false, false, ViewerType.JMOL, 15, 5, 1, null }, }; } } -- 1.7.10.2