JAL-4435 Reformatting tree node labels and tree sub group names
authorRenia Correya <rcorreya001@dundee.ac.uk>
Tue, 8 Oct 2024 11:22:06 +0000 (12:22 +0100)
committerRenia Correya <rcorreya001@dundee.ac.uk>
Tue, 8 Oct 2024 11:22:06 +0000 (12:22 +0100)
src/jalview/analysis/AlignmentUtils.java
src/jalview/analysis/scoremodels/SecondaryStructureDistanceModel.java
src/jalview/gui/TreeCanvas.java
src/jalview/util/Constants.java

index 31670fd..41e491c 100644 (file)
@@ -38,6 +38,7 @@ import java.util.Set;
 import java.util.SortedMap;
 import java.util.TreeMap;
 import java.util.Vector;
+import java.util.stream.Collectors;
 
 import jalview.api.AlignCalcWorkerI;
 import jalview.bin.Console;
@@ -3202,4 +3203,30 @@ public class AlignmentUtils
     }
     return false;
   }
-}
+  
+  // Method to get the key for a given provider value
+  public static String getProviderKey(String providerValue) {
+      for (Map.Entry<String, String> entry : Constants.STRUCTURE_PROVIDERS.entrySet()) {
+          if (entry.getValue().equals(providerValue)) {
+              return entry.getKey();  // Return the key (abbreviation) for the matching provider value
+          }
+      }
+      return null;  // Return null if no match is found
+  }
+  
+  public static String reduceLabelLength(String label) {
+    // Split the input by " | "
+    String[] parts = label.split(" \\| ");
+    
+    // Map the full names to their abbreviations
+    String reducedLabel = Arrays.stream(parts)
+            .map(fullName -> Constants.STRUCTURE_PROVIDERS.entrySet().stream()
+                    .filter(entry -> entry.getValue().equals(fullName))
+                    .map(Map.Entry::getKey)
+                    .findFirst()
+                    .orElse(fullName)) // Use fullName if no abbreviation is found
+            .collect(Collectors.joining(" | "));
+    
+    return reducedLabel; // Return the reduced label if abbreviations were applied
+  }
+}
\ No newline at end of file
index 6ed94b2..52a60d1 100644 (file)
@@ -130,7 +130,8 @@ public class SecondaryStructureDistanceModel extends DistanceScoreModel
         newSequences.add(alSeq);
         if (alSeq != null)
         {
-          labels.add("No Secondary Structure");
+          //labels.add("No Secondary Structure");
+          labels.add(Constants.STRUCTURE_PROVIDERS.get("None"));
         }
         SeqCigar newSeqCigar = scig; // new SeqCigar(scig);
         newCigs.add(newSeqCigar);
@@ -142,8 +143,9 @@ public class SecondaryStructureDistanceModel extends DistanceScoreModel
         {
           if (alSeq != null)
           {
-            labels.add(AlignmentUtils
-                    .extractSSSourceFromAnnotationDescription(ssec.get(i)));
+            String provider = AlignmentUtils.extractSSSourceFromAnnotationDescription(ssec.get(i));
+            //String providerAbbreviation = AlignmentUtils.getProviderKey(provider);
+            labels.add(provider);
           }
           // newSequences.add(seq);
           newSequences.add(alSeq);
index 08ecba6..49b569a 100755 (executable)
@@ -51,6 +51,7 @@ import javax.swing.JScrollPane;
 import javax.swing.SwingUtilities;
 import javax.swing.ToolTipManager;
 
+import jalview.analysis.AlignmentUtils;
 import jalview.analysis.Conservation;
 import jalview.analysis.TreeModel;
 import jalview.api.AlignViewportI;
@@ -112,6 +113,8 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
   int offy;
 
   private float threshold;
+  
+  int labelLengthThreshold = 4;
 
   String longestName;
 
@@ -127,6 +130,9 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
   BinaryNode highlightNode;
 
   boolean applyToAllViews = false;
+  
+  //Map to store label positions (BinaryNode -> List of bounding rectangles for the label)
+  private Map<BinaryNode, List<Rectangle>> labelBoundsMap = new HashMap<>();
 
   /**
    * Creates a new TreeCanvas object.
@@ -285,7 +291,7 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
    */
   public void drawNode(Graphics g, BinaryNode node, double chunk,
           double wscale, int width, int offx, int offy)
-  {
+  {    
     if (node == null)
     {
       return;
@@ -441,10 +447,41 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
       }
       if (node.hasLabel())
       {
-        nodeLabel = node.getLabel() + " " + nodeLabel;
+        String label = node.getLabel();
+        
+        if(label.length() > labelLengthThreshold) {
+          
+          //label = AlignmentUtils.reduceLabelLength(label);
+        }
+        
+        nodeLabel = label + " | " + nodeLabel;
+
+        // Split the nodeLabel by "|"
+        String[] lines = nodeLabel.split("\\|");
+
+        // Iterate over the lines and draw each line separately
+        String longestLabelString = "";
+        int i = 0;
+        for (i = 0; i < lines.length; i++) {
+            g.drawString(lines[i].trim(), xstart + 2, ypos - 2 - (i * fm.getHeight()));
+            if(longestLabelString.length() < lines[i].trim().length()) {
+              longestLabelString = lines[i].trim();
+            }
+        }
+        
+        int labelWidth = fm.stringWidth(longestLabelString);
+        int labelHeight = fm.getHeight() * (i-1);
+
+        // Calculate the bounding box of the string
+        int xLabelPos = xstart + 2;
+        int yLabelPos = ypos - 2;
+        Rectangle labelBounds = new Rectangle(xLabelPos, yLabelPos - labelHeight, labelWidth, labelHeight);
+
+        // Add the bounding box to the map for this node (list allows multiple bounding boxes)
+        labelBoundsMap.computeIfAbsent(node, k -> new ArrayList<>()).add(labelBounds);
       }
 
-      if (!nodeLabel.equals(""))
+      else if (!nodeLabel.equals(""))
       {
         g.drawString(nodeLabel, xstart + 2, ypos - 2);
       }
@@ -936,6 +973,10 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
     av.setCurrentTree(tree);
 
     Object ob = findElement(evt.getX(), evt.getY());
+    
+    // Get mouse coordinates
+    int mouseX = evt.getX();
+    int mouseY = evt.getY();
 
     if (ob instanceof BinaryNode)
     {
@@ -946,13 +987,35 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
 
     }
     else
-    {
+    {     
+      
       if (highlightNode != null)
       {
         highlightNode = null;
         setToolTipText(null);
         repaint();
       }
+      
+      // Iterate through the map of label bounding boxes
+      for (Map.Entry<BinaryNode, List<Rectangle>> entry : labelBoundsMap.entrySet()) {
+          BinaryNode node = entry.getKey();
+          List<Rectangle> boundsList = entry.getValue();
+
+          // Check each bounding box for this node
+          for (Rectangle labelBounds : boundsList) {
+              if (labelBounds.contains(mouseX, mouseY)) {
+                  // Show tooltip for this node's label
+                  String nodeLabel = node.getDisplayName();
+                  this.setToolTipText(nodeLabel);
+                  repaint();
+                  return; // Exit once we find a matching label
+              }
+          }
+      }
+      // Clear tooltip if no label is hovered
+      setToolTipText(null);
+      repaint();
+
     }
   }
 
@@ -1075,7 +1138,7 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
       gatherLabelsTo(groups.get(i), l);
       if (!tp.isColumnWise())
       {
-        createSeqGroupFor(aps, l, col);
+        createSeqGroupFor(aps, l, col, groups.get(i).getLabel());
       }
       else
       {
@@ -1137,7 +1200,12 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
         sb.append(" | ");
       }
       first = false;
+//      if(labelsForNode.size()>1) {
+//        String providerAbbreviation = AlignmentUtils.getProviderKey(label);
+//        sb.append(providerAbbreviation);
+//      }     
       sb.append(label);
+      
     }
     binaryNode.setLabel(sb.toString());
   }
@@ -1299,7 +1367,7 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
   }
 
   public void createSeqGroupFor(AlignmentPanel[] aps, Vector<BinaryNode> l,
-          Color col)
+          Color col, String label)
   {
 
     Vector<SequenceI> sequences = new Vector<>();
@@ -1317,8 +1385,14 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
     ColourSchemeI cs = null;
     SequenceGroup _sg = new SequenceGroup(sequences, null, cs, true, true,
             false, 0, av.getAlignment().getWidth() - 1);
-
-    _sg.setName("JTreeGroup:" + _sg.hashCode());
+    
+    if(label != null && !label.isEmpty()) {
+      label = AlignmentUtils.reduceLabelLength(label);
+      _sg.setName("JTreeGroup:" + label);
+    }
+    else {
+      _sg.setName("JTreeGroup:" + _sg.hashCode());
+    }
     _sg.setIdColour(col);
 
     for (int a = 0; a < aps.length; a++)
index 5f01895..b8afeeb 100644 (file)
@@ -59,4 +59,16 @@ public class Constants
 
   // Secondary structure consensus label
   public static final String SECONDARY_STRUCTURE_CONSENSUS_LABEL = "Secondary Structure Consensus";
+  
+  //A map that stores abbreviations of structure providers as keys and their full names as values.
+  public static final Map<String, String> STRUCTURE_PROVIDERS = new HashMap<>();
+
+  static {
+      STRUCTURE_PROVIDERS.put("None", "No Secondary Structure");
+      STRUCTURE_PROVIDERS.put("AF", "AlphaFold DB");
+      STRUCTURE_PROVIDERS.put("SM", "SWISS-MODEL");
+      STRUCTURE_PROVIDERS.put("PDB", "PDB");
+      STRUCTURE_PROVIDERS.put("JP", "JPred");
+      STRUCTURE_PROVIDERS.put("AFill", "AlphaFill");
+  }
 }