JAL-4386 - Implementation of retrieving secondary structure
authorRenia Correya <rcorreya001@dundee.ac.uk>
Wed, 15 May 2024 09:58:52 +0000 (10:58 +0100)
committerRenia Correya <rcorreya001@dundee.ac.uk>
Wed, 15 May 2024 09:58:52 +0000 (10:58 +0100)
source/provider from matching the annotation description and PDB entry.
Implementation of Show secondary structure menu option. Updated
calculation of secondary structure consensus.

resources/lang/Messages.properties
src/jalview/analysis/AAFrequency.java
src/jalview/analysis/AlignmentUtils.java
src/jalview/analysis/scoremodels/SecondaryStructureDistanceModel.java
src/jalview/gui/AlignFrame.java
src/jalview/gui/CalculationChooser.java
src/jalview/jbgui/GAlignFrame.java
test/jalview/analysis/AlignmentUtilsTests.java

index 349340f..fea261c 100644 (file)
@@ -283,7 +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_secondary_structure = Show Secondary Structure
 label.show_first = Show first
 label.show_last = Show last
 label.struct_from_pdb = Process secondary structure from PDB
index ea02228..707110a 100755 (executable)
@@ -253,10 +253,7 @@ 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);
-        }
+        AlignmentAnnotation aa = AlignmentUtils.getDisplayedAlignmentAnnotation(sequences[row]);
         if(aa!=null) {
           ssCount++;
         }
index 798b4bc..7d0ccdb 100644 (file)
@@ -37,6 +37,7 @@ import java.util.NoSuchElementException;
 import java.util.Set;
 import java.util.SortedMap;
 import java.util.TreeMap;
+import java.util.Vector;
 
 import jalview.api.AlignCalcWorkerI;
 import jalview.bin.Console;
@@ -53,6 +54,7 @@ import jalview.datamodel.DBRefEntry;
 import jalview.datamodel.GeneLociI;
 import jalview.datamodel.IncompleteCodonException;
 import jalview.datamodel.Mapping;
+import jalview.datamodel.PDBEntry;
 import jalview.datamodel.SeqCigar;
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceFeature;
@@ -2903,14 +2905,14 @@ public class AlignmentUtils
     return Color.gray;
   }
 
-  public static char findSSAnnotationForGivenSeqposition(AlignmentAnnotation[] aa,
+  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);
+      if (aa.getAnnotationForPosition(seqPosition) != null) {
+        Annotation a = aa.getAnnotationForPosition(seqPosition);
         ss = a.secondaryStructure;
         
         //There is no representation for coil and it can be either ' ' or null. 
@@ -2926,11 +2928,118 @@ public class AlignmentUtils
     return ss;    
   }
   
-  public static String getSSSourceFromAnnotationDescription(AlignmentAnnotation[] annotations)
-  {
-    String ssSource = null;
+  public static List<String> extractSSSourceInAlignmentAnnotation(AlignmentAnnotation[] annotations) {
+    
+    List<String> ssSources = new ArrayList<>();
+    Set<String> addedSources = new HashSet<>(); // to keep track of added sources
+
+          
+    for (AlignmentAnnotation aa: annotations) {
+      
+      String ssSource = extractSSSourceFromAnnotationDescription(aa);
+      
+      if (ssSource!= null && !addedSources.contains(ssSource)) {
+          ssSources.add(ssSource);
+          addedSources.add(ssSource);
+      }
+      
+     }
+    Collections.sort(ssSources);
+       
+    return ssSources;
+    
+  }
+  
+  public static String extractSSSourceFromAnnotationDescription(AlignmentAnnotation aa) {
+    
+    
+    for (String label : Constants.SECONDARY_STRUCTURE_LABELS.keySet()) {
+      
+      if (label.equals(aa.label)) {  
+        
+        //For JPred 
+        if(aa.label.equals(Constants.SS_ANNOTATION_FROM_JPRED_LABEL)){
+          
+          return (Constants.SECONDARY_STRUCTURE_LABELS.get(aa.label));
+          
+         }
+        
+        //For input with secondary structure
+        if(aa.label.equals(Constants.SS_ANNOTATION_LABEL) 
+                && aa.description.equals(Constants.SS_ANNOTATION_LABEL)){
+          
+          return (Constants.SECONDARY_STRUCTURE_LABELS.get(aa.label));
+          
+         }
+        
+        //For other sources
+        if(aa.sequenceRef==null) {
+          return null;
+        }
+        else if(aa.sequenceRef.getDatasetSequence()==null) {
+          return null;
+        }
+         Vector<PDBEntry> pdbEntries = aa.sequenceRef.getDatasetSequence().getAllPDBEntries();
+         
+         for (PDBEntry entry : pdbEntries){
+           
+           String entryProvider = entry.getProvider();
+           if(entryProvider == null) {
+             entryProvider = "PDB";
+           }
+           
+           // Trim the string from first occurrence of colon
+           String entryID = entry.getId();
+           int index = entryID.indexOf(':');
+           
+           // Check if colon exists
+           if (index != -1) {
+             
+             // Trim the string from first occurrence of colon
+             entryID = entryID.substring(0, index); 
+             
+           }
+           
+           if(entryProvider == "PDB" && aa.description.toLowerCase().contains
+                     ("secondary structure for " + entryID.toLowerCase())){
+               
+               return entryProvider;
+             
+           }
+           
+           else if (entryProvider != "PDB" && aa.description.toLowerCase().contains(entryID.toLowerCase())){
+              
+              return entryProvider;
+            
+            }
+          
+          }
+          
+        }   
+      }
+    
+    return null;
+    
+  }
+  
+  //to do set priority for labels
+  public static AlignmentAnnotation getDisplayedAlignmentAnnotation(SequenceI seq){
     
-    return ssSource;
+    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;
     
   }
   
index 5b0f242..6cce5b4 100644 (file)
@@ -218,18 +218,20 @@ public class SecondaryStructureDistanceModel extends DistanceScoreModel
             if(!gap1 && !undefinedSS1) {  
               //fetch the position in sequence for the column and finds the
               //corresponding secondary structure annotation
-              //TO DO - consider based on priority
+              //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, seqPosition);              
+                  AlignmentUtils.findSSAnnotationForGivenSeqposition(aa[0], seqPosition);              
             }
             
             if(!gap2 && !undefinedSS2) {              
               int seqPosition = seqs[j].findPosition(cpos);
               AlignmentAnnotation[] aa = seqs[j].getRefSeq().getAnnotation(selectedSSSource);
-              ss2 = 
-                  AlignmentUtils.findSSAnnotationForGivenSeqposition(aa, seqPosition);               
+              if(aa!=null)
+                ss2 = 
+                  AlignmentUtils.findSSAnnotationForGivenSeqposition(aa[0], seqPosition);               
             }           
 
             if ((!gap1 && !gap2) || params.includeGaps())
index 1bf2529..ccda002 100644 (file)
@@ -61,7 +61,9 @@ import java.util.List;
 import java.util.Locale;
 import java.util.Vector;
 
+import javax.swing.AbstractButton;
 import javax.swing.ButtonGroup;
+import javax.swing.ButtonModel;
 import javax.swing.JCheckBoxMenuItem;
 import javax.swing.JComponent;
 import javax.swing.JEditorPane;
@@ -71,6 +73,7 @@ import javax.swing.JLayeredPane;
 import javax.swing.JMenu;
 import javax.swing.JMenuItem;
 import javax.swing.JPanel;
+import javax.swing.JRadioButtonMenuItem;
 import javax.swing.JScrollPane;
 import javax.swing.SwingUtilities;
 
@@ -82,6 +85,7 @@ import jalview.analysis.Dna;
 import jalview.analysis.GeneticCodeI;
 import jalview.analysis.ParseProperties;
 import jalview.analysis.SequenceIdMatcher;
+import jalview.api.AlignCalcWorkerI;
 import jalview.api.AlignExportSettingsI;
 import jalview.api.AlignViewControllerGuiI;
 import jalview.api.AlignViewControllerI;
@@ -150,6 +154,7 @@ import jalview.schemes.ColourSchemeI;
 import jalview.schemes.ColourSchemes;
 import jalview.schemes.ResidueColourScheme;
 import jalview.schemes.TCoffeeColourScheme;
+import jalview.util.Constants;
 import jalview.util.HttpUtils;
 import jalview.util.ImageMaker.TYPE;
 import jalview.util.MessageManager;
@@ -157,6 +162,7 @@ import jalview.util.Platform;
 import jalview.util.imagemaker.BitmapImageSizing;
 import jalview.viewmodel.AlignmentViewport;
 import jalview.viewmodel.ViewportRanges;
+import jalview.workers.SecondaryStructureConsensusThread;
 import jalview.ws.DBRefFetcher;
 import jalview.ws.DBRefFetcher.FetchFinishedListenerI;
 import jalview.ws.jws1.Discoverer;
@@ -5675,6 +5681,133 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     viewport.setShowUnconserved(showNonconservedMenuItem.getState());
     alignPanel.paintAlignment(false, false);
   }
+  
+  @Override
+  protected void updateShowSSRadioButtons(JMenu showSS, ButtonGroup ssButtonGroup){
+    
+    List<String> ssSources = new ArrayList<String>();
+    AlignmentAnnotation[] anns = alignPanel.getAlignment()
+            .getAlignmentAnnotation();
+    
+    ssSources = AlignmentUtils.extractSSSourceInAlignmentAnnotation(anns);
+    
+    // Get the currently selected radio button
+    String selectedButtonModelName = getSelectedRadioButtonDisplayString(ssButtonGroup);
+    boolean selectedButtonModel =  false;
+    
+    // Clear existing radio buttons
+    showSS.removeAll();
+    JRadioButtonMenuItem radioButtonAllSS = new JRadioButtonMenuItem("All");
+    radioButtonAllSS.addActionListener(new ActionListener() {
+      @Override
+      public void actionPerformed(ActionEvent e) {
+          showSS_actionPerformed("All");
+      }
+    });
+    ssButtonGroup.add(radioButtonAllSS);
+    showSS.add(radioButtonAllSS);
+    
+    JRadioButtonMenuItem radioButtonNoneSS = new JRadioButtonMenuItem("None");
+    radioButtonNoneSS.addActionListener(new ActionListener() {
+      @Override
+      public void actionPerformed(ActionEvent e) {
+          showSS_actionPerformed("None");
+      }
+    });
+    ssButtonGroup.add(radioButtonNoneSS);
+    showSS.add(radioButtonNoneSS);
+    showSS.addSeparator();
+
+       for(String ssSource : ssSources) {
+        
+        JRadioButtonMenuItem radioButton = new JRadioButtonMenuItem(ssSource);
+        radioButton.addActionListener(new ActionListener() {
+          @Override
+          public void actionPerformed(ActionEvent e) {
+              showSS_actionPerformed(ssSource);
+          }
+        });
+        ssButtonGroup.add(radioButton);
+        showSS.add(radioButton);
+        
+        // Check if this radio button's name matches the selected radio button's name
+        if (ssSource.equals(selectedButtonModelName)) {
+            radioButton.setSelected(true); // Select this radio button
+            selectedButtonModel = true;
+        }
+        
+      } 
+
+       if (selectedButtonModelName == "None") {
+         // If no radio button was previously selected, select "All"
+         ssButtonGroup.setSelected(radioButtonNoneSS.getModel(), true);
+         selectedButtonModel = true;
+       }
+       if (!selectedButtonModel) {
+           // If no radio button was previously selected, select "All"
+           ssButtonGroup.setSelected(radioButtonAllSS.getModel(), true);
+       }
+  }
+  
+  @Override
+  protected void showSS_actionPerformed(String ssSourceSelection){
+    
+
+    AlignmentAnnotation[] annotations = alignPanel.getAlignment()
+            .getAlignmentAnnotation();
+    
+    for (AlignmentAnnotation aa: annotations) {
+      
+      for (String label : Constants.SECONDARY_STRUCTURE_LABELS.keySet()) {
+        
+        if (label.equals(aa.label)) { 
+          
+          aa.visible = false;
+          
+          if(ssSourceSelection == "All") {
+            aa.visible = true;
+          }
+          
+          else {
+            String ssSource = AlignmentUtils.extractSSSourceFromAnnotationDescription(aa);
+            if(ssSource.equals(ssSourceSelection)) {
+              aa.visible = true;
+            }
+            
+            
+          }
+        }
+      }
+      
+    }
+    
+      
+      List<AlignCalcWorkerI> workers = viewport.getCalcManager()
+              .getRegisteredWorkersOfClass(SecondaryStructureConsensusThread.class);
+      if (!workers.isEmpty()) {
+          
+        viewport.getCalcManager().startWorker(workers.remove(0));
+
+      }
+      
+      PaintRefresher.Refresh(this, viewport.getSequenceSetId());
+      alignPanel.updateAnnotation();
+      alignPanel.paintAlignment(true, true);
+          
+    
+    
+  }
+  
+  protected String getSelectedRadioButtonDisplayString(ButtonGroup ssButtonGroup) {
+    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
+}
 
   /*
    * (non-Javadoc)
index d05aa03..4e22a74 100644 (file)
@@ -594,6 +594,8 @@ public class CalculationChooser extends JPanel
     AlignmentAnnotation[] annotations = af.getViewport().getAlignment().getAlignmentAnnotation();
     
     List<String> ssSources = AlignmentUtils.getSecondaryStructureSources(annotations);
+    //List<String> ssSources = AlignmentUtils.extractSSSourceInAlignmentAnnotation(annotations);
+    
                  
     return ssSources;
   }
index dd66811..3c9f642 100755 (executable)
@@ -32,6 +32,7 @@ import java.awt.event.KeyEvent;
 import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 import javax.swing.BorderFactory;
@@ -55,10 +56,13 @@ import jalview.analysis.GeneticCodeI;
 import jalview.analysis.GeneticCodes;
 import jalview.api.SplitContainerI;
 import jalview.bin.Cache;
+import jalview.bin.Console;
 import jalview.gui.JvSwingUtils;
 import jalview.gui.Preferences;
 import jalview.io.FileFormats;
+import jalview.log.JLoggerLog4j;
 import jalview.schemes.ResidueColourScheme;
+import jalview.util.Log4j;
 import jalview.util.MessageManager;
 import jalview.util.Platform;
 
@@ -1798,14 +1802,60 @@ public class GAlignFrame extends JInternalFrame
     };
     addMenuActionAndAccelerator(keyStroke, copyHighlighted, al);
     copyHighlighted.addActionListener(al);
+    
+    
+
+    ButtonGroup ssButtonGroup = new ButtonGroup();
+    final JRadioButtonMenuItem showAll = new JRadioButtonMenuItem(
+            MessageManager.getString("label.show_first"));
+    final JRadioButtonMenuItem showjPred = new JRadioButtonMenuItem(
+            MessageManager.getString("label.show_last"));
+    final JRadioButtonMenuItem show3DSS = new JRadioButtonMenuItem(
+            MessageManager.getString("label.show_last"));
+    ssButtonGroup.add(showAll);
+    ssButtonGroup.add(showjPred);
+    ssButtonGroup.add(show3DSS);
+    final boolean autoFirst1 = Cache
+            .getDefault(Preferences.SHOW_AUTOCALC_ABOVE, false);
+    showAll.setSelected(autoFirst1);
+    setShowAutoCalculatedAbove(autoFirst);
+    showAutoFirst.addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        setShowAutoCalculatedAbove(showAutoFirst.isSelected());
+        sortAnnotations_actionPerformed();
+      }
+    });
+    showAutoLast.setSelected(!showAutoFirst.isSelected());
+    showAutoLast.addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        setShowAutoCalculatedAbove(!showAutoLast.isSelected());
+        sortAnnotations_actionPerformed();
+      }
+    });
 
     JMenu tooltipSettingsMenu = new JMenu(
             MessageManager.getString("label.sequence_id_tooltip"));
     JMenu autoAnnMenu = new JMenu(
             MessageManager.getString("label.autocalculated_annotation"));
 
-    JMenu selectSS = new JMenu(
-            MessageManager.getString("label.select_secondary_structure_preference"));
+    JMenu showSS = new JMenu(
+            MessageManager.getString("label.show_secondary_structure")); 
+    
+    showSS.addMouseListener(new MouseAdapter() {
+      
+      @Override
+      public void mouseEntered(MouseEvent e) {
+
+          updateShowSSRadioButtons(showSS, ssButtonGroup); // Update radio buttons every time the menu is clicked
+         
+      }
+    });
     
     JMenu exportImageMenu = new JMenu(
             MessageManager.getString("label.export_image"));
@@ -1907,6 +1957,8 @@ public class GAlignFrame extends JInternalFrame
     annotationsMenu.add(sortAnnBySequence);
     annotationsMenu.add(sortAnnByLabel);
     annotationsMenu.addSeparator();
+    annotationsMenu.add(showSS);
+    annotationsMenu.addSeparator();
     autoAnnMenu.add(showAutoFirst);
     autoAnnMenu.add(showAutoLast);
     autoAnnMenu.addSeparator();
@@ -1919,8 +1971,6 @@ 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);
@@ -2816,4 +2866,22 @@ public class GAlignFrame extends JInternalFrame
   protected void showComplement_actionPerformed(boolean complement)
   {
   }
+
+  protected List<String> updateShowSSRadioButtons()
+  {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  protected void updateShowSSRadioButtons(JMenu showSS,
+          ButtonGroup ssButtonGroup)
+  {
+    // TODO Auto-generated method stub
+  }
+
+  protected void showSS_actionPerformed(String ssSourceSelection)
+  {
+    // TODO Auto-generated method stub
+    
+  }
 }
index eee5e87..d5639fa 100644 (file)
@@ -36,6 +36,7 @@ import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.SortedMap;
 import java.util.TreeMap;
 
@@ -2855,12 +2856,12 @@ public class AlignmentUtilsTests
             {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);
-//    }
+    
+    @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() {