From: Renia Correya Date: Tue, 28 May 2024 10:13:00 +0000 (+0100) Subject: JAL-4386 Added secondary structure providers check boxes in show X-Git-Url: http://source.jalview.org/gitweb/?a=commitdiff_plain;h=b3d82da0ff6f8695b23c3be9624b0ee4fe146e15;p=jalview.git JAL-4386 Added secondary structure providers check boxes in show secondary structure menu. Implemented displaying of secondary structure and consensus based on user selection. Added secondary structure providers option in calculate window. Added provider label in pca panel and tree panel for secondary structure similarity. --- diff --git a/resources/lang/Messages.properties b/resources/lang/Messages.properties index 9e68eab..3f2e633 100644 --- a/resources/lang/Messages.properties +++ b/resources/lang/Messages.properties @@ -1293,7 +1293,9 @@ label.quality_descr = Alignment Quality based on Blosum62 scores label.conservation_descr = Conservation of total alignment less than {0}% gaps label.consensus_descr = PID label.ssconsensus_label = Secondary Structure Consensus -label.ssconsensus_descr = SS Consensus +label.ssconsensus_descr = Secondary Structure Consensus +option.ss_providers_all = All +option.ss_providers_none = None label.complement_consensus_descr = PID for cDNA label.strucconsensus_descr = PID for base pairs label.occupancy_descr = Number of aligned positions diff --git a/src/jalview/analysis/AAFrequency.java b/src/jalview/analysis/AAFrequency.java index 707110a..a979c45 100755 --- a/src/jalview/analysis/AAFrequency.java +++ b/src/jalview/analysis/AAFrequency.java @@ -196,13 +196,13 @@ public class AAFrequency public static final ProfilesI calculateSS(List 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 sequences, - int start, int end, boolean profile) + int start, int end, boolean profile, String source) { SequenceI[] seqs = new SequenceI[sequences.size()]; int width = 0; @@ -222,14 +222,15 @@ public class AAFrequency { end = width; } + - ProfilesI reply = calculateSS(seqs, width, start, end, profile); + ProfilesI reply = calculateSS(seqs, width, start, end, profile, source); 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; @@ -253,27 +254,31 @@ public class AAFrequency } 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); + List annots = AlignmentUtils.getAlignmentAnnotationForSource(sequences[row], source); + if(annots!=null) { + for(AlignmentAnnotation aa:annots) { + if(aa!=null) { + ssCount++; + } - char ss = AlignmentUtils.findSSAnnotationForGivenSeqposition( - aa, seqPosition); - if(ss == '*') { - continue; - } - ssCounts.add(ss); - } - else if(Comparison.isGap(c) && aa!=null) { - ssCounts.addGap(); + 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(); + } } } + } int maxSSCount = ssCounts.getModalCount(); String maxSS = ssCounts.getSSForCount(maxSSCount); diff --git a/src/jalview/analysis/AlignmentUtils.java b/src/jalview/analysis/AlignmentUtils.java index 7d0ccdb..eec982b 100644 --- a/src/jalview/analysis/AlignmentUtils.java +++ b/src/jalview/analysis/AlignmentUtils.java @@ -70,6 +70,7 @@ import jalview.util.DBRefUtils; import jalview.util.IntRangeComparator; import jalview.util.MapList; import jalview.util.MappingUtils; +import jalview.util.MessageManager; import jalview.workers.SecondaryStructureConsensusThread; /** @@ -2854,193 +2855,302 @@ public class AlignmentUtils } - public static List getSecondaryStructureSources(AlignmentAnnotation[] annotations) { - - List ssSources = new ArrayList<>(); - Set addedLabels = new HashSet<>(); // to keep track of added labels - - for (AlignmentAnnotation annotation : annotations) { - String label = annotation.label; - if (Constants.SECONDARY_STRUCTURE_LABELS.containsKey(label) && !addedLabels.contains(label)) { - ssSources.add(Constants.SECONDARY_STRUCTURE_LABELS.get(label)); - addedLabels.add(label); // Add the label to the set - } + public static List getSecondaryStructureSources( + AlignmentAnnotation[] annotations) + { + + List ssSources = new ArrayList<>(); + Set addedLabels = new HashSet<>(); // to keep track of added labels + + for (AlignmentAnnotation annotation : annotations) + { + String label = annotation.label; + if (Constants.SECONDARY_STRUCTURE_LABELS.containsKey(label) + && !addedLabels.contains(label)) + { + ssSources.add(Constants.SECONDARY_STRUCTURE_LABELS.get(label)); + addedLabels.add(label); // Add the label to the set } + } - return ssSources; + return ssSources; } public static boolean isSecondaryStructurePresent(AlignmentAnnotation[] annotations) { boolean ssPresent = false; - + for (AlignmentAnnotation aa : annotations) { - if(ssPresent) { + if (ssPresent) + { break; - } + } - if (Constants.SECONDARY_STRUCTURE_LABELS.containsKey(aa.label)) { - ssPresent = true; - break; + if (Constants.SECONDARY_STRUCTURE_LABELS.containsKey(aa.label)) + { + ssPresent = true; + break; } } - + return ssPresent; - + } - public static Color getSecondaryStructureAnnotationColour(char symbol){ - - if (symbol== Constants.COIL) { + public static Color getSecondaryStructureAnnotationColour(char symbol) + { + + if (symbol == Constants.COIL) + { return Color.gray; } - if (symbol== Constants.SHEET) { + if (symbol == Constants.SHEET) + { return Color.green; } - if (symbol== Constants.HELIX) { + if (symbol == Constants.HELIX) + { return Color.red; } - + return Color.gray; } public static char findSSAnnotationForGivenSeqposition(AlignmentAnnotation aa, int seqPosition) { - char ss = '*'; - - if (aa != null) { - if (aa.getAnnotationForPosition(seqPosition) != null) { + char ss = '*'; + + if (aa != null) + { + 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. - if (ss == ' ' || ss == '-') { - ss = Constants.COIL; + + // There is no representation for coil and it can be either ' ' or null. + if (ss == ' ' || ss == '-') + { + ss = Constants.COIL; } } - else { + else + { ss = Constants.COIL; - } + } } - - return ss; + + return ss; } - public static List extractSSSourceInAlignmentAnnotation(AlignmentAnnotation[] annotations) { - + public static List extractSSSourceInAlignmentAnnotation( + AlignmentAnnotation[] annotations) + { + List ssSources = new ArrayList<>(); - Set addedSources = new HashSet<>(); // to keep track of added sources + Set addedSources = new HashSet<>(); // to keep track of added + // sources + + if (annotations == null) + { + return ssSources; + } + + for (AlignmentAnnotation aa : annotations) + { - - for (AlignmentAnnotation aa: annotations) { - String ssSource = extractSSSourceFromAnnotationDescription(aa); - - if (ssSource!= null && !addedSources.contains(ssSource)) { - ssSources.add(ssSource); - addedSources.add(ssSource); + + 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)){ - + 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)){ - + + } + + // 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) { + + } + + // For other sources + if (aa.sequenceRef == null) + { return null; } - else if(aa.sequenceRef.getDatasetSequence()==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; - - } - + 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){ - - 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; + public static List getAlignmentAnnotationForSource( + SequenceI seq, String ssSource) + { + + List ssAnnots = new ArrayList(); + for (String ssLabel : Constants.SECONDARY_STRUCTURE_LABELS.keySet()) + { + + AlignmentAnnotation[] aa = seq.getAnnotation(ssLabel); + if (aa != null) + { + + if (ssSource.equals(MessageManager.getString("option.ss_providers_all"))) + { + ssAnnots.addAll(Arrays.asList(aa)); + continue; + } + + for (AlignmentAnnotation annot : aa) + { + + if (ssSource + .equals(extractSSSourceFromAnnotationDescription(annot))) + { + ssAnnots.add(annot); + } } } - } } - + if (ssAnnots.size() > 0) + { + return ssAnnots; + } + return null; - + + } + + public static Map> getSequenceAssociatedAlignmentAnnotations( + AlignmentAnnotation[] alignAnnotList, String selectedSSSource) + { + + Map> ssAlignmentAnnotationForSequences + = new HashMap>(); + 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 (selectedSSSource.equals(MessageManager.getString("option.ss_providers_all"))) + { + ssAlignmentAnnotationForSequences + .computeIfAbsent(aa.sequenceRef.getDatasetSequence(), + k -> new ArrayList<>()) + .add(aa); + break; + } + + String ssSource = AlignmentUtils + .extractSSSourceFromAnnotationDescription(aa); + if (ssSource.equals(selectedSSSource)) + { + + ssAlignmentAnnotationForSequences + .computeIfAbsent(aa.sequenceRef.getDatasetSequence(), + k -> new ArrayList<>()) + .add(aa); + break; + } + } + } + } + + return ssAlignmentAnnotationForSequences; + } } diff --git a/src/jalview/analysis/scoremodels/SecondaryStructureDistanceModel.java b/src/jalview/analysis/scoremodels/SecondaryStructureDistanceModel.java index 6cce5b4..4e3a3de 100644 --- a/src/jalview/analysis/scoremodels/SecondaryStructureDistanceModel.java +++ b/src/jalview/analysis/scoremodels/SecondaryStructureDistanceModel.java @@ -27,14 +27,13 @@ import jalview.api.analysis.ScoreModelI; import jalview.api.analysis.SimilarityParamsI; import jalview.datamodel.AlignmentAnnotation; import jalview.datamodel.AlignmentView; -import jalview.datamodel.Annotation; import jalview.datamodel.SeqCigar; +import jalview.datamodel.SequenceI; import jalview.math.Matrix; import jalview.math.MatrixI; -import jalview.util.Constants; -import jalview.util.SetUtils; +import jalview.util.MessageManager; -import java.util.HashMap; +import java.util.ArrayList; import java.util.HashSet; import java.util.Map; import java.util.Set; @@ -110,53 +109,29 @@ public class SecondaryStructureDistanceModel extends DistanceScoreModel SeqCigar[] seqs = seqData.getSequences(); int noseqs = seqs.length; //no of sequences - int cpwidth = 0; // = seqData.getWidth(); + 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(); - 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; + if(ssSource == null || ssSource == "") { + ssSource = MessageManager.getString("option.ss_providers_all"); } + ssRateMatrix = ScoreModels.getInstance().getSecondaryStructureMatrix(); // need to get real position for view position int[] viscont = seqData.getVisibleContigs(); - /* - * Add secondary structure annotations that are added to the annotation track - * to the map - */ - Map> ssAlignmentAnnotationForSequences - = new HashMap>(); AlignmentAnnotation[] alignAnnotList = fr.getViewport().getAlignment() .getAlignmentAnnotation(); - if(alignAnnotList.length > 0) { - for (AlignmentAnnotation aa: alignAnnotList) { - if (selectedSSSource.equals(aa.label)) { - ssAlignmentAnnotationForSequences.computeIfAbsent( - aa.sequenceRef.getName(), k -> new HashSet<>()) - .add(aa.description); - } - } - } - + /* - * Get the set of sequences which are not considered for the 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 + * Add secondary structure annotations that are added to the annotation track + * to the map */ - Set seqsWithUndefinedSS - = findSeqsWithUndefinedSS(seqs, ssAlignmentAnnotationForSequences); + Map> ssAlignmentAnnotationForSequences + = AlignmentUtils.getSequenceAssociatedAlignmentAnnotations(alignAnnotList, ssSource); /* * scan each column, compute and add to each similarity[i, j] @@ -185,13 +160,10 @@ public class SecondaryStructureDistanceModel extends DistanceScoreModel //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); + 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) { @@ -206,8 +178,8 @@ public class SecondaryStructureDistanceModel extends DistanceScoreModel } //check if the sequence contains gap in the current column - boolean gap1 = !seqsWithoutGapAtCol.contains(sc1); - boolean gap2 = !seqsWithoutGapAtCol.contains(sc2); + boolean gap1 = !seqsWithoutGapAtCol.contains(seqs[i]); + boolean gap2 = !seqsWithoutGapAtCol.contains(seqs[j]); //Variable to store secondary structure at the current column char ss1 = '*'; @@ -220,18 +192,18 @@ public class SecondaryStructureDistanceModel extends DistanceScoreModel //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); + AlignmentAnnotation aa = ssAlignmentAnnotationForSequences.get(seqs[i].getRefSeq()).get(0); if(aa!=null) ss1 = - AlignmentUtils.findSSAnnotationForGivenSeqposition(aa[0], seqPosition); + AlignmentUtils.findSSAnnotationForGivenSeqposition(aa, seqPosition); } if(!gap2 && !undefinedSS2) { int seqPosition = seqs[j].findPosition(cpos); - AlignmentAnnotation[] aa = seqs[j].getRefSeq().getAnnotation(selectedSSSource); + AlignmentAnnotation aa = ssAlignmentAnnotationForSequences.get(seqs[j].getRefSeq()).get(0); if(aa!=null) ss2 = - AlignmentUtils.findSSAnnotationForGivenSeqposition(aa[0], seqPosition); + AlignmentUtils.findSSAnnotationForGivenSeqposition(aa, seqPosition); } if ((!gap1 && !gap2) || params.includeGaps()) @@ -291,65 +263,6 @@ public class SecondaryStructureDistanceModel extends DistanceScoreModel 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 findSeqsWithUndefinedSS(SeqCigar[] seqs, - Map> ssAlignmentAnnotationForSequences) { - Set 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> ssAlignmentAnnotationForSequences) { - for (String label : Constants.SECONDARY_STRUCTURE_LABELS.keySet()) { - AlignmentAnnotation[] annotations = seq.getRefSeq().getAnnotation(label); - if (annotations != null) { - for (AlignmentAnnotation annotation : annotations) { - HashSet descriptionSet = ssAlignmentAnnotationForSequences - .get(annotation.sequenceRef.getName()); - if (descriptionSet != null) - { - if (descriptionSet.contains(annotation.description)) { - // Secondary structure annotation is present and - //added to the track, no need to add seq - return false; - } - } - } - } - } - // Either annotations are undefined or not added to the track - return true; - } @Override public String getName() diff --git a/src/jalview/api/AlignViewportI.java b/src/jalview/api/AlignViewportI.java index b7747f5..404d8ea 100644 --- a/src/jalview/api/AlignViewportI.java +++ b/src/jalview/api/AlignViewportI.java @@ -134,7 +134,7 @@ public interface AlignViewportI extends ViewStyleI */ AlignmentAnnotation getAlignmentConsensusAnnotation(); - AlignmentAnnotation getAlignmentSecondaryStructureConsensusAnnotation(); + List getAlignmentSecondaryStructureConsensusAnnotation(); /** @@ -183,7 +183,7 @@ public interface AlignViewportI extends ViewStyleI */ void setSequenceConsensusHash(ProfilesI hconsensus); - void setSequenceSSConsensusHash(ProfilesI hSSConsensus); + void setSequenceSSConsensusHash(Map hSSConsesnusProfileMap); /** @@ -578,6 +578,10 @@ public interface AlignViewportI extends ViewStyleI ContactMatrixI getContactMatrix(AlignmentAnnotation alignmentAnnotation); - ProfilesI getSequenceSSConsensusHash(); + Map getSequenceSSConsensusHash(); + + List getSecondaryStructureSources(); + + void setSecondaryStructureSources(List secondaryStructureSources); } diff --git a/src/jalview/datamodel/Alignment.java b/src/jalview/datamodel/Alignment.java index 73ccdc5..ce9250c 100755 --- a/src/jalview/datamodel/Alignment.java +++ b/src/jalview/datamodel/Alignment.java @@ -71,6 +71,8 @@ public class Alignment implements AlignmentI, AutoCloseable public Hashtable alignmentProperties; private List codonFrameList; + + private List secondaryStructureSources; private void initAlignment(SequenceI[] seqs) { @@ -82,12 +84,13 @@ public class Alignment implements AlignmentI, AutoCloseable nucleotide = Comparison.isNucleotide(seqs); sequences = Collections.synchronizedList(new ArrayList()); + for (int i = 0; i < seqs.length; i++) { sequences.add(seqs[i]); } - + } /** @@ -2122,4 +2125,16 @@ public class Alignment implements AlignmentI, AutoCloseable cmholder.addContactListFor(annotation, cm); } + + public List getSecondaryStructureSources() + { + return secondaryStructureSources; + } + + public void setSecondaryStructureSources( + List secondaryStructureSources) + { + this.secondaryStructureSources = secondaryStructureSources; + } + } diff --git a/src/jalview/datamodel/SequenceGroup.java b/src/jalview/datamodel/SequenceGroup.java index b5048a0..5416ac4 100755 --- a/src/jalview/datamodel/SequenceGroup.java +++ b/src/jalview/datamodel/SequenceGroup.java @@ -26,6 +26,8 @@ import java.beans.PropertyChangeSupport; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; @@ -34,6 +36,7 @@ import jalview.analysis.Conservation; import jalview.renderer.ResidueShader; import jalview.renderer.ResidueShaderI; import jalview.schemes.ColourSchemeI; +import jalview.util.MessageManager; /** * Collects a set contiguous ranges on a set of sequences @@ -154,7 +157,7 @@ public class SequenceGroup implements AnnotatedCollectionI AlignmentAnnotation consensus = null; - AlignmentAnnotation ssConsensus = null; + List ssConsensus = null; AlignmentAnnotation conservation = null; @@ -619,18 +622,31 @@ public class SequenceGroup implements AnnotatedCollectionI cs.setConsensus(cnsns); upd = true; } + + Map hSSConsensusProfileMap = new HashMap(); + List ssSources = new ArrayList(); - - ProfilesI ssCnsns = AAFrequency.calculateSS(sequences, startRes, - endRes + 1, showSequenceLogo); + //ssSources = AlignmentUtils.extractSSSourceInAlignmentAnnotation(ssConsensus.toArray()); + if(ssSources != null) { + ssSources.add(MessageManager.getString("option.ss_providers_all")); + + 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; } @@ -726,27 +742,44 @@ public class SequenceGroup implements AnnotatedCollectionI public ProfilesI ssConsensusData = null; - private void _updateSSConsensusRow(ProfilesI ssCnsns, long nseq) + private void _updateSSConsensusRow(Map hSSConsensusProfileMap, long nseq) { + List ssSources = new ArrayList<>(hSSConsensusProfileMap.keySet()); + + Collections.sort(ssSources); if (ssConsensus == null) { - getSSConsensus(); + getSSConsensus(ssSources); } - ssConsensus.label = "Sec Str Consensus for " + getName(); - ssConsensus.description = "Percent Identity"; - ssConsensusData = ssCnsns; - // preserve width if already set - int aWidth = (ssConsensus.annotations != null) - ? (endRes < ssConsensus.annotations.length - ? ssConsensus.annotations.length - : endRes + 1) - : endRes + 1; - ssConsensus.annotations = null; - ssConsensus.annotations = new Annotation[aWidth]; // should be alignment width + for (AlignmentAnnotation aa : ssConsensus) { + ProfilesI profile = null; + String ssSource = null; + for(String source : ssSources) { + if(aa.description.startsWith(source)) { + profile = hSSConsensusProfileMap.get(source); + ssSource = source; + } + } + if(profile == null) { + continue; + } - AAFrequency.completeSSConsensus(ssConsensus, ssCnsns, startRes, endRes + 1, + aa.label = MessageManager.getString("label.ssconsensus_label") + " " + ssSource + " " + getName(); + aa.description = ssSource + MessageManager.getString("label.ssconsensus_label") +" for " + getName(); + ssConsensusData = profile; + // preserve width if already set + int aWidth = (aa.annotations != null) + ? (endRes < aa.annotations.length + ? aa.annotations.length + : endRes + 1) + : endRes + 1; + aa.annotations = null; + aa.annotations = new Annotation[aWidth]; // should be alignment width + + AAFrequency.completeSSConsensus(aa, profile, startRes, endRes + 1, ignoreGapsInConsensus, showSequenceLogo, nseq); // TODO: setting // container + } // for // ignoreGapsInConsensusCalculation); } @@ -1206,7 +1239,7 @@ public class SequenceGroup implements AnnotatedCollectionI return consensus; } - public AlignmentAnnotation getSSConsensus() + public List getSSConsensus(List ssSources) { // TODO get or calculate and get consensus annotation row for this group int aWidth = this.getWidth(); @@ -1219,13 +1252,20 @@ public class SequenceGroup implements AnnotatedCollectionI } if (ssConsensus == null) { - ssConsensus = new AlignmentAnnotation("", "", new Annotation[1], 0f, - 100f, AlignmentAnnotation.BAR_GRAPH); - ssConsensus.hasText = true; - ssConsensus.autoCalculated = true; - ssConsensus.groupRef = this; - ssConsensus.label = "Sec Str Consensus for " + getName(); - ssConsensus.description = "Percent Identity"; + ssConsensus = new ArrayList(); + + for(String ssSource : ssSources) { + AlignmentAnnotation aa = new AlignmentAnnotation("", "", new Annotation[1], 0f, + 100f, AlignmentAnnotation.BAR_GRAPH); + aa.hasText = true; + aa.autoCalculated = true; + aa.groupRef = this; + + aa.label = MessageManager.getString("label.ssconsensus_label") + " " + ssSource + " " + getName(); + aa.description = ssSource + MessageManager.getString("label.ssconsensus_label") +" for " + getName(); + ssConsensus.add(aa); + } + } return ssConsensus; } diff --git a/src/jalview/gui/AlignFrame.java b/src/jalview/gui/AlignFrame.java index ccda002..45bfe83 100644 --- a/src/jalview/gui/AlignFrame.java +++ b/src/jalview/gui/AlignFrame.java @@ -56,14 +56,14 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Deque; import java.util.Enumeration; +import java.util.HashMap; import java.util.Hashtable; import java.util.List; import java.util.Locale; +import java.util.Map; 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; @@ -73,7 +73,6 @@ 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; @@ -85,7 +84,6 @@ 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; @@ -162,7 +160,6 @@ 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; @@ -5683,131 +5680,111 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, } @Override - protected void updateShowSSRadioButtons(JMenu showSS, ButtonGroup ssButtonGroup){ + protected void updateShowSecondaryStructureMenu(JMenu showSS, ButtonGroup ssButtonGroup){ List ssSources = new ArrayList(); AlignmentAnnotation[] anns = alignPanel.getAlignment() .getAlignmentAnnotation(); + Map checkboxMap = getCheckboxesInMenu(showSS); ssSources = AlignmentUtils.extractSSSourceInAlignmentAnnotation(anns); - // Get the currently selected radio button - String selectedButtonModelName = getSelectedRadioButtonDisplayString(ssButtonGroup); - boolean selectedButtonModel = false; + List selectedCheckBoxes = getSelectedOptions(checkboxMap); - // 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"); + // Add checkboxes for categories + for (String ssSource : ssSources) { + + if(checkboxMap.get(ssSource)== null) { + JCheckBoxMenuItem checkBox = new JCheckBoxMenuItem(ssSource); + checkBox.setSelected(false); + + checkBox.addItemListener(e -> { + if (e.getStateChange() == ItemEvent.SELECTED) { + + showOrHideSecondaryStructureForSource(ssSource, true); + + } else { + + + showOrHideSecondaryStructureForSource(ssSource, false); + } + }); + showSS.add(checkBox); } - }); - ssButtonGroup.add(radioButtonNoneSS); - showSS.add(radioButtonNoneSS); - showSS.addSeparator(); + } + // Iterate over the keys of checkboxMap + for (String key : checkboxMap.keySet()) { + // Check if the key is not in ssSources + if (!ssSources.contains(key)) { + showSS.remove(checkboxMap.get(key)); + checkboxMap.remove(key); + selectedCheckBoxes.remove(key); + } + if(selectedCheckBoxes.contains(key)){ + checkboxMap.get(key).setSelected(true); + } + else { + checkboxMap.get(key).setSelected(false); + } - 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; + ssButtonGroup.clearSelection(); + } + + } + + private List getSelectedOptions(Map checkboxMap) { + List selectedOptions = new ArrayList<>(); + for (String key : checkboxMap.keySet()) { + JCheckBoxMenuItem checkbox = checkboxMap.get(key); + if (checkbox.isSelected()) { + selectedOptions.add(key); } - - } - - 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); - } + } + return selectedOptions; } - @Override - protected void showSS_actionPerformed(String ssSourceSelection){ + private Map getCheckboxesInMenu(JMenu menu) { + Map checkboxMap = new HashMap<>(); + for (Component component : menu.getMenuComponents()) { + if (component instanceof JCheckBoxMenuItem) { + JCheckBoxMenuItem checkbox = (JCheckBoxMenuItem) component; + checkboxMap.put(checkbox.getText(), checkbox); + } + } + return checkboxMap; +} + + + protected void showOrHideSecondaryStructureForSource(String ssSourceSelection, boolean visible){ - AlignmentAnnotation[] annotations = alignPanel.getAlignment() .getAlignmentAnnotation(); for (AlignmentAnnotation aa: annotations) { + if(aa.label.startsWith(MessageManager.getString("label.ssconsensus_label")) && aa.description.startsWith(ssSourceSelection)) { + aa.visible = visible; + } + 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; - } - - - } + aa.visible = visible; + } } } } - - 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/AlignViewport.java b/src/jalview/gui/AlignViewport.java index 4e1fcab..756a266 100644 --- a/src/jalview/gui/AlignViewport.java +++ b/src/jalview/gui/AlignViewport.java @@ -318,7 +318,7 @@ public class AlignViewport extends AlignmentViewport if (residueShading != null) { residueShading.setConsensus(hconsensus); - residueShading.setSsConsensus(hSSConsensus); + residueShading.setSSConsensusProfileMap(hSSConsensusProfileMap); } setColourAppliesToAllGroups(true); } diff --git a/src/jalview/gui/CalculationChooser.java b/src/jalview/gui/CalculationChooser.java index 4e22a74..8c8bf21 100644 --- a/src/jalview/gui/CalculationChooser.java +++ b/src/jalview/gui/CalculationChooser.java @@ -312,7 +312,7 @@ public class CalculationChooser extends JPanel } this.add(actionPanel, BorderLayout.SOUTH); - int width = 365; + int width = 375; int height = includeParams ? 420 : 240; setMinimumSize(new Dimension(325, height - 10)); @@ -467,8 +467,13 @@ public class CalculationChooser extends JPanel final JComboBox comboBox = new JComboBox<>(); Object curSel = comboBox.getSelectedItem(); DefaultComboBoxModel sourcesModel = new DefaultComboBoxModel<>(); - + List ssSources = getApplicableSecondaryStructureSources(); + + if(ssSources == null) { + return comboBox; + } + ssSources.add(0, MessageManager.getString("option.ss_providers_all")); boolean selectedIsPresent = false; for (String source : ssSources) @@ -593,8 +598,8 @@ public class CalculationChooser extends JPanel { AlignmentAnnotation[] annotations = af.getViewport().getAlignment().getAlignmentAnnotation(); - List ssSources = AlignmentUtils.getSecondaryStructureSources(annotations); - //List ssSources = AlignmentUtils.extractSSSourceInAlignmentAnnotation(annotations); + //List ssSources = AlignmentUtils.getSecondaryStructureSources(annotations); + List ssSources = AlignmentUtils.extractSSSourceInAlignmentAnnotation(annotations); return ssSources; @@ -607,16 +612,18 @@ public class CalculationChooser extends JPanel { boolean doPCA = pca.isSelected(); String modelName = modelNames.getSelectedItem().toString(); - String ssSource = ""; - Object selectedItem = ssSourceDropdown.getSelectedItem(); - if (selectedItem != null) { - ssSource = selectedItem.toString(); + + String ssSource = null; + + if (modelName.equals(secondaryStructureModelName)) { + Object selectedItem = ssSourceDropdown.getSelectedItem(); + if (selectedItem != null) { + ssSource = selectedItem.toString(); + } } SimilarityParams params = getSimilarityParameters(doPCA); - if(ssSource.length()>0) - { - params.setSecondaryStructureSource(ssSource); - } + params.setSecondaryStructureSource(ssSource); + if (doPCA) { openPcaPanel(modelName, params); diff --git a/src/jalview/gui/PCAPanel.java b/src/jalview/gui/PCAPanel.java index 576f3b2..0bcb0da 100644 --- a/src/jalview/gui/PCAPanel.java +++ b/src/jalview/gui/PCAPanel.java @@ -32,8 +32,10 @@ import java.awt.print.PrinterException; import java.awt.print.PrinterJob; import javax.swing.ButtonGroup; +import javax.swing.JLabel; import javax.swing.JMenuItem; import javax.swing.JRadioButtonMenuItem; +import javax.swing.SwingConstants; import javax.swing.event.InternalFrameAdapter; import javax.swing.event.InternalFrameEvent; @@ -129,6 +131,14 @@ public class PCAPanel extends GPCAPanel PaintRefresher.Register(this, av.getSequenceSetId()); setRotatableCanvas(new RotatableCanvas(alignPanel)); + + if(params.getSecondaryStructureSource()!=null ) { + // Initialize and set subtitle text + JLabel subtitleLabel = new JLabel(" Secondary Structure Provider : " + + params.getSecondaryStructureSource(), SwingConstants.LEFT); + this.getContentPane().add(subtitleLabel, BorderLayout.NORTH); + + } this.getContentPane().add(getRotatableCanvas(), BorderLayout.CENTER); addKeyListener(getRotatableCanvas()); diff --git a/src/jalview/gui/PopupMenu.java b/src/jalview/gui/PopupMenu.java index d2c00eb..d1eeb73 100644 --- a/src/jalview/gui/PopupMenu.java +++ b/src/jalview/gui/PopupMenu.java @@ -1741,10 +1741,16 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener AlignmentUtils.addReferenceAnnotations(candidates, alignment, null); if(AlignmentUtils.isSSAnnotationPresent(candidates)) { + restartSSConsensusWorker(); + ap.validateAnnotationDimensions(true); + ap.fontChanged(); + ap.av.alignmentChanged(ap); + ap.adjustAnnotationHeight(); + restartSSConsensusWorker(); + //ap.alignFrame.getViewport().getCalcManager().restartWorkers(); } - refresh(); } diff --git a/src/jalview/gui/TreePanel.java b/src/jalview/gui/TreePanel.java index f708c48..a421850 100755 --- a/src/jalview/gui/TreePanel.java +++ b/src/jalview/gui/TreePanel.java @@ -20,6 +20,7 @@ */ package jalview.gui; +import java.awt.BorderLayout; import java.awt.Font; import java.awt.Graphics; import java.awt.event.ActionEvent; @@ -35,8 +36,11 @@ import java.util.List; import java.util.Locale; import javax.swing.ButtonGroup; +import javax.swing.JLabel; import javax.swing.JMenuItem; +import javax.swing.JPanel; import javax.swing.JRadioButtonMenuItem; +import javax.swing.SwingConstants; import javax.swing.event.InternalFrameAdapter; import javax.swing.event.InternalFrameEvent; @@ -96,6 +100,10 @@ public class TreePanel extends GTreePanel TreeModel tree; private AlignViewport av; + + + // New JLabel for subtitle + private JLabel subtitleLabel; /** * Creates a new TreePanel object. @@ -181,6 +189,20 @@ public class TreePanel extends GTreePanel treeCanvas = new TreeCanvas(this, ap, scrollPane); scrollPane.setViewportView(treeCanvas); + + if(this.similarityParams.getSecondaryStructureSource()!=null ) { + + // Initialize the subtitle label + subtitleLabel = new JLabel(" Secondary Structure Provider : " + + this.similarityParams.getSecondaryStructureSource(), SwingConstants.LEFT); + + // Create a new panel to hold the label and treeCanvas + JPanel panel = new JPanel(new BorderLayout()); + panel.add(subtitleLabel, BorderLayout.NORTH); + panel.add(scrollPane, BorderLayout.CENTER); + + this.add(panel); + } if (columnWise) { diff --git a/src/jalview/jbgui/GAlignFrame.java b/src/jalview/jbgui/GAlignFrame.java index 3c9f642..f02f204 100755 --- a/src/jalview/jbgui/GAlignFrame.java +++ b/src/jalview/jbgui/GAlignFrame.java @@ -22,8 +22,8 @@ package jalview.jbgui; import java.awt.BorderLayout; import java.awt.Color; +import java.awt.Component; import java.awt.GridLayout; -import java.awt.Menu; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.FocusAdapter; @@ -56,13 +56,10 @@ 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; @@ -199,10 +196,6 @@ public class GAlignFrame extends JInternalFrame protected JMenuItem expandViews = new JMenuItem(); - protected JCheckBoxMenuItem threeDStructure = new JCheckBoxMenuItem(); - - protected JCheckBoxMenuItem jPred = new JCheckBoxMenuItem(); - protected JCheckBoxMenuItem showGroupConsensus = new JCheckBoxMenuItem(); protected JCheckBoxMenuItem showGroupConservation = new JCheckBoxMenuItem(); @@ -1802,42 +1795,8 @@ 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(); - } - }); + ButtonGroup ssButtonGroup = new ButtonGroup(); JMenu tooltipSettingsMenu = new JMenu( MessageManager.getString("label.sequence_id_tooltip")); @@ -1847,12 +1806,47 @@ public class GAlignFrame extends JInternalFrame JMenu showSS = new JMenu( MessageManager.getString("label.show_secondary_structure")); - showSS.addMouseListener(new MouseAdapter() { + JRadioButtonMenuItem radioButtonAllSS = new JRadioButtonMenuItem(MessageManager.getString("option.ss_providers_all")); + radioButtonAllSS.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + showSS_actionPerformed(MessageManager.getString("option.ss_providers_all")); + // 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) { + showSS_actionPerformed(MessageManager.getString("option.ss_providers_none")); + // 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 + updateShowSecondaryStructureMenu(showSS, ssButtonGroup); // Update radio buttons every time the menu is clicked } }); @@ -2599,10 +2593,6 @@ public class GAlignFrame extends JInternalFrame } - protected void jpred_actionPerformed(ActionEvent e) - { - } - protected void scaleAbove_actionPerformed(ActionEvent e) { } @@ -2873,13 +2863,14 @@ public class GAlignFrame extends JInternalFrame return null; } - protected void updateShowSSRadioButtons(JMenu showSS, - ButtonGroup ssButtonGroup) + protected void showSS_actionPerformed(String ssSourceSelection) { // TODO Auto-generated method stub + } - protected void showSS_actionPerformed(String ssSourceSelection) + protected void updateShowSecondaryStructureMenu(JMenu showSS, + ButtonGroup ssButtonGroup) { // TODO Auto-generated method stub diff --git a/src/jalview/project/Jalview2XML.java b/src/jalview/project/Jalview2XML.java index 2f4052a..e620c1c 100644 --- a/src/jalview/project/Jalview2XML.java +++ b/src/jalview/project/Jalview2XML.java @@ -5310,7 +5310,7 @@ public class Jalview2XML viewport.getResidueShading() .setConsensus(viewport.getSequenceConsensusHash()); viewport.getResidueShading() - .setSsConsensus(viewport.getSequenceSSConsensusHash()); + .setSSConsensusProfileMap(viewport.getSequenceSSConsensusHash()); if (safeBoolean(view.isConservationSelected()) && cs != null) { viewport.getResidueShading() diff --git a/src/jalview/renderer/AnnotationRenderer.java b/src/jalview/renderer/AnnotationRenderer.java index 4e9f669..2b73002 100644 --- a/src/jalview/renderer/AnnotationRenderer.java +++ b/src/jalview/renderer/AnnotationRenderer.java @@ -33,6 +33,8 @@ import java.awt.geom.AffineTransform; import java.awt.image.ImageObserver; import java.util.BitSet; import java.util.Hashtable; +import java.util.List; +import java.util.Map; import org.jfree.graphics2d.svg.SVGGraphics2D; import org.jibble.epsgraphics.EpsGraphics2D; @@ -91,7 +93,7 @@ public class AnnotationRenderer private ProfilesI hconsensus; - private ProfilesI hSSconsensus; + private Map hSSconsensus; private Hashtable[] complementConsensus; @@ -432,16 +434,21 @@ public class AnnotationRenderer } } - else if(aa.autoCalculated && aa.label.startsWith(MessageManager.getString("label.ssconsensus_label"))) + if(aa.autoCalculated && aa.label.startsWith(MessageManager.getString("label.ssconsensus_label"))) { - return AAFrequency.extractProfile( - hSSconsensus.get(column), - av_ignoreGapsConsensus); + if(hSSconsensus!=null) { + for (String source : hSSconsensus.keySet()) { + if(aa.description.startsWith(source)) { + + return AAFrequency.extractProfile( + hSSconsensus.get(source).get(column), + av_ignoreGapsConsensus); + } + } + } } - else - { if (aa.autoCalculated && aa.label.startsWith("StrucConsensus")) { // TODO implement group structure consensus @@ -463,7 +470,7 @@ public class AnnotationRenderer av_ignoreGapsConsensus); } } - } + return null; } @@ -529,7 +536,7 @@ public class AnnotationRenderer .getAlignmentStrucConsensusAnnotation(); final AlignmentAnnotation complementConsensusAnnot = av .getComplementConsensusAnnotation(); - final AlignmentAnnotation ssConsensusAnnot = av + final List ssConsensusAnnot = av .getAlignmentSecondaryStructureConsensusAnnotation(); BitSet graphGroupDrawn = new BitSet(); @@ -557,7 +564,7 @@ public class AnnotationRenderer normaliseProfile = row.groupRef.isNormaliseSequenceLogo(); } else if (row == consensusAnnot || row == structConsensusAnnot - || row == complementConsensusAnnot || row == ssConsensusAnnot) + || row == complementConsensusAnnot || (ssConsensusAnnot!=null && ssConsensusAnnot.contains(row))) { renderHistogram = av_renderHistogram; renderProfile = av_renderProfile; @@ -1619,7 +1626,7 @@ public class AnnotationRenderer colour = profcolour.findColour(codonTranslation.charAt(0), column, null); } - if(_aa.label == MessageManager.getString("label.ssconsensus_label")) { + if(_aa.label.startsWith(MessageManager.getString("label.ssconsensus_label"))) { colour = AlignmentUtils.getSecondaryStructureAnnotationColour(dc[0]); } else diff --git a/src/jalview/renderer/ResidueShader.java b/src/jalview/renderer/ResidueShader.java index b914c65..9231901 100644 --- a/src/jalview/renderer/ResidueShader.java +++ b/src/jalview/renderer/ResidueShader.java @@ -63,20 +63,10 @@ public class ResidueShader implements ResidueShaderI private ProfilesI consensus; /* - * the consensus data for each column + * the ss consensus data for each column for each source */ - private ProfilesI ssConsensus; - - public ProfilesI getSsConsensus() - { - return ssConsensus; - } - - public void setSsConsensus(ProfilesI ssConsensus) - { - this.ssConsensus = ssConsensus; - } + private Map ssConsensusProfileMap; /* * if true, apply shading of colour by conservation @@ -144,7 +134,7 @@ public class ResidueShader implements ResidueShaderI this.conservationIncrement = rs.conservationIncrement; this.ignoreGaps = rs.ignoreGaps; this.pidThreshold = rs.pidThreshold; - this.ssConsensus = rs.ssConsensus; + this.ssConsensusProfileMap = rs.ssConsensusProfileMap; } /** @@ -281,7 +271,7 @@ public class ResidueShader implements ResidueShaderI } @Override - public Color findSSColour(char symbol, int position, SequenceI seq) + public Color findSSColour(char symbol, int position, SequenceI seq, String source) { if (colourScheme == null) { @@ -291,7 +281,7 @@ public class ResidueShader implements ResidueShaderI /* * get 'base' colour */ - ProfileI profile = ssConsensus == null ? null : ssConsensus.get(position); + ProfileI profile = ssConsensusProfileMap.get(source) == null ? null : ssConsensusProfileMap.get(source).get(position); String modalSS = profile == null ? null : profile.getModalSS(); float pid = profile == null ? 0f @@ -463,4 +453,14 @@ public class ResidueShader implements ResidueShaderI { colourScheme = cs; } + + public Map getSSConsensusProfileMap() + { + return ssConsensusProfileMap; + } + + public void setSSConsensusProfileMap(Map ssConsensusProfileMap) + { + this.ssConsensusProfileMap = ssConsensusProfileMap; + } } diff --git a/src/jalview/renderer/ResidueShaderI.java b/src/jalview/renderer/ResidueShaderI.java index 0412d21..42f4e2e 100644 --- a/src/jalview/renderer/ResidueShaderI.java +++ b/src/jalview/renderer/ResidueShaderI.java @@ -35,7 +35,7 @@ public interface ResidueShaderI public abstract void setConsensus(ProfilesI cons); - public abstract void setSsConsensus(ProfilesI cons); + public abstract void setSSConsensusProfileMap(Map ssConsensusProfileMap); public abstract boolean conservationApplied(); @@ -84,6 +84,7 @@ public interface ResidueShaderI public abstract void setColourScheme(ColourSchemeI cs); - Color findSSColour(char symbol, int position, SequenceI seq); + Color findSSColour(char symbol, int position, SequenceI seq, + String source); } \ No newline at end of file diff --git a/src/jalview/viewmodel/AlignmentViewport.java b/src/jalview/viewmodel/AlignmentViewport.java index 6ad2f20..63bbe93 100644 --- a/src/jalview/viewmodel/AlignmentViewport.java +++ b/src/jalview/viewmodel/AlignmentViewport.java @@ -25,6 +25,7 @@ import java.beans.PropertyChangeSupport; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.BitSet; +import java.util.Collections; import java.util.Deque; import java.util.HashMap; import java.util.Hashtable; @@ -33,6 +34,7 @@ import java.util.List; import java.util.Map; import jalview.analysis.AnnotationSorter.SequenceAnnotationOrder; +import jalview.analysis.AlignmentUtils; import jalview.analysis.Conservation; import jalview.analysis.TreeModel; import jalview.api.AlignCalcManagerI; @@ -699,7 +701,9 @@ public abstract class AlignmentViewport protected AlignmentAnnotation consensus; - protected AlignmentAnnotation secondaryStructureConsensus; + protected List secondaryStructureConsensus; + + protected List secondaryStructureSources; protected AlignmentAnnotation complementConsensus; @@ -722,7 +726,7 @@ public abstract class AlignmentViewport */ protected ProfilesI hconsensus = null; - protected ProfilesI hSSConsensus = null; + protected Map hSSConsensusProfileMap = null; @@ -744,6 +748,32 @@ public abstract class AlignmentViewport { hconservation = cons; } + + @Override + public List getSecondaryStructureSources() + { + return secondaryStructureSources; + } + + @Override + public void setSecondaryStructureSources( + List secondaryStructureSources) + { + this.secondaryStructureSources = secondaryStructureSources; + } + + protected void setSecondaryStructureSources(AlignmentAnnotation[] aa) + { + List sources = null; + + if(aa!=null) { + sources = AlignmentUtils.extractSSSourceInAlignmentAnnotation(aa); + if(sources != null) { + sources.add(0,MessageManager.getString("option.ss_providers_all")); + setSecondaryStructureSources(sources); + } + } + } /** * percentage gaps allowed in a column before all amino acid properties should @@ -764,11 +794,11 @@ public abstract class AlignmentViewport } @Override - public void setSequenceSSConsensusHash(ProfilesI hSSConsensus) + public void setSequenceSSConsensusHash(Map hSSConsensusProfileMap) { - this.hSSConsensus = hSSConsensus; + this.hSSConsensusProfileMap = hSSConsensusProfileMap; } - + @Override public void setComplementConsensusHash( Hashtable[] hconsensus) @@ -781,12 +811,13 @@ public abstract class AlignmentViewport { return hconsensus; } - + @Override - public ProfilesI getSequenceSSConsensusHash() + public Map getSequenceSSConsensusHash() { - return hSSConsensus; + return hSSConsensusProfileMap; } + @Override public Hashtable[] getComplementConsensusHash() @@ -828,7 +859,7 @@ public abstract class AlignmentViewport @Override - public AlignmentAnnotation getAlignmentSecondaryStructureConsensusAnnotation() + public List getAlignmentSecondaryStructureConsensusAnnotation() { return secondaryStructureConsensus; } @@ -930,7 +961,7 @@ public abstract class AlignmentViewport /** - * trigger update of consensus annotation + * trigger update of Secondary Structure consensus annotation */ public void updateSecondaryStructureConsensus(final AlignmentViewPanel ap) { @@ -939,11 +970,42 @@ public abstract class AlignmentViewport { return; } + if (secondaryStructureConsensus.size() != secondaryStructureSources.size()) { + + for(String source : secondaryStructureSources) { + 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)); } + ap.adjustAnnotationHeight(); + + } // --------START Structure Conservation @@ -2042,10 +2104,21 @@ public abstract class AlignmentViewport 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 secondaryStructureSources = getSecondaryStructureSources(); + + if(secondaryStructureSources!=null) { + + secondaryStructureConsensus = new ArrayList(); + 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); @@ -2106,14 +2179,20 @@ public abstract class AlignmentViewport } } - private void initSSConsensus(AlignmentAnnotation aa) + private void initSSConsensus(List secondaryStructureConsensuses) { - aa.hasText = true; - aa.autoCalculated = true; - - if (showSSConsensus) - { - alignment.addAnnotation(aa); + if(secondaryStructureConsensuses == null) { + return; + } + for(AlignmentAnnotation aa : secondaryStructureConsensuses) { + aa.hasText = true; + aa.autoCalculated = true; + + if (showSSConsensus) + { + alignment.addAnnotation(aa); + } + } } @@ -2317,7 +2396,16 @@ public abstract class AlignmentViewport { updateCalcs = true; alignment.addAnnotation(sg.getConsensus(), 0); - alignment.addAnnotation(sg.getSSConsensus(), 0); + + List secondaryStructureSources = getSecondaryStructureSources(); + if(secondaryStructureSources !=null) { + List ssAa = sg.getSSConsensus(secondaryStructureSources); + if(ssAa != null) { + for(AlignmentAnnotation aa : ssAa) { + alignment.addAnnotation(aa, 0); + } + } + } } // refresh the annotation rows if (updateCalcs) @@ -3108,6 +3196,7 @@ public abstract class AlignmentViewport return sq; } + //to do jal-4386 public SequenceI getSSConsensusSeq() { if (secondaryStructureConsensus == null) @@ -3119,23 +3208,23 @@ public abstract class AlignmentViewport return null; } StringBuffer seqs = new StringBuffer(); - for (int i = 0; i < secondaryStructureConsensus.annotations.length; i++) - { - Annotation annotation = secondaryStructureConsensus.annotations[i]; - if (annotation != null) - { - String description = annotation.description; - if (description != null && description.startsWith("[")) - { - // consensus is a tie - just pick the first one - seqs.append(description.charAt(1)); - } - else - { - seqs.append(annotation.displayCharacter); - } - } - } +// for (int i = 0; i < secondaryStructureConsensus.annotations.length; i++) +// { +// Annotation annotation = secondaryStructureConsensus.annotations[i]; +// if (annotation != null) +// { +// String description = annotation.description; +// if (description != null && description.startsWith("[")) +// { +// // consensus is a tie - just pick the first one +// seqs.append(description.charAt(1)); +// } +// else +// { +// seqs.append(annotation.displayCharacter); +// } +// } +// } SequenceI sq = new Sequence("Sec Str Consensus", seqs.toString()); sq.setDescription("Percentage Identity Sec Str Consensus " diff --git a/src/jalview/workers/SecondaryStructureConsensusThread.java b/src/jalview/workers/SecondaryStructureConsensusThread.java index 04cefe5..282b337 100644 --- a/src/jalview/workers/SecondaryStructureConsensusThread.java +++ b/src/jalview/workers/SecondaryStructureConsensusThread.java @@ -20,7 +20,13 @@ */ package jalview.workers; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + import jalview.analysis.AAFrequency; +import jalview.analysis.AlignmentUtils; import jalview.api.AlignViewportI; import jalview.api.AlignmentViewPanel; import jalview.datamodel.AlignmentAnnotation; @@ -29,6 +35,7 @@ import jalview.datamodel.Annotation; import jalview.datamodel.ProfilesI; import jalview.datamodel.SequenceI; import jalview.renderer.ResidueShaderI; +import jalview.util.MessageManager; public class SecondaryStructureConsensusThread extends AlignCalcWorker { @@ -49,7 +56,7 @@ public class SecondaryStructureConsensusThread extends AlignCalcWorker // long started = System.currentTimeMillis(); try { - AlignmentAnnotation ssConsensus = getSSConsensusAnnotation(); + List ssConsensus = getSSConsensusAnnotation(); AlignmentAnnotation gap = getGapAnnotation(); if ((ssConsensus == null && gap == null) || calcMan.isPending(this)) { @@ -84,7 +91,8 @@ public class SecondaryStructureConsensusThread extends AlignCalcWorker calcMan.workerComplete(this); return; } - + + setSecondaryStructureSources(); eraseSSConsensus(aWidth); computeSSConsensus(alignment); updateResultAnnotation(true); @@ -115,10 +123,12 @@ public class SecondaryStructureConsensusThread extends AlignCalcWorker */ protected void eraseSSConsensus(int aWidth) { - AlignmentAnnotation ssConsensus = getSSConsensusAnnotation(); - if (ssConsensus != null) - { - ssConsensus.annotations = new Annotation[aWidth]; + List ssConsensuses = getSSConsensusAnnotation(); + for(AlignmentAnnotation ssConsensus : ssConsensuses) { + if (ssConsensus != null) + { + ssConsensus.annotations = new Annotation[aWidth]; + } } AlignmentAnnotation gap = getGapAnnotation(); if (gap != null) @@ -135,11 +145,17 @@ public class SecondaryStructureConsensusThread extends AlignCalcWorker SequenceI[] aseqs = getSequences(); int width = alignment.getWidth(); - ProfilesI hSSConsensus = AAFrequency.calculateSS(aseqs, width, 0, width, - true); + Map hSSConsensusProfileMap = new HashMap(); + List ssSources = getSecondaryStructureSources(); + for(String ssSource : ssSources) { + ProfilesI hSSConsensus = AAFrequency.calculateSS(aseqs, width, 0, width, + true, ssSource); + hSSConsensusProfileMap.put(ssSource, hSSConsensus); + } + - alignViewport.setSequenceSSConsensusHash(hSSConsensus); - setColourSchemeConsensus(hSSConsensus); + alignViewport.setSequenceSSConsensusHash(hSSConsensusProfileMap); + setColourSchemeConsensus(hSSConsensusProfileMap); } /** @@ -153,12 +169,12 @@ public class SecondaryStructureConsensusThread extends AlignCalcWorker /** * @param hconsensus */ - protected void setColourSchemeConsensus(ProfilesI hSSconsensus) + protected void setColourSchemeConsensus(Map ssConsensusProfileMap) { ResidueShaderI cs = alignViewport.getResidueShading(); if (cs != null) { - cs.setSsConsensus(hSSconsensus); + cs.setSSConsensusProfileMap(ssConsensusProfileMap); } } @@ -167,10 +183,33 @@ public class SecondaryStructureConsensusThread extends AlignCalcWorker * * @return */ - protected AlignmentAnnotation getSSConsensusAnnotation() + protected List getSSConsensusAnnotation() { return alignViewport.getAlignmentSecondaryStructureConsensusAnnotation(); } + + /** + * Get the Consensus annotation for the alignment + * + * @return + */ + protected void setSecondaryStructureSources() + { + List sources = null; + AlignmentAnnotation[] aa = alignViewport.getAlignment().getAlignmentAnnotation(); + if(aa!=null) { + sources = AlignmentUtils.extractSSSourceInAlignmentAnnotation(aa); + if(sources != null) { + sources.add(0, MessageManager.getString("option.ss_providers_all")); + alignViewport.setSecondaryStructureSources(sources); + } + } + } + + protected List getSecondaryStructureSources() + { + return alignViewport.getSecondaryStructureSources(); + } /** * Get the Gap annotation for the alignment @@ -194,18 +233,30 @@ public class SecondaryStructureConsensusThread extends AlignCalcWorker public void updateResultAnnotation(boolean immediate) { - AlignmentAnnotation ssConsensus = getSSConsensusAnnotation(); - ProfilesI hSSConsensus = (ProfilesI) getViewportSSConsensus(); + List ssConsensuses = getSSConsensusAnnotation(); + Map ssConsensusProfileMap = getViewportSSConsensus(); + for(AlignmentAnnotation ssConsensus : ssConsensuses) { + ProfilesI ssConsensusProfile = null; + for(String source: ssConsensusProfileMap.keySet()) { + if(ssConsensus.description.startsWith(source)) { + ssConsensusProfile = ssConsensusProfileMap.get(source); + break; + } + } + if(ssConsensusProfile==null) { + continue; + } if (immediate || !calcMan.isWorking(this) && ssConsensus != null - && hSSConsensus != null) + && ssConsensusProfile != null) { - deriveSSConsensus(ssConsensus, hSSConsensus); + deriveSSConsensus(ssConsensus, ssConsensusProfile); AlignmentAnnotation gap = getGapAnnotation(); if (gap != null) { - deriveGap(gap, hSSConsensus); + deriveGap(gap, ssConsensusProfile); } } + } } /** @@ -217,12 +268,12 @@ public class SecondaryStructureConsensusThread extends AlignCalcWorker * @param hconsensus * the computed consensus data */ - protected void deriveSSConsensus(AlignmentAnnotation ssConsensusAnnotation, + protected void deriveSSConsensus(AlignmentAnnotation ssConsensus, ProfilesI hSSConsensus) { long nseq = getSequences().length; - AAFrequency.completeSSConsensus(ssConsensusAnnotation, hSSConsensus, + AAFrequency.completeSSConsensus(ssConsensus, hSSConsensus, hSSConsensus.getStartColumn(), hSSConsensus.getEndColumn() + 1, alignViewport.isIgnoreGapsConsensus(), alignViewport.isShowSequenceLogo(), nseq); @@ -250,7 +301,7 @@ public class SecondaryStructureConsensusThread extends AlignCalcWorker * * @return */ - protected Object getViewportSSConsensus() + protected Map getViewportSSConsensus() { // TODO convert ComplementConsensusThread to use Profile return alignViewport.getSequenceSSConsensusHash();