Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

issue with RectangularSelection #800

Open
fred4ets opened this issue Jun 22, 2021 · 2 comments
Open

issue with RectangularSelection #800

fred4ets opened this issue Jun 22, 2021 · 2 comments

Comments

@fred4ets
Copy link

Hello,

I have 2 issues using RectangularSelection.

See CME below showing the 2 issues.

CME is based on chaco/examples/demo/basic/scatter_rect_select.py.

I have added FooTool class, which displays "Foo!" when key "p" is pressed.

And added enable_rect_selection trait to enable/disable RectangularSelection.

First, if you set enable_rect_selection to False, you get:

  • "Foo!" is displayed
  • selected points in blue stay selected when mouse pointer is off selected points.

Now, if you set enable_rect_selection to True, you get:

  • "Foo!" is not more displayed because no keyboard events are now detected.
  • selected points in blue do not stay selected anymore when mouse pointer is off selected points.

So, what I would like to have as behaviour, when enable_rect_selection is set to True, is:

  • "Foo!" is displayed
  • selected points in blue stay selected when mouse pointer is off selected points.

How could I achieve this?

Thanks in advance.

Regards.

The CME:

import sys

# Major library imports
from numpy import sort, compress, arange
from numpy.random import random

# Enthought library imports
from enable.api import Component, ComponentEditor
from traits.api import HasTraits, Instance
from traitsui.api import Item, Group, View

# Chaco imports
from chaco.api import (
    ArrayPlotData,
    Plot,
    LassoOverlay,
    ScatterInspectorOverlay,
)
from chaco.tools.api import RectangularSelection, ScatterInspector
from enable.api import BaseTool, KeySpec


class FooTool(BaseTool):

    key = KeySpec

    def normal_key_pressed(self, event):
        if self.key.match(event):
            print('Foo!')

# ===============================================================================
# # Create the Chaco plot.
# ===============================================================================
def _create_plot_component():
    # Create some data
    npts = 200
    x = sort(random(npts))
    y = random(npts)

    # Create a plot data obect and give it this data
    pd = ArrayPlotData()
    pd.set_data("index", x)
    pd.set_data("value", y)

    # Create the plot
    plot = Plot(pd)
    plot.plot(
        ("index", "value"),
        type="scatter",
        name="my_plot",
        marker="circle",
        index_sort="ascending",
        color="red",
        marker_size=4,
        bgcolor="white",
    )

    # Tweak some of the plot properties
    plot.title = "Scatter Plot With Rectangular Selection"
    plot.line_width = 1
    plot.padding = 50

    # Right now, some of the tools are a little invasive, and we need the
    # actual ScatterPlot object to give to them
    my_plot = plot.plots["my_plot"][0]

    enable_rect_selection = True

    # Attach some tools to the plot
    if enable_rect_selection:
        rect_selection = RectangularSelection(
            component=my_plot,
            selection_datasource=my_plot.index,
            drag_button="left",
            metadata_name="selections",
        )
        my_plot.tools.append(rect_selection)
        # my_plot.active_tool = rect_selection

        lasso_overlay = LassoOverlay(
            lasso_selection=rect_selection, component=my_plot
        )
        my_plot.overlays.append(lasso_overlay)

    my_plot.tools.append(ScatterInspector(my_plot, selection_mode="toggle"))

    plot.tools.append(FooTool(key=KeySpec('p')))

    scatter_overlay = ScatterInspectorOverlay(
        component=my_plot,
        selection_color="cornflowerblue",
        selection_marker_size=int(my_plot.marker_size) + 3,
        selection_marker="circle",
    )
    my_plot.overlays.append(scatter_overlay)



    return plot


# ===============================================================================
# Attributes to use for the plot view.
size = (650, 650)
title = "Scatter plot with selection"
bgcolor = "lightgray"


# ===============================================================================
# # Demo class that is used by the demo.py application.
# ===============================================================================
class Demo(HasTraits):
    plot = Instance(Component)

    traits_view = View(
        Group(
            Item(
                "plot",
                editor=ComponentEditor(size=size, bgcolor=bgcolor),
                show_label=False
            ),
            orientation="vertical",
        ),
        resizable=True,
        title=title,
    )

    def _selection_changed(self, event):
        mask = self.index_datasource.metadata["selections"]
        print("New selection: ")
        print(compress(mask, arange(len(mask))))
        # Ensure that the points are printed immediately:
        sys.stdout.flush()

    def _plot_default(self):
        plot = _create_plot_component()

        # Retrieve the plot hooked to the RectangularSelection tool.
        my_plot = plot.plots["my_plot"][0]
        # rect_selection = my_plot.active_tool

        # Set up the trait handler for the selection
        self.index_datasource = my_plot.index
        # rect_selection.observe(self._selection_changed, "selection_changed")

        return plot


demo = Demo()

if __name__ == "__main__":
    demo.configure_traits()

Debian x86_64, Python 3.7.3, ETS source from git

@fred4ets
Copy link
Author

Hello,

Anybody has any clue to fix this issue?

Thanks in advance.

Regards

@corranwebster
Copy link
Contributor

corranwebster commented May 15, 2023

Sorry for the long delay in looking at this. It looks like there are a couple of things going on here.

It looks like part of the problem is the way that key events are handled. If you run the sample code, you will see that the FooTool actually works when the mouse pointer is in the padding region outside the plot area. This is because what is happening is that:

  • key events dispatch first to the component under the mouse pointer (ie. the plot object)
  • it dispatches the key event to its tools
  • for each Interactor, if there is a matching handler eg. normal_key_pressed then it gets called; and if the auto_handle_event trait is True then the key event gets marked as "handled" even if the tool does nothing.

The LassoSelection/RectangleSelection tools on the renderers have key interactions, so they will go through that codepath, which means the key event never gets to the FooTool on the Plot object.

Probably the easiest work-around this is to put the FooTool on the renderer but before the RectangleSelection in the list of tools, so it gets the event first.

There may be some thought needed about the LassoSelection tool and whether it should be auto-handling events. Some of the issue may be because LassoSelection doesn't inherit from BaseTool, which doesn't have the auto-handling behaviour.

I'm not 100% sure what the issue is with the selection turning off. I only see this when you click (which the selection tool likely things of as the start of a new selection, and so deselecting things makes sense). The selection tools do have optional selection modes that extent or invert selections, so it may be that one of those makes more sense to use?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants