Merge branch 'develop' into feature/JAL-4386_calculate_tree_using_secondary_structure...
authorRenia Correya <rcorreya001@dundee.ac.uk>
Tue, 3 Sep 2024 18:16:24 +0000 (23:46 +0530)
committerRenia Correya <rcorreya001@dundee.ac.uk>
Tue, 3 Sep 2024 18:16:24 +0000 (23:46 +0530)
# Conflicts:
# src/jalview/analysis/AAFrequency.java
# src/jalview/analysis/AlignmentUtils.java
# src/jalview/analysis/scoremodels/SecondaryStructureDistanceModel.java
# src/jalview/api/AlignViewportI.java
# src/jalview/datamodel/Profile.java
# src/jalview/datamodel/SequenceGroup.java
# src/jalview/gui/AlignFrame.java
# src/jalview/gui/AlignViewport.java
# src/jalview/gui/PopupMenu.java
# src/jalview/jbgui/GAlignFrame.java
# src/jalview/project/Jalview2XML.java
# src/jalview/renderer/AnnotationRenderer.java
# src/jalview/renderer/ResidueShader.java
# src/jalview/renderer/ResidueShaderI.java
# src/jalview/util/Constants.java
# src/jalview/viewmodel/AlignmentViewport.java
# src/jalview/workers/SecondaryStructureConsensusThread.java
# test/jalview/analysis/AlignmentUtilsTests.java

20 files changed:
1  2 
src/jalview/analysis/AAFrequency.java
src/jalview/analysis/AlignmentUtils.java
src/jalview/analysis/scoremodels/SecondaryStructureDistanceModel.java
src/jalview/api/AlignViewportI.java
src/jalview/datamodel/Profile.java
src/jalview/datamodel/ProfileI.java
src/jalview/datamodel/SequenceGroup.java
src/jalview/gui/AlignFrame.java
src/jalview/gui/AlignViewport.java
src/jalview/gui/CalculationChooser.java
src/jalview/gui/PopupMenu.java
src/jalview/jbgui/GAlignFrame.java
src/jalview/project/Jalview2XML.java
src/jalview/renderer/AnnotationRenderer.java
src/jalview/renderer/ResidueShader.java
src/jalview/util/Constants.java
src/jalview/viewmodel/AlignmentViewport.java
src/jalview/workers/SecondaryStructureConsensusThread.java
test/jalview/analysis/AlignmentUtilsTests.java
test/jalview/renderer/ResidueShaderTest.java

@@@ -192,15 -194,14 +192,14 @@@ public class AAFrequenc
      // jalview.bin.Console.outPrintln(elapsed);
    }
  
-   
    public static final ProfilesI calculateSS(List<SequenceI> list, int start,
 -          int end)
 +          int end, String source)
    {
 -    return calculateSS(list, start, end, false);
 +    return calculateSS(list, start, end, false, source);
    }
-   
    public static final ProfilesI calculateSS(List<SequenceI> sequences,
 -          int start, int end, boolean profile)
 +          int start, int end, boolean profile, String source)
    {
      SequenceI[] seqs = new SequenceI[sequences.size()];
      int width = 0;
        return reply;
      }
    }
-   
    public static final ProfilesI calculateSS(final SequenceI[] sequences,
 -          int width, int start, int end, boolean saveFullProfile)
 +          int width, int start, int end, boolean saveFullProfile, String source)
    {
  
      int seqCount = sequences.length;
 +    
 +    int seqWithSSCount = 0;
-     
      ProfileI[] result = new ProfileI[width];
  
      for (int column = start; column < end; column++)
                    "WARNING: Consensus skipping null sequence - possible race condition.");
            continue;
          }
-         
          char c = sequences[row].getCharAt(column);
 -        AlignmentAnnotation aa = AlignmentUtils
 -                .getDisplayedAlignmentAnnotation(sequences[row]);
 -        if (aa != null)
 -        {
 -          ssCount++;
 -        }
 -
 -        if (sequences[row].getLength() > column && !Comparison.isGap(c)
 -                && aa != null)
 -        {
 -
 -          int seqPosition = sequences[row].findPosition(column);
 -          char ss = AlignmentUtils.findSSAnnotationForGivenSeqposition(aa,
 -                  seqPosition);
 -          if (ss == '*')
 -          {
 -            continue;
 +        List<AlignmentAnnotation> annots = AlignmentUtils.getAlignmentAnnotationForSource(sequences[row], source);
 +        if(annots!=null) {
 +          seqWithSSCount++;
 +          for(AlignmentAnnotation aa:annots) {
 +            if(aa!=null) {
 +              ssCount++;
 +            }
 +            
 +            if (sequences[row].getLength() > column && !Comparison.isGap(c) && aa !=null)
 +            {
 +              
 +              int seqPosition = sequences[row].findPosition(column);
 +              
 +              char ss = AlignmentUtils.findSSAnnotationForGivenSeqposition(
 +                      aa, seqPosition); 
 +              if(ss == '*') {
 +                continue;
 +              }        
 +              ssCounts.add(ss);                    
 +            }
 +            else if(Comparison.isGap(c) && aa!=null) {
 +              ssCounts.addGap();
 +            }
            }
 -          ssCounts.add(ss);
 -        }
 -        else if (Comparison.isGap(c) && aa != null)
 -        {
 -          ssCounts.addGap();
          }
        }
  
        int maxSSCount = ssCounts.getModalCount();
        String maxSS = ssCounts.getSSForCount(maxSSCount);
        int gapCount = ssCounts.getGapCount();
 -      ProfileI profile = new Profile(maxSS, ssCount, gapCount, maxSSCount);
 +      ProfileI profile = new Profile(maxSS, ssCount, gapCount, 
 +              maxSSCount, seqWithSSCount);
  
        if (saveFullProfile)
        {
          profile.setSSCounts(ssCounts);
          * happens if sequences calculated over were 
          * shorter than alignment width
          */
 -        ssConsensus.annotations[i] = null;
 -        return;
 -      }
 -
 -      final int dp = getPercentageDp(nseq);
 +       ssConsensus.annotations[i] = null;
 +       return;
 +     }
 +     
 +     if(ssConsensus.getNoOfSequencesIncluded()<0) {
 +       ssConsensus.setNoOfSequencesIncluded(profile.getSeqWithSSCount());
 +     }
 +     
 +     final int dp = getPercentageDp(nseq);
  
-      float value = profile.getSSPercentageIdentity(ignoreGaps);
+       float value = profile.getSSPercentageIdentity(ignoreGaps);
  
-      String description = getSSTooltip(profile, value, showSequenceLogo,
-              ignoreGaps, dp);
+       String description = getSSTooltip(profile, value, showSequenceLogo,
+               ignoreGaps, dp);
  
 -      String modalSS = profile.getModalSS();
 -      if ("".equals(modalSS))
 -      {
 -        modalSS = "-";
 -      }
 -      else if (modalSS.length() > 1)
 -      {
 -        modalSS = "+";
 -      }
 -      ssConsensus.annotations[i] = new Annotation(modalSS, description, ' ',
 -              value);
 -    }
 -    // long elapsed = System.currentTimeMillis() - now;
 -    // jalview.bin.Console.outPrintln(-elapsed);
 -  }
 +     String modalSS = profile.getModalSS();
 +     if ("".equals(modalSS))
 +     {
 +       modalSS = "-";
 +     }
 +     else if (modalSS.length() > 1)
 +     {
 +       modalSS = "+";
 +     }
 +     ssConsensus.annotations[i] = new Annotation(modalSS, description,
 +             ' ', value);
 +   }
 +   
 +   //Hide consensus with no data to display
 +   if(ssConsensus.getNoOfSequencesIncluded()<1)
 +     ssConsensus.visible = false;
 +
 +   // long elapsed = System.currentTimeMillis() - now;
 +   // jalview.bin.Console.outPrintln(-elapsed);
 + }
  
    /**
     * Derive the gap count annotation row.
@@@ -2937,11 -2915,11 +2939,11 @@@ public class AlignmentUtil
        return Color.red;
      }
  
 -    return Color.gray;
 +    return Color.white;
    }
  
-   public static char findSSAnnotationForGivenSeqposition(AlignmentAnnotation aa,
-           int seqPosition)
+   public static char findSSAnnotationForGivenSeqposition(
+           AlignmentAnnotation aa, int seqPosition)
    {
      char ss = '*';
  
  
    }
  
 +  public static Map<SequenceI, ArrayList<AlignmentAnnotation>> getSequenceAssociatedAlignmentAnnotations(
 +          AlignmentAnnotation[] alignAnnotList, String selectedSSSource)
 +  {
 +
 +    Map<SequenceI, ArrayList<AlignmentAnnotation>> ssAlignmentAnnotationForSequences 
 +             = new HashMap<SequenceI, ArrayList<AlignmentAnnotation>>();
 +    if (alignAnnotList == null || alignAnnotList.length == 0)
 +    {
 +      return ssAlignmentAnnotationForSequences;
 +    }
 +
 +    for (AlignmentAnnotation aa : alignAnnotList)
 +    {
 +      if (aa.sequenceRef == null)
 +      {
 +        continue;
 +      }
 +      
 +      for (String label : Constants.SECONDARY_STRUCTURE_LABELS.keySet())
 +      {
 +
 +        if (label.equals(aa.label))
 +        {
 +
 +          if (Constants.SS_ALL_PROVIDERS.equals(selectedSSSource))
 +          {
 +            ssAlignmentAnnotationForSequences
 +                    .computeIfAbsent(aa.sequenceRef.getDatasetSequence(),
 +                            k -> new ArrayList<>())
 +                    .add(aa);
 +            break;
 +          }
 +
 +          String ssSource = AlignmentUtils
 +                  .extractSSSourceFromAnnotationDescription(aa);
 +          if (ssSource != null && ssSource.equals(selectedSSSource))
 +          {
 +
 +            ssAlignmentAnnotationForSequences
 +                    .computeIfAbsent(aa.sequenceRef.getDatasetSequence(),
 +                            k -> new ArrayList<>())
 +                    .add(aa);
 +            break;
 +          }
 +        }
 +      }
 +    }
 +
 +    return ssAlignmentAnnotationForSequences;
 +
 +  }
-   
++
++
+   // to do set priority for labels
+   public static AlignmentAnnotation getDisplayedAlignmentAnnotation(
+           SequenceI seq)
+   {
+     for (String ssLabel : Constants.SECONDARY_STRUCTURE_LABELS.keySet())
+     {
+       AlignmentAnnotation[] aa = seq.getAnnotation(ssLabel);
+       if (aa != null)
+       {
+         for (AlignmentAnnotation annot : aa)
+         {
+           if (annot.visible)
+           {
+             return annot;
+           }
+         }
+       }
+     }
+     return null;
+   }
  }
@@@ -106,26 -109,30 +109,26 @@@ public class SecondaryStructureDistance
    @Override
    public MatrixI findDistances(AlignmentView seqData,
            SimilarityParamsI params)
-   {   
-     
+   {
      SeqCigar[] seqs = seqData.getSequences();
 -    int noseqs = seqs.length; // no of sequences
 -    int cpwidth = 0; // = seqData.getWidth();
 -    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 = 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;
 +    int noseqs = seqs.length; //no of sequences
 +    int cpwidth = 0; 
 +    double[][] similarities = new double[noseqs][noseqs]; //matrix to store similarity score
 +    //secondary structure source parameter selected by the user from the drop down.
 +    String ssSource = params.getSecondaryStructureSource(); 
 +    if(ssSource == null || ssSource == "") {
 +      ssSource = Constants.SS_ALL_PROVIDERS;
      }
 -
 +    ssRateMatrix = ScoreModels.getInstance().getSecondaryStructureMatrix();
 +        
      // need to get real position for view position
      int[] viscont = seqData.getVisibleContigs();
 +    
 +    
 +    AlignmentAnnotation[] alignAnnotList = fr.getViewport().getAlignment()
 +            .getAlignmentAnnotation();   
 +    
  
      /*
       * Add secondary structure annotations that are added to the annotation track
           */
          for (int i = 0; i < (noseqs - 1); i++)
          {
-           //Iterates for each sequences
+           // Iterates for each sequences
            for (int j = i + 1; j < noseqs; j++)
            {
 -            SeqCigar sc1 = seqs[i];
 -            SeqCigar sc2 = seqs[j];
 -
 -            // check if ss is defined
 -            boolean undefinedSS1 = seqsWithUndefinedSS.contains(sc1);
 -            boolean undefinedSS2 = seqsWithUndefinedSS.contains(sc2);
 +                         
 +            //check if ss is defined
 +            boolean undefinedSS1 = ssAlignmentAnnotationForSequences.get(seqs[i].getRefSeq()) == null;
 +            boolean undefinedSS2 = ssAlignmentAnnotationForSequences.get(seqs[j].getRefSeq()) == null;
  
              // Set similarity to max score if both SS are not defined
-             if (undefinedSS1 && undefinedSS2) {
-                 similarities[i][j] += ssRateMatrix.getMaximumScore();
-                 continue;
-             } 
-             
-             // Set similarity to minimum score if either one SS is not defined
-             else if(undefinedSS1 || undefinedSS2) {
-                 similarities[i][j] += ssRateMatrix.getMinimumScore();
-                 continue;
+             if (undefinedSS1 && undefinedSS2)
+             {
+               similarities[i][j] += ssRateMatrix.getMaximumScore();
+               continue;
              }
 -
 -            // Set similarity to minimum score if either one SS is not defined
 -            else if (undefinedSS1 || undefinedSS2)
 -            {
 -              similarities[i][j] += ssRateMatrix.getMinimumScore();
 -              continue;
 -            }
 -
 -            // check if the sequence contains gap in the current column
 -            boolean gap1 = !seqsWithoutGapAtCol.contains(sc1);
 -            boolean gap2 = !seqsWithoutGapAtCol.contains(sc2);
 -
 -            // Variable to store secondary structure at the current column
 +            
 +            //check if the sequence contains gap in the current column
 +            boolean gap1 = !seqsWithoutGapAtCol.contains(seqs[i]);
 +            boolean gap2 = !seqsWithoutGapAtCol.contains(seqs[j]);            
 +            
 +            //Variable to store secondary structure at the current column
              char ss1 = '*';
              char ss2 = '*';
-             
-             //secondary structure is fetched only if the current column is not 
-             //gap for the sequence
-             if(!gap1 && !undefinedSS1) {  
-               //fetch the position in sequence for the column and finds the
-               //corresponding secondary structure annotation
-               //TO DO - consider based on priority and displayed
+             // secondary structure is fetched only if the current column is not
+             // gap for the sequence
+             if (!gap1 && !undefinedSS1)
+             {
+               // fetch the position in sequence for the column and finds the
+               // corresponding secondary structure annotation
+               // TO DO - consider based on priority and displayed
                int seqPosition = seqs[i].findPosition(cpos);
 -              AlignmentAnnotation[] aa = seqs[i].getRefSeq()
 -                      .getAnnotation(selectedSSSource);
 -              if (aa != null)
 -                ss1 = AlignmentUtils.findSSAnnotationForGivenSeqposition(
 -                        aa[0], seqPosition);
 +              AlignmentAnnotation aa = ssAlignmentAnnotationForSequences.get(seqs[i].getRefSeq()).get(0);
 +              if(aa!=null)
 +              ss1 = 
 +                  AlignmentUtils.findSSAnnotationForGivenSeqposition(aa, seqPosition);              
              }
-             
-             if(!gap2 && !undefinedSS2) {              
+             if (!gap2 && !undefinedSS2)
+             {
                int seqPosition = seqs[j].findPosition(cpos);
 -              AlignmentAnnotation[] aa = seqs[j].getRefSeq()
 -                      .getAnnotation(selectedSSSource);
 -              if (aa != null)
 -                ss2 = AlignmentUtils.findSSAnnotationForGivenSeqposition(
 -                        aa[0], seqPosition);
 -            }
 +              AlignmentAnnotation aa = ssAlignmentAnnotationForSequences.get(seqs[j].getRefSeq()).get(0);
 +              if(aa!=null)
 +                ss2 = 
 +                  AlignmentUtils.findSSAnnotationForGivenSeqposition(aa, seqPosition);               
 +            }           
  
              if ((!gap1 && !gap2) || params.includeGaps())
              {
      return seqsWithoutGapAtCol;
    }
  
-     
 -  /**
 -   * Builds and returns a set containing sequences (SeqCigar) which are not
 -   * considered for the similarity calculation. Following sequences are added:
 -   * 1. Sequences without a defined secondary structure from the selected
 -   * source. 2. Sequences whose secondary structure annotations are not added to
 -   * the annotation track
 -   * 
 -   * @param seqs
 -   * @param ssAlignmentAnnotationForSequences
 -   * @return
 -   */
 -  private Set<SeqCigar> findSeqsWithUndefinedSS(SeqCigar[] seqs,
 -          Map<String, HashSet<String>> ssAlignmentAnnotationForSequences)
 -  {
 -    Set<SeqCigar> seqsWithUndefinedSS = new HashSet<>();
 -    for (SeqCigar seq : seqs)
 -    {
 -      if (isSSUndefinedOrNotAdded(seq, ssAlignmentAnnotationForSequences))
 -      {
 -        seqsWithUndefinedSS.add(seq);
 -      }
 -    }
 -    return seqsWithUndefinedSS;
 -  }
 -
 -  /**
 -   * Returns true if a sequence (SeqCigar) should not be considered for the
 -   * similarity calculation. Following conditions are checked: 1. Sequence
 -   * without a defined secondary structure from the selected source. 2.
 -   * Sequences whose secondary structure annotations are not added to the
 -   * annotation track
 -   * 
 -   * @param seq
 -   * @param ssAlignmentAnnotationForSequences
 -   * @return
 -   */
 -  private boolean isSSUndefinedOrNotAdded(SeqCigar seq,
 -          Map<String, HashSet<String>> ssAlignmentAnnotationForSequences)
 -  {
 -    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;
 -  }
 -
    @Override
    public String getName()
    {
@@@ -129,10 -133,9 +129,9 @@@ public interface AlignViewportI extend
     * @return
     */
    AlignmentAnnotation getAlignmentConsensusAnnotation();
 -
 -  AlignmentAnnotation getAlignmentSecondaryStructureConsensusAnnotation();
 +  
 +  List<AlignmentAnnotation> getAlignmentSecondaryStructureConsensusAnnotation();
  
    /**
     * get the container for alignment gap annotation
     * 
     * @param hconsensus
     */
    void setSequenceConsensusHash(ProfilesI hconsensus);
 -
 -  void setSequenceSSConsensusHash(ProfilesI hSSConsensus);
 +  
 +  void setSequenceSSConsensusHash(Map<String, ProfilesI> hSSConsesnusProfileMap);
-   
  
    /**
     * Set the cDNA complement consensus for the viewport
@@@ -32,10 -32,8 +32,10 @@@ public class Profile implements Profile
     * an object holding counts of symbols in the profile
     */
    private ResidueCount counts;
-   
    private SecondaryStructureCount ssCounts;
 +  
 +  private int seqWithSSCount = -1;
  
    /*
     * the number of sequences (gapped or not) in the profile
Simple merge
@@@ -136,8 -132,9 +136,7 @@@ public class SequenceGroup implements A
     * consensus calculation property
     */
    private boolean showSequenceLogo = false;
-   
  
 -  private boolean showSequenceSSLogo = false;
 -
    /**
     * flag indicating if logo should be rendered normalised
     */
    private boolean hidecols = false;
  
    AlignmentAnnotation consensus = null;
-   
  
 -  AlignmentAnnotation ssConsensus = null;
 +  List<AlignmentAnnotation> ssConsensus = null;
 +  
 +  List<String> secondaryStructureSources = null;
  
    AlignmentAnnotation conservation = null;
  
    private boolean showConsensusHistogram;
-   
 -  private boolean showSSConsensusHistogram;
 -
    private AnnotatedCollectionI context;
 +  
 +  public Map<String, ProfilesI> hSSConsensusProfileMap;
  
    /**
     * Creates a new SequenceGroup object.
          cs.setConsensus(cnsns);
          upd = true;
        }
 +      
 +      hSSConsensusProfileMap = new HashMap<String, ProfilesI>();
 +      List <String> ssSources = new ArrayList<String>();
 +      AnnotatedCollectionI aa = this.getContext();
 +      
 +      if(aa !=null )
 +      {
 +        ssSources = AlignmentUtils.extractSSSourceInAlignmentAnnotation(aa.getAlignmentAnnotation());
 +      }
 +      if(ssSources != null) {
 +        ssSources.add(Constants.SS_ALL_PROVIDERS);
  
 -      ProfilesI ssCnsns = AAFrequency.calculateSS(sequences, startRes,
 -              endRes + 1, showSequenceLogo);
 +        for(String ssSource : ssSources) {
 +          ProfilesI hSSConsensus = AAFrequency.calculateSS(sequences, startRes,  endRes + 1, showSequenceLogo,
 +                  ssSource);
 +          hSSConsensusProfileMap.put(ssSource, hSSConsensus);
 +        }
 +      }
 +            
        if (ssConsensus != null)
        {
 -        _updateSSConsensusRow(ssCnsns, sequences.size());
 +        _updateSSConsensusRow(hSSConsensusProfileMap, sequences.size());
          upd = true;
        }
 +      
        if (cs != null)
        {
 -        cs.setSsConsensus(ssCnsns);
 +        cs.setSSConsensusProfileMap(hSSConsensusProfileMap);
          upd = true;
        }
-       
  
        if ((conservation != null)
                || (cs != null && cs.conservationApplied()))
      }
      this.showSequenceLogo = showSequenceLogo;
    }
-   
 -  public void setshowSequenceSSLogo(boolean showSequenceSSLogo)
 -  {
 -    // TODO: decouple calculation from settings update
 -    if (this.showSequenceSSLogo != showSequenceSSLogo
 -            && ssConsensus != null)
 -    {
 -      this.showSequenceSSLogo = showSequenceSSLogo;
 -      recalcConservation();
 -    }
 -    this.showSequenceSSLogo = showSequenceSSLogo;
 -  }
 -
    /**
     * 
     * @param showConsHist
      this.showConsensusHistogram = showConsHist;
    }
  
 -  public void setShowSSConsensusHistogram(boolean showSSConsHist)
 -  {
 -
 -    if (showSSConsensusHistogram != showSSConsHist && consensus != null)
 -    {
 -      this.showSSConsensusHistogram = showSSConsHist;
 -      recalcConservation();
 -    }
 -    this.showSSConsensusHistogram = showSSConsHist;
 -  }
    /**
     * @return the showConsensusHistogram
     */
@@@ -5911,11 -5830,19 +5911,10 @@@ public class AlignFrame extends GAlignF
  
    }
  
 -  protected String getSelectedRadioButtonDisplayString(
 -          ButtonGroup ssButtonGroup)
 +  protected void showSSConsensus_actionPerformed(ActionEvent e)
    {
 -    Enumeration<AbstractButton> buttons = ssButtonGroup.getElements();
 -    while (buttons.hasMoreElements())
 -    {
 -      AbstractButton button = buttons.nextElement();
 -      if (button.isSelected())
 -      {
 -        return button.getText();
 -      }
 -    }
 -    return null; // No radio button is selected
 +    viewport.setShowSSConsensus(showSSConsensus.getState());
 +    alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
    }
  
    /*
      alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
    }
  
 -  @Override
 -  protected void showSSConsensusHistogram_actionPerformed(ActionEvent e)
 -  {
 -    viewport.setShowSSConsensusHistogram(
 -            showSSConsensusHistogram.getState());
 -    alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
 -  }
    /*
     * (non-Javadoc)
     * 
Simple merge
@@@ -1971,34 -1764,30 +1971,34 @@@ public class PopupMenu extends JPopupMe
    {
      final AlignmentI alignment = this.ap.getAlignment();
      AlignmentUtils.addReferenceAnnotations(candidates, alignment, null);
 -
 -    if (AlignmentUtils.isSSAnnotationPresent(candidates))
 -    {
 +        
 +    if(AlignmentUtils.isSSAnnotationPresent(candidates)) {
 +      
 +      restartSSConsensusWorker();
 +      ap.validateAnnotationDimensions(true);
 +      ap.fontChanged();
 +      ap.av.alignmentChanged(ap);
 +      ap.adjustAnnotationHeight();
        restartSSConsensusWorker();
 +      //ap.alignFrame.getViewport().getCalcManager().restartWorkers();
      }
-         
 -
 -    refresh();
    }
-   
-   
-   private void restartSSConsensusWorker() {
-     
-     List<AlignCalcWorkerI> workers = ap.alignFrame.getViewport().getCalcManager()
-             .getRegisteredWorkersOfClass(SecondaryStructureConsensusThread.class);
-     if (!workers.isEmpty()) {
-         
-       ap.alignFrame.getViewport().getCalcManager().startWorker(workers.remove(0));
+   private void restartSSConsensusWorker()
+   {
+     List<AlignCalcWorkerI> workers = ap.alignFrame.getViewport()
+             .getCalcManager().getRegisteredWorkersOfClass(
+                     SecondaryStructureConsensusThread.class);
+     if (!workers.isEmpty())
+     {
+       ap.alignFrame.getViewport().getCalcManager()
+               .startWorker(workers.remove(0));
  
      }
-         
    }
-   
-   
  
    protected void makeReferenceSeq_actionPerformed(ActionEvent actionEvent)
    {
@@@ -210,8 -207,10 +210,8 @@@ public class GAlignFrame extends JInter
  
    protected JCheckBoxMenuItem showGroupConservation = new JCheckBoxMenuItem();
  
-   protected JCheckBoxMenuItem showConsensusHistogram = new JCheckBoxMenuItem();  
+   protected JCheckBoxMenuItem showConsensusHistogram = new JCheckBoxMenuItem();
  
 -  protected JCheckBoxMenuItem showSSConsensusHistogram = new JCheckBoxMenuItem();
 -
    protected JCheckBoxMenuItem showSequenceLogo = new JCheckBoxMenuItem();
  
    protected JCheckBoxMenuItem normaliseSequenceLogo = new JCheckBoxMenuItem();
          showConsensusHistogram_actionPerformed(e);
        }
  
 -    });
 -    showSSConsensusHistogram.setText(
 -            MessageManager.getString("label.show_ssconsensus_histogram"));
 -    showSSConsensusHistogram.addActionListener(new ActionListener()
 -    {
 +    });    
 -      @Override
 -      public void actionPerformed(ActionEvent e)
 -      {
 -        showConsensusHistogram_actionPerformed(e);
 -      }
 -
 -    });
      showSequenceLogo
              .setText(MessageManager.getString("label.show_consensus_logo"));
      showSequenceLogo.addActionListener(new ActionListener()
              MessageManager.getString("label.autocalculated_annotation"));
  
      JMenu showSS = new JMenu(
 -            MessageManager.getString("label.show_secondary_structure"));
 -
 -    showSS.addMouseListener(new MouseAdapter()
 -    {
 -
 +            MessageManager.getString("label.show_secondary_structure")); 
 +    
 +    JRadioButtonMenuItem radioButtonAllSS = new JRadioButtonMenuItem(MessageManager.getString("option.ss_providers_all"));
 +    radioButtonAllSS.addActionListener(new ActionListener() {
 +      @Override
 +      public void actionPerformed(ActionEvent e) {
 +          showOrHideSecondaryStructureForSource(MessageManager.getString("option.ss_providers_all"), true);
 +          // Select all checkboxes if "All" is selected
 +          Component[] components = showSS.getMenuComponents();
 +          for (Component component : components) {
 +              if (component instanceof JCheckBoxMenuItem) {
 +                  ((JCheckBoxMenuItem) component).setSelected(true);
 +              }
 +          }
 +      }
 +    });
 +    ssButtonGroup.add(radioButtonAllSS);
 +    showSS.add(radioButtonAllSS);
 +    
 +    JRadioButtonMenuItem radioButtonNoneSS = new JRadioButtonMenuItem(MessageManager.getString("option.ss_providers_none"));
 +    radioButtonNoneSS.addActionListener(new ActionListener() {
 +      @Override
 +      public void actionPerformed(ActionEvent e) {
 +          showOrHideSecondaryStructureForSource(MessageManager.getString("option.ss_providers_none"), false);
 +          // Remove selection of all checkboxes if "None" is selected
 +          Component[] components = showSS.getMenuComponents();
 +          for (Component component : components) {
 +              if (component instanceof JCheckBoxMenuItem) {
 +                  ((JCheckBoxMenuItem) component).setSelected(false);
 +              }
 +          }
 +      }
 +    });
 +    ssButtonGroup.add(radioButtonNoneSS);
 +    showSS.add(radioButtonNoneSS);
 +    showSS.addSeparator();
 +    
 +    annotationsMenu.addMouseListener(new MouseAdapter() {
 +      
        @Override
 -      public void mouseEntered(MouseEvent e)
 -      {
 -
 -        updateShowSSRadioButtons(showSS, ssButtonGroup); // Update radio buttons
 -                                                         // every time the menu
 -                                                         // is clicked
 +      public void mouseEntered(MouseEvent e) {
  
 +        updateShowSecondaryStructureMenu(showSS, ssButtonGroup); // Update radio buttons every time the menu is clicked
 +         
        }
      });
-     
      JMenu exportImageMenu = new JMenu(
              MessageManager.getString("label.export_image"));
      JMenu fileMenu = new JMenu(MessageManager.getString("action.file"));
      return null;
    }
  
 -  protected void updateShowSSRadioButtons(JMenu showSS,
 -          ButtonGroup ssButtonGroup)
 +  protected void showOrHideSecondaryStructureForSource(String ssSourceSelection, boolean visible)
    {
      // TODO Auto-generated method stub
 +    
    }
  
 -  protected void showSS_actionPerformed(String ssSourceSelection)
 +  protected void updateShowSecondaryStructureMenu(JMenu showSS,
 +          ButtonGroup ssButtonGroup)
    {
      // TODO Auto-generated method stub
-     
    }
  }
@@@ -5454,7 -5419,7 +5456,8 @@@ public class Jalview2XM
      viewport.getResidueShading()
              .setConsensus(viewport.getSequenceConsensusHash());
      viewport.getResidueShading()
 -            .setSsConsensus(viewport.getSequenceSSConsensusHash());
 +    .setSSConsensusProfileMap(viewport.getSequenceSSConsensusHash());
++
      if (safeBoolean(view.isConservationSelected()) && cs != null)
      {
        viewport.getResidueShading()
@@@ -63,12 -61,21 +63,11 @@@ public class ResidueShader implements R
     * the consensus data for each column
     */
    private ProfilesI consensus;
-   
    /*
 -   * the consensus data for each column
 -   */
 -  private ProfilesI ssConsensus;
 -
 -  public ProfilesI getSsConsensus()
 -  {
 -    return ssConsensus;
 -  }
 -
 -  public void setSsConsensus(ProfilesI ssConsensus)
 -  {
 -    this.ssConsensus = ssConsensus;
 -  }
 +   * the ss consensus data for each column for each source
-    */
-   
++   */  
 +  private Map<String, ProfilesI> ssConsensusProfileMap;
  
    /*
     * if true, apply shading of colour by conservation
  
      return colour;
    }
-   
    @Override
 -  public Color findSSColour(char symbol, int position, SequenceI seq)
 +  public Color findSSColour(char symbol, int position)
    {
      if (colourScheme == null)
      {
@@@ -28,31 -28,25 +28,33 @@@ import java.util.Map
   */
  public class Constants
  {
-   
-   //character used to represent secondary structures
+   // 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
+   // 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";  
-   
+   // 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
 -  }
 +  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
 +  } 
 +  
 +  public static final String SS_PROVIDER_PROPERTY = "SS_PROVIDER";  
 +
 +  //generic secondary structure provider options 
 +  public static final String SS_ALL_PROVIDERS = "All";  
 +  public static final String SS_NONE_PROVIDER = "None";
 +  
 +  //Secondary structure consensus label
 +  public static final String SECONDARY_STRUCTURE_CONSENSUS_LABEL = "Secondary Structure Consensus";
  }
@@@ -766,10 -722,8 +766,9 @@@ public abstract class AlignmentViewpor
     * results of alignment consensus analysis for visible portion of view
     */
    protected ProfilesI hconsensus = null;
 -
 -  protected ProfilesI hSSConsensus = null;
 +  
 +  protected Map<String, ProfilesI> hSSConsensusProfileMap = null;
 +  
-   
  
    /**
     * results of cDNA complement consensus visible portion of view
    {
      this.hconsensus = hconsensus;
    }
-   
    @Override
 -  public void setSequenceSSConsensusHash(ProfilesI hSSConsensus)
 +  public void setSequenceSSConsensusHash(Map<String, ProfilesI> hSSConsensusProfileMap)
    {
 -    this.hSSConsensus = hSSConsensus;
 +    this.hSSConsensusProfileMap = hSSConsensusProfileMap;
    }
-     
    @Override
    public void setComplementConsensusHash(
            Hashtable<String, Object>[] hconsensus)
      return consensus;
    }
  
-   
    @Override
 -  public AlignmentAnnotation getAlignmentSecondaryStructureConsensusAnnotation()
 +  public List<AlignmentAnnotation> getAlignmentSecondaryStructureConsensusAnnotation()
    {
      return secondaryStructureConsensus;
    }
        }
      }
    }
-   
-   
-   
  
    /**
 -   * trigger update of consensus annotation
 +   * trigger update of Secondary Structure consensus annotation
     */
    public void updateSecondaryStructureConsensus(final AlignmentViewPanel ap)
    {
      {
        return;
      }
 -    if (calculator.getRegisteredWorkersOfClass(
 -            SecondaryStructureConsensusThread.class) == null)
 +    List<String> ssSources = viewStyle.getSecondaryStructureSources();
 +    if (secondaryStructureConsensus.size() != ssSources.size()) {
 +      
 +      for(String source : ssSources) {      
 +        boolean ssConsensusForSourcePresent = false;
 +        for(AlignmentAnnotation aa : secondaryStructureConsensus) {
 +          if(aa.description.startsWith(source)) {
 +            ssConsensusForSourcePresent = true;
 +            break;
 +          }
 +        }
 +        
 +        if(!ssConsensusForSourcePresent) {
 +          AlignmentAnnotation ssConsensus = new AlignmentAnnotation(MessageManager.getString("label.ssconsensus_label") + " "+source,
 +                  source + " " + MessageManager.getString("label.ssconsensus_descr"),
 +                  new Annotation[1], 0f, 100f, AlignmentAnnotation.BAR_GRAPH);
 +
 +          ssConsensus.hasText = true;
 +          ssConsensus.autoCalculated = true;
 +          secondaryStructureConsensus.add(ssConsensus);
 +          if (showSSConsensus)
 +          {
 +            ssConsensus.visible = true;
 +            alignment.addAnnotation(ssConsensus);
 +            
 +          }
 +        }
 +      }
 +    }
 +    if (calculator
 +            .getRegisteredWorkersOfClass(SecondaryStructureConsensusThread.class) == null)
      {
-       calculator.registerWorker(new SecondaryStructureConsensusThread(this, ap));
+       calculator.registerWorker(
+               new SecondaryStructureConsensusThread(this, ap));
      }
 +    ap.adjustAnnotationHeight();
 +
 +    
    }
  
    // --------START Structure Conservation
     * should consensus profile be rendered by default
     */
    protected boolean showSequenceLogo = false;
-   
 -  protected boolean showSequenceSSLogo = false;
 -
    /**
     * should consensus profile be rendered normalised to row height
     */
     * should consensus histograms be rendered by default
     */
    protected boolean showConsensusHistogram = true;
-   
 -  protected boolean showSSConsensusHistogram = true;
 -
 -  public void setShowSSConsensusHistogram(boolean showSSConsensusHistogram)
 -  {
 -    this.showSSConsensusHistogram = showSSConsensusHistogram;
 -  }
 -
    /**
     * @return the showConsensusProfile
     */
    {
      return showSequenceLogo;
    }
-   
 -  @Override
 -  public boolean isShowSequenceSSLogo()
 -  {
 -    return showSequenceSSLogo;
 -  }
 -
    /**
     * @param showSequenceLogo
     *          the new value
        calculator.updateAnnotationFor(ConsensusThread.class);
        calculator.updateAnnotationFor(ComplementConsensusThread.class);
        calculator.updateAnnotationFor(StrucConsensusThread.class);
 -    }
 -    this.showSequenceLogo = showSequenceLogo;
 -  }
 +      
 +      //to do
  
 -  public void setShowSequenceSSLogo(boolean showSequenceSSLogo)
 -  {
 -    if (showSequenceSSLogo != this.showSequenceSSLogo)
 -    {
 -      // TODO: decouple settings setting from calculation when refactoring
 -      // annotation update method from alignframe to viewport
 -      this.showSequenceSSLogo = showSequenceSSLogo;
 -      calculator
 -              .updateAnnotationFor(SecondaryStructureConsensusThread.class);
 +      calculator.updateAnnotationFor(SecondaryStructureConsensusThread.class);
      }
 -    this.showSequenceSSLogo = showSequenceSSLogo;
 +    this.showSequenceLogo = showSequenceLogo;
    }
-   
    /**
     * @param showConsensusHistogram
     *          the showConsensusHistogram to set
  
    protected boolean showQuality = true;
  
-   protected boolean showConsensus = true;  
+   protected boolean showConsensus = true;
  
 -  protected boolean showSSConsensus = false;
 +  protected boolean showSSConsensus = true;
  
    protected boolean showOccupancy = true;
  
        consensus = new AlignmentAnnotation("Consensus",
                MessageManager.getString("label.consensus_descr"),
                new Annotation[1], 0f, 100f, AlignmentAnnotation.BAR_GRAPH);
 -
 -      secondaryStructureConsensus = new AlignmentAnnotation(
 -              MessageManager.getString("label.ssconsensus_label"),
 -              MessageManager.getString("label.ssconsensus_descr"),
 -              new Annotation[1], 0f, 100f, AlignmentAnnotation.BAR_GRAPH);
 +      setSecondaryStructureSources(alignment.getAlignmentAnnotation());
 +      List<String> secondaryStructureSources = getSecondaryStructureSources();
 +
 +      if(secondaryStructureSources!=null) {
 +
 +        secondaryStructureConsensus = new ArrayList<AlignmentAnnotation>();
 +        for (String ssSource : secondaryStructureSources) {
 +        
 +          AlignmentAnnotation ssConsensus = new AlignmentAnnotation(MessageManager.getString("label.ssconsensus_label") + " "+ssSource,
 +                  ssSource + " " + MessageManager.getString("label.ssconsensus_descr"),
 +                  new Annotation[1], 0f, 100f, AlignmentAnnotation.BAR_GRAPH);
 +          secondaryStructureConsensus.add(ssConsensus);
 +        }
 +        
 +      }
-       
        initConsensus(consensus);
        initSSConsensus(secondaryStructureConsensus);
        initGapCounts();
@@@ -184,33 -167,11 +184,34 @@@ public class SecondaryStructureConsensu
     * 
     * @return
     */
 -  protected AlignmentAnnotation getSSConsensusAnnotation()
 +  protected List<AlignmentAnnotation> getSSConsensusAnnotation()
    {
-     return alignViewport.getAlignmentSecondaryStructureConsensusAnnotation();
+     return alignViewport
+             .getAlignmentSecondaryStructureConsensusAnnotation();
    }
 +  
 +  /**
 +   * Get the Consensus annotation for the alignment
 +   * 
 +   * @return
 +   */
 +  protected void setSecondaryStructureSources()
 +  {
 +    List<String> sources = null;
 +    AlignmentAnnotation[] aa = alignViewport.getAlignment().getAlignmentAnnotation();
 +    if(aa!=null) {
 +      sources = AlignmentUtils.extractSSSourceInAlignmentAnnotation(aa);
 +      if(sources != null) {
 +        sources.add(0, Constants.SS_ALL_PROVIDERS);
 +        alignViewport.setSecondaryStructureSources(sources);
 +      }
 +    }
 +  }
 +  
 +  protected List<String> getSecondaryStructureSources()
 +  {
 +    return alignViewport.getSecondaryStructureSources();
 +  }
  
    /**
     * Get the Gap annotation for the alignment
@@@ -2775,139 -2779,181 +2778,160 @@@ public class AlignmentUtilsTest
                      && 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));
-     }
  
-     @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);
-     }
 -  @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 = "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 = "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[] {});
  
-     @DataProvider(name = "SSAnnotationPresence")
-     public static Object[][] provideSSAnnotationPresence() {
-         Map<SequenceI, List<AlignmentAnnotation>> annotations1 = new HashMap<>();
-         SequenceI seq1 = new Sequence("Seq1", "ASD---ASD---ASD", 37, 45);
-         List<AlignmentAnnotation> annotationsList1 = new ArrayList<>();
-         annotationsList1.add(new AlignmentAnnotation("Secondary Structure", "Secondary Structure", new Annotation[]{}));
-         annotations1.put(seq1, annotationsList1); // Annotation present secondary structure for seq1
-         Map<SequenceI, List<AlignmentAnnotation>> annotations2 = new HashMap<>();
-         SequenceI seq2 = new Sequence("Seq2", "ASD---ASD------", 37, 42);
-         List<AlignmentAnnotation> annotationsList2 = new ArrayList<>();
-         annotationsList2.add(new AlignmentAnnotation("Other Annotation", "Other Annotation", new Annotation[]{}));
-         annotations2.put(seq2, annotationsList2); // Annotation not related to any of secondary structure for seq2
-         Map<SequenceI, List<AlignmentAnnotation>> annotations3 = new HashMap<>();
-         // Empty annotation map
-         
-         Map<SequenceI, List<AlignmentAnnotation>> annotations4 = new HashMap<>();
-         SequenceI seq4 = new Sequence("Seq4", "ASD---ASD---AS-", 37, 44);
-         List<AlignmentAnnotation> annotationsList4 = new ArrayList<>();
-         annotationsList4.add(new AlignmentAnnotation("jnetpred", "jnetpred", new Annotation[]{}));
-         annotations4.put(seq4, annotationsList4); // Annotation present from JPred for seq4
-         return new Object[][]{
-             {annotations1, true}, // Annotations present secondary structure present
-             {annotations2, false}, // No annotations related to any of the secondary structure present
-             {annotations3, false},  // Empty annotation map
-             {annotations4, true}, // Annotations present from JPred secondary structure present
-         };
-     }
-     
-     @Test
-     public void testGetSSSourceFromAnnotationDescription(AlignmentAnnotation[] annotations, String expectedSSSource) {
-         List<String> actualSSSource = AlignmentUtils.extractSSSourceInAlignmentAnnotation(annotations);
-         Assert.assertEquals(actualSSSource, expectedSSSource);
-     }
-     
-     @DataProvider(name = "SSSourceFromAnnotationDescription")
-     public static Object[][] provideSSSourceFromAnnotationDescription() {
-         Map<SequenceI, List<AlignmentAnnotation>> annotations1 = new HashMap<>();
-         SequenceI seq1 = new Sequence("Seq1", "ASD---ASD---ASD", 37, 45);
-         List<AlignmentAnnotation> annotationsList1 = new ArrayList<>();
-         annotationsList1.add(new AlignmentAnnotation("jnetpred", "JPred Output", new Annotation[]{}));
-         annotations1.put(seq1, annotationsList1); // Annotation present from JPred for seq1
-         Map<SequenceI, List<AlignmentAnnotation>> annotations2 = new HashMap<>();
-         SequenceI seq2 = new Sequence("Seq2", "ASD---ASD------", 37, 42);
-         List<AlignmentAnnotation> annotationsList2 = new ArrayList<>();
-         annotationsList2.add(new AlignmentAnnotation("Secondary Structure", 
-                 "Secondary Structure for af-q43517-f1A", new Annotation[]{}));
-         annotations2.put(seq2, annotationsList2); // Annotation present secondary structure from Alphafold for seq2
-         Map<SequenceI, List<AlignmentAnnotation>> annotations3 = new HashMap<>();
-         // Empty annotation map
-         
-         Map<SequenceI, List<AlignmentAnnotation>> annotations4 = new HashMap<>();
-         SequenceI seq4 = new Sequence("Seq4", "ASD---ASD---AS-", 37, 44);
-         List<AlignmentAnnotation> annotationsList4 = new ArrayList<>();
-         annotationsList4.add(new AlignmentAnnotation("Secondary Structure", 
-                 "Secondary Structure for 4zhpA", new Annotation[]{}));
-         annotations4.put(seq4, annotationsList4); // Annotation present secondary structure from pdb for seq4
-         
-         Map<SequenceI, List<AlignmentAnnotation>> annotations5 = new HashMap<>();
-         SequenceI seq5 = new Sequence("Seq5", "ASD---ASD---AS-", 37, 44);
-         List<AlignmentAnnotation> annotationsList5 = new ArrayList<>();
-         annotationsList5.add(new AlignmentAnnotation("Secondary Structure", 
-                 "Secondary Structure for p09911_54-147__3a7wzn.1.p3502557454997462030P", 
-                 new Annotation[]{}));
-         annotations5.put(seq5, annotationsList5); // Annotation present secondary structure from Swiss model for seq5
-         
-         //JPred Output - JPred
-         //Secondary Structure for af-q43517-f1A - Alphafold
-         //Secondary Structure for 4zhpA - Experimental
-         //Secondary Structure for p09911_54-147__3a7wzn.1.p3502557454997462030P - Swiss Model
-         
-         return new Object[][]{
-             {annotations1, "JPred"}, 
-             {annotations2, "Alphafold"}, 
-             {annotations3, null},  
-             {annotations4, "PDB"},
-             {annotations5, "Swiss Model"}
-         };
-     }   
+     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 } };
++        { '-', Color.white } };
+   }
+   @Test(dataProvider = "SSAnnotationPresence")
+   public void testIsSSAnnotationPresent(
+           Map<SequenceI, List<AlignmentAnnotation>> annotations,
+           boolean expectedPresence)
+   {
+     boolean actualPresence = AlignmentUtils
+             .isSSAnnotationPresent(annotations);
+     Assert.assertEquals(actualPresence, expectedPresence);
+   }
+   @DataProvider(name = "SSAnnotationPresence")
+   public static Object[][] provideSSAnnotationPresence()
+   {
+     Map<SequenceI, List<AlignmentAnnotation>> annotations1 = new HashMap<>();
+     SequenceI seq1 = new Sequence("Seq1", "ASD---ASD---ASD", 37, 45);
+     List<AlignmentAnnotation> annotationsList1 = new ArrayList<>();
+     annotationsList1.add(new AlignmentAnnotation("Secondary Structure",
+             "Secondary Structure", new Annotation[] {}));
+     annotations1.put(seq1, annotationsList1); // Annotation present secondary
+                                               // structure for seq1
+     Map<SequenceI, List<AlignmentAnnotation>> annotations2 = new HashMap<>();
+     SequenceI seq2 = new Sequence("Seq2", "ASD---ASD------", 37, 42);
+     List<AlignmentAnnotation> annotationsList2 = new ArrayList<>();
+     annotationsList2.add(new AlignmentAnnotation("Other Annotation",
+             "Other Annotation", new Annotation[] {}));
+     annotations2.put(seq2, annotationsList2); // Annotation not related to any
+                                               // of secondary structure for seq2
+     Map<SequenceI, List<AlignmentAnnotation>> annotations3 = new HashMap<>();
+     // Empty annotation map
+     Map<SequenceI, List<AlignmentAnnotation>> annotations4 = new HashMap<>();
+     SequenceI seq4 = new Sequence("Seq4", "ASD---ASD---AS-", 37, 44);
+     List<AlignmentAnnotation> annotationsList4 = new ArrayList<>();
+     annotationsList4.add(new AlignmentAnnotation("jnetpred", "jnetpred",
+             new Annotation[] {}));
+     annotations4.put(seq4, annotationsList4); // Annotation present from JPred
+                                               // for seq4
+     return new Object[][] { { annotations1, true }, // Annotations present
+                                                     // secondary structure
+                                                     // present
+         { annotations2, false }, // No annotations related to any of the
+                                  // secondary structure present
+         { annotations3, false }, // Empty annotation map
+         { annotations4, true }, // Annotations present from JPred secondary
+                                 // structure present
+     };
+   }
 -  @Test
 -  public void testGetSSSourceFromAnnotationDescription(
 -          AlignmentAnnotation[] annotations, String expectedSSSource)
 -  {
 -    List<String> actualSSSource = AlignmentUtils
 -            .extractSSSourceInAlignmentAnnotation(annotations);
 -    Assert.assertEquals(actualSSSource, expectedSSSource);
 -  }
 -
+   @DataProvider(name = "SSSourceFromAnnotationDescription")
+   public static Object[][] provideSSSourceFromAnnotationDescription()
+   {
+     Map<SequenceI, List<AlignmentAnnotation>> annotations1 = new HashMap<>();
+     SequenceI seq1 = new Sequence("Seq1", "ASD---ASD---ASD", 37, 45);
+     List<AlignmentAnnotation> annotationsList1 = new ArrayList<>();
+     annotationsList1.add(new AlignmentAnnotation("jnetpred", "JPred Output",
+             new Annotation[] {}));
+     annotations1.put(seq1, annotationsList1); // Annotation present from JPred
+                                               // for seq1
+     Map<SequenceI, List<AlignmentAnnotation>> annotations2 = new HashMap<>();
+     SequenceI seq2 = new Sequence("Seq2", "ASD---ASD------", 37, 42);
+     List<AlignmentAnnotation> annotationsList2 = new ArrayList<>();
+     annotationsList2.add(new AlignmentAnnotation("Secondary Structure",
+             "Secondary Structure for af-q43517-f1A", new Annotation[] {}));
+     annotations2.put(seq2, annotationsList2); // Annotation present secondary
+                                               // structure from Alphafold for
+                                               // seq2
+     Map<SequenceI, List<AlignmentAnnotation>> annotations3 = new HashMap<>();
+     // Empty annotation map
+     Map<SequenceI, List<AlignmentAnnotation>> annotations4 = new HashMap<>();
+     SequenceI seq4 = new Sequence("Seq4", "ASD---ASD---AS-", 37, 44);
+     List<AlignmentAnnotation> annotationsList4 = new ArrayList<>();
+     annotationsList4.add(new AlignmentAnnotation("Secondary Structure",
+             "Secondary Structure for 4zhpA", new Annotation[] {}));
+     annotations4.put(seq4, annotationsList4); // Annotation present secondary
+                                               // structure from pdb for seq4
+     Map<SequenceI, List<AlignmentAnnotation>> annotations5 = new HashMap<>();
+     SequenceI seq5 = new Sequence("Seq5", "ASD---ASD---AS-", 37, 44);
+     List<AlignmentAnnotation> annotationsList5 = new ArrayList<>();
+     annotationsList5.add(new AlignmentAnnotation("Secondary Structure",
+             "Secondary Structure for p09911_54-147__3a7wzn.1.p3502557454997462030P",
+             new Annotation[] {}));
+     annotations5.put(seq5, annotationsList5); // Annotation present secondary
+                                               // structure from Swiss model for
+                                               // seq5
+     // JPred Output - JPred
+     // Secondary Structure for af-q43517-f1A - Alphafold
+     // Secondary Structure for 4zhpA - Experimental
+     // Secondary Structure for p09911_54-147__3a7wzn.1.p3502557454997462030P -
+     // Swiss Model
+     return new Object[][] { { annotations1, "JPred" },
+         { annotations2, "Alphafold" },
+         { annotations3, null },
+         { annotations4, "PDB" },
+         { annotations5, "Swiss Model" } };
+   }
  
  }