JAL-4386 - Implementation of substitution matrix and test cases.
authorRenia Correya <rcorreya001@dundee.ac.uk>
Mon, 13 May 2024 09:23:02 +0000 (10:23 +0100)
committerRenia Correya <rcorreya001@dundee.ac.uk>
Mon, 13 May 2024 09:23:02 +0000 (10:23 +0100)
18 files changed:
resources/lang/Messages.properties
resources/scoreModel/secondarystructure.scm [new file with mode: 0644]
src/jalview/analysis/AAFrequency.java
src/jalview/analysis/AlignmentUtils.java
src/jalview/analysis/scoremodels/ScoreModels.java
src/jalview/analysis/scoremodels/SecondaryStructureDistanceModel.java
src/jalview/appletgui/AlignFrame.java
src/jalview/gui/CalculationChooser.java
src/jalview/jbgui/GAlignFrame.java
src/jalview/renderer/AnnotationRenderer.java
src/jalview/schemes/ResidueProperties.java
src/jalview/util/Constants.java [new file with mode: 0644]
test/jalview/analysis/AlignmentUtilsTests.java
test/jalview/analysis/scoremodels/SecondaryStructureDistanceModelTest.java
test/jalview/bin/CommandsTest2.java
test/jalview/gui/AnnotationChooserTest.java
test/jalview/gui/AnnotationRowFilterTest.java
test/jalview/gui/StructureChooserTest.java

index 195eb1f..349340f 100644 (file)
@@ -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 (file)
index 0000000..f56986f
--- /dev/null
@@ -0,0 +1,14 @@
+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
index 796625a..ea02228 100755 (executable)
@@ -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);
   }
 
   /**
index d88950c..798b4bc 100644 (file)
@@ -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<String, String> 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;
+    
+  }
+  
 }
index dd1bc9d..1c47968 100644 (file)
@@ -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;
+  }
 }
index 1dcf297..5b0f242 100644 (file)
@@ -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.
-   * <p>
-   * 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.
    * <p>
    * 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<SeqCigar> 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<SeqCigar> findSeqsWithoutGapAtColumn(
+  private Set<SeqCigar> findSeqsWithoutGapAtColumn(
           SeqCigar[] seqs, int columnPosition)
   {
     Set<SeqCigar> seqsWithoutGapAtCol = new HashSet<>();
@@ -335,7 +302,7 @@ public class SecondaryStructureDistanceModel extends DistanceScoreModel
    * @param ssAlignmentAnnotationForSequences         
    * @return
    */
-  protected Set<SeqCigar> findSeqsWithUndefinedSS(SeqCigar[] seqs,
+  private Set<SeqCigar> findSeqsWithUndefinedSS(SeqCigar[] seqs,
           Map<String, HashSet<String>> ssAlignmentAnnotationForSequences) {
       Set<SeqCigar> seqsWithUndefinedSS = new HashSet<>();
       for (SeqCigar seq : seqs) {
@@ -361,103 +328,27 @@ public class SecondaryStructureDistanceModel extends DistanceScoreModel
    */
   private boolean isSSUndefinedOrNotAdded(SeqCigar seq, 
           Map<String, HashSet<String>> 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<String> 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
index f502952..55a5364 100644 (file)
@@ -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);
index 7747a6b..d05aa03 100644 (file)
@@ -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);
index da35bd4..dd66811 100755 (executable)
@@ -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);
index 015db5c..a56f06c 100644 (file)
@@ -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
             {
               
index e297ff6..2fcb95f 100755 (executable)
@@ -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<String, Integer> 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 (file)
index 0000000..bced9c8
--- /dev/null
@@ -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 <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
+  } 
+}
index f017662..eee5e87 100644 (file)
@@ -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<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(dataProvider = "SSSourceFromAnnotationDescription")
+//    public void testGetSSSourceFromAnnotationDescription(Map<SequenceI, List<AlignmentAnnotation>> annotations, String expectedSSSource) {
+//        String actualSSSource = AlignmentUtils.getSSSourceFromAnnotationDescription(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"}
+        };
+    }   
+
 }
index 68c740c..f250525 100644 (file)
@@ -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 };
-
-  /**
-   * <pre>
-   * 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
-   * </pre>
-   * 
-   * @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);
+  }
+
+  
 }
index aa3c834..a732254 100644 (file)
@@ -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 },
         /*
          */
         //
index f3c0dee..c8208ca 100644 (file)
@@ -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();
index 8e5c06b..8960b97 100644 (file)
@@ -121,7 +121,7 @@ public class AnnotationRowFilterTest
      */
     Vector<String> 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");
index dd5cd4c..91c8bbc 100644 (file)
@@ -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 }, };
   }
 
 }