1

I would like to use the chaco tools ScatterInspector and/or ScatterInspectorOverlay with enaml. I've set up a very simple controller and view (source below) but cannot determine how to proceed. I have tried unsuccessfully to follow the minimal and old examples I've found.

If I uncomment the overlay part for ScatterInspectorOverlay, the code fails to run with

File ".../chaco/scatter_inspector_overlay.py", line 51, in overlay if not plot or not plot.index or not getattr(plot, "value", True):

If I comment out the overlay part, I of course don't get the overlay behavior I want and also, on moving the mouse, get

File ".../chaco/tools/scatter_inspector.py", line 48, in normal_mouse_move index = plot.map_index((event.x, event.y), threshold=self.threshold)

view.enaml source:

from enaml.widgets.api import (
        Window, Container, EnableCanvas,
    )

enamldef ScatterView(Window):
    attr controller
    title = "Scatter Inspector Test"
    initial_size = (640,480)

    Container:

        EnableCanvas:
            component = controller.scatter_plot

controller.py source:

import enaml
from enaml.stdlib.sessions import show_simple_view
from traits.api import HasTraits, Instance
from chaco.api import Plot, ArrayPlotData, ScatterInspectorOverlay
from chaco.tools.api import ScatterInspector
from numpy import linspace, sin

class ScatterController(HasTraits):
    scatter_plot = Instance(Plot)

    def _scatter_plot_default(self):
        # data
        x = linspace(-14, 14, 100)
        y = sin(x) * x**3
        plotdata = ArrayPlotData(x = x, y = y)

        # plot
        scatter_plot = Plot(plotdata)
        renderer = scatter_plot.plot(("x", "y"), type="scatter", color="red")

        # inspector
        scatter_plot.tools.append(ScatterInspector(scatter_plot))

        # overlay
        # scatter_plot.overlays.append( ScatterInspectorOverlay(
        #         scatter_plot,
        #         hover_color = 'red',
        #         hover_marker_size = 6,
        #         selection_marker_size = 6,
        #         selection_color = 'yellow',
        #         selection_outline_color='purple',
        #         selection_line_width = 3
        #     ))

        #return
        return scatter_plot

if __name__ == "__main__":
    with enaml.imports():
        from view import ScatterView

    main_controller = ScatterController()
    window = ScatterView(controller=ScatterController())
    show_simple_view(window)
JefferyRPrice
  • 895
  • 5
  • 17

1 Answers1

2

The problem with my above code was that I was adding ScatterInspector to scatter_plot rather than to renderer and that I was missing the [0] index to get renderer.

The key thing I was really wanting to do, though, was to be notified when the mouse was hovering over a data point and/or a data point was selected. I added when_hover_or_selection_changes which shows how to do that.

Working controller.py:

...
# plot
scatter_plot = Plot(plotdata)
renderer = scatter_plot.plot(("x", "y"), type="scatter", color="lightblue")[0]

# inspector
renderer.tools.append(ScatterInspector(renderer))

# overlay
renderer.overlays.append(ScatterInspectorOverlay(renderer,
                hover_color="red",
                hover_marker_size=6,
                selection_marker_size=6,
                selection_color="yellow",
                selection_outline_color="purple",
                selection_line_width=3))

...

# get notified when hover or selection changes
@on_trait_change('renderer.index.metadata')
def when_hover_or_selection_changes(self):
    print 'renderer.index.metadata = ', self.renderer.index.metadata    
JefferyRPrice
  • 895
  • 5
  • 17
  • This almost works for me - the GUI comes up and I can select the scatterplot points with the mouse, but the `print` in `when_hover_or_selection_changes` doesn't seem to execute. Note I had to add `from traits.api import on_trait_change`. Do you know of a way to debug this? – davidA Oct 29 '13 at 09:12
  • If it helps, using the DebugWrapper from https://svn.enthought.com/enthought/wiki/OnTraitChangeDispatch, I see the following when a point is clicked: `Notification: >()` and `Notification: >(, 'metadata_changed', , True)`. I'm not sure how this maps to `@on_trait_change` yet. – davidA Oct 29 '13 at 09:28
  • I'm not sure what the level of indentation should be for that `@on_trait_change` line, actually. Should it be a method of `ScatterController`, or is it a function definition within the `_scatter_plot_default` function, as the formatting above suggests? I've tried both. EDIT: as it references `self.renderer` I'm going to go with it being a normal class method. But that also suggests self.renderer needs to be set somewhere. In the above code, it's not set. – davidA Oct 29 '13 at 09:33
  • 1
    @meowsqueak Yes, that `@on_trait_change` line is indeed a method of `ScatterController` as you figured out via `self.renderer`. You are also right that the above code is a much abbreviated part of a larger class. In my case `self.renderer` was set as follows: `self.renderer = plot.plot(('h', 'v'), type='scatter')[0]` – JefferyRPrice Oct 30 '13 at 20:57