Repository: enthought/chaco

Issue:
issue with LegendHighlighter tool
Hello,

I have the following issue when I run the CME below:

if 'name' (line 52) is set to a string with only one character, LegendHighlighter does not work (does not highlight curve), whereas it runs without problem in any other case.

```python
#!/usr/bin/env python
"""
Draws several overlapping line plots like simple_line.py, but uses a separate
Y range for j1 compared to the other 3 curves. Also has a second Y-axis on the
right hand side for j1. Demonstrates use of the BroadcasterTool.

Interactive behavior:
* Left-drag pans the plot.
* Right-click and dragging on the legend allows you to reposition the legend.
* Double-clicking on line or scatter plots brings up a traits editor for the
  plot.
"""

# Major library imports
from numpy import arange, cos

# Enthought library imports
from enable.api import Component, ComponentEditor
from traits.api import HasTraits, Instance
from traitsui.api import Item, VGroup, View

# Chaco imports
from chaco.api import (
    create_line_plot,
    add_default_axes,
    add_default_grids,
    OverlayPlotContainer,
    Legend,
)
from chaco.tools.api import (
    LegendHighlighter,
    TraitsTool,
)

# =============================================================================
# Create the Chaco plot.
# =============================================================================


def _create_plot_component():

    container = OverlayPlotContainer(
        padding=60, fill_padding=True, use_backbuffer=True, border_visible=True
    )

    # Create the initial X-series of data
    numpoints = 100
    low = -5
    high = 15.0
    x = arange(low, high + 0.001, (high - low) / numpoints)

    name = 'a'

    # Plot some bessel functions
    plots = {}
    y = cos(x)
    plot = create_line_plot((x, y))
    container.add(plot)
    plots[name] = plot
    add_default_grids(plot)
    add_default_axes(plot)
    # Create a legend, with tools to move it around and highlight renderers:
    legend = Legend(component=container, padding=10, align="ur")
    legend.tools.append(LegendHighlighter(legend))
    container.overlays.append(legend)
    # Set the list of plots on the legend
    legend.plots = plots

    # Add the traits inspector tool to the container
    container.tools.append(TraitsTool(container))

    return container


# =============================================================================
# Attributes to use for the plot view.
size = (800, 700)

# =============================================================================
# Demo class that is used by the demo.py application.
# =============================================================================


class Demo(HasTraits):
    plot = Instance(Component)

    traits_view = View(
        VGroup(
            Item("plot", editor=ComponentEditor(size=size), show_label=False)
        ),
        resizable=True,
        width=size[0],
        height=size[1],
    )

    def _plot_default(self):
        return _create_plot_component()


demo = Demo()

if __name__ == "__main__":
    demo.configure_traits()
```

Any help would be appreciated.

Thanks in advance.

Regards

*Python 3.9.2, Debian 11 x86_64, code source from github*



Discussion:
Thanks for the report. I can replicate the issue.

Resolving patch:
diff --git a/chaco/overlays/legend.py b/chaco/overlays/legend.py
--- a/chaco/overlays/legend.py
+++ b/chaco/overlays/legend.py
@@ -427,7 +427,7 @@ def get_preferred_size(self):
         # We need a dummy GC in order to get font metrics
         dummy_gc = font_metrics_provider()
         label_sizes = array(
-            [label.get_width_height(dummy_gc) for label in labels]
+            [label.get_bounding_box(dummy_gc) for label in labels]
         )
 
         if len(label_sizes) > 0:
@@ -465,8 +465,12 @@ def get_preferred_size(self):
 
     def get_label_at(self, x, y):
         """ Returns the label object at (x,y) """
+        icon_space = array([
+            self.icon_spacing + self.icon_bounds[0],
+            self.icon_bounds[1],
+        ])
         for i, pos in enumerate(self._cached_label_positions):
-            size = self._cached_label_sizes[i]
+            size = self._cached_label_sizes[i] + icon_space
             corner = pos + size
             if (pos[0] <= x <= corner[0]) and (pos[1] <= y <= corner[1]):
                 return self._cached_labels[i]
diff --git a/chaco/tools/legend_highlighter.py b/chaco/tools/legend_highlighter.py
--- a/chaco/tools/legend_highlighter.py
+++ b/chaco/tools/legend_highlighter.py
@@ -30,10 +30,7 @@ def get_hit_plots(legend, event):
         return []
 
     try:
-        # FIXME: The size of the legend is not being computed correctly, so
-        # always look at the front of the label where we know we'll get a hit.
-        label = legend.get_label_at(legend.x + 20, event.y)
-
+        label = legend.get_label_at(event.x, event.y)
     except:
         raise
         label = None


Test patch: