From 4e8b2752f94195adadb8ae9b46e0fcd5181a7155 Mon Sep 17 00:00:00 2001 From: Renia Correya Date: Wed, 15 May 2024 10:58:52 +0100 Subject: [PATCH] JAL-4386 - Implementation of retrieving secondary structure 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 | 2 +- src/jalview/analysis/AAFrequency.java | 5 +- src/jalview/analysis/AlignmentUtils.java | 123 ++++++++++++++++-- .../SecondaryStructureDistanceModel.java | 10 +- src/jalview/gui/AlignFrame.java | 133 ++++++++++++++++++++ src/jalview/gui/CalculationChooser.java | 2 + src/jalview/jbgui/GAlignFrame.java | 76 ++++++++++- test/jalview/analysis/AlignmentUtilsTests.java | 13 +- 8 files changed, 338 insertions(+), 26 deletions(-) diff --git a/resources/lang/Messages.properties b/resources/lang/Messages.properties index 349340f..fea261c 100644 --- a/resources/lang/Messages.properties +++ b/resources/lang/Messages.properties @@ -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 diff --git a/src/jalview/analysis/AAFrequency.java b/src/jalview/analysis/AAFrequency.java index ea02228..707110a 100755 --- a/src/jalview/analysis/AAFrequency.java +++ b/src/jalview/analysis/AAFrequency.java @@ -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++; } diff --git a/src/jalview/analysis/AlignmentUtils.java b/src/jalview/analysis/AlignmentUtils.java index 798b4bc..7d0ccdb 100644 --- a/src/jalview/analysis/AlignmentUtils.java +++ b/src/jalview/analysis/AlignmentUtils.java @@ -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 extractSSSourceInAlignmentAnnotation(AlignmentAnnotation[] annotations) { + + List ssSources = new ArrayList<>(); + Set 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 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; } diff --git a/src/jalview/analysis/scoremodels/SecondaryStructureDistanceModel.java b/src/jalview/analysis/scoremodels/SecondaryStructureDistanceModel.java index 5b0f242..6cce5b4 100644 --- a/src/jalview/analysis/scoremodels/SecondaryStructureDistanceModel.java +++ b/src/jalview/analysis/scoremodels/SecondaryStructureDistanceModel.java @@ -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()) diff --git a/src/jalview/gui/AlignFrame.java b/src/jalview/gui/AlignFrame.java index 1bf2529..ccda002 100644 --- a/src/jalview/gui/AlignFrame.java +++ b/src/jalview/gui/AlignFrame.java @@ -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 ssSources = new ArrayList(); + 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 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 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) diff --git a/src/jalview/gui/CalculationChooser.java b/src/jalview/gui/CalculationChooser.java index d05aa03..4e22a74 100644 --- a/src/jalview/gui/CalculationChooser.java +++ b/src/jalview/gui/CalculationChooser.java @@ -594,6 +594,8 @@ public class CalculationChooser extends JPanel AlignmentAnnotation[] annotations = af.getViewport().getAlignment().getAlignmentAnnotation(); List ssSources = AlignmentUtils.getSecondaryStructureSources(annotations); + //List ssSources = AlignmentUtils.extractSSSourceInAlignmentAnnotation(annotations); + return ssSources; } diff --git a/src/jalview/jbgui/GAlignFrame.java b/src/jalview/jbgui/GAlignFrame.java index dd66811..3c9f642 100755 --- a/src/jalview/jbgui/GAlignFrame.java +++ b/src/jalview/jbgui/GAlignFrame.java @@ -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 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 + + } } diff --git a/test/jalview/analysis/AlignmentUtilsTests.java b/test/jalview/analysis/AlignmentUtilsTests.java index eee5e87..d5639fa 100644 --- a/test/jalview/analysis/AlignmentUtilsTests.java +++ b/test/jalview/analysis/AlignmentUtilsTests.java @@ -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> annotations, String expectedSSSource) { -// String actualSSSource = AlignmentUtils.getSSSourceFromAnnotationDescription(annotations); -// Assert.assertEquals(actualSSSource, expectedSSSource); -// } + + @Test + public void testGetSSSourceFromAnnotationDescription(AlignmentAnnotation[] annotations, String expectedSSSource) { + List actualSSSource = AlignmentUtils.extractSSSourceInAlignmentAnnotation(annotations); + Assert.assertEquals(actualSSSource, expectedSSSource); + } @DataProvider(name = "SSSourceFromAnnotationDescription") public static Object[][] provideSSSourceFromAnnotationDescription() { -- 1.7.10.2