I'm currently evaluating vispy
for my interactive plotting needs. While it feels a bit beta-ish I'm rather impressed with its speed. Also API design-wise it looks promising.
One feature I'd need to work is picking plot elements with the mouse. There is one example in the distribution (0.6.4
) that promises to do precisely that: examples/demo/scene/picking.py
. Unfortunately it doesn't work for me.
It displays a single window containing a graph with multiple lines. I can interact with the plot as whole, i.e. zoom and shift, but I cannot select individual lines.
If I monkey-debug the relevant piece of code (print statement is mine, full example is at github):
@fig.connect
def on_mouse_press(event):
global selected, fig
if event.handled or event.button != 1:
return
if selected is not None:
selected.set_data(width=1)
selected = None
for v in fig.visuals_at(event.pos):
print(v)
if isinstance(v, vp.LinePlot):
selected = v
break
if selected is not None:
selected.set_data(width=3)
update_cursor(event.pos)
I get <ViewBox at 0x...>
no matter where I click. fig
is a vispy.plot.Fig
instance which is not well documented.
How can I make this work, i.e. make visuals_at
see beyond the ViewBox
and find the actual LinePlot
instances?
There is a workaround to make the view non-interactive before calling visuals_at. Afterwards the view can be set to interactive again.
This workaround can be found here in a google groups message workaround
The post is from the year 2015, so the problem seems to have been known for some time.
Code
So add to the code
plt.view.interactive = False
before calling fig.visuals_at and afterwards do
plt.view.interactive = True
Afterwards the code for on_mouse_press should look like this:
def on_mouse_press(event):
global selected, fig
if event.handled or event.button != 1:
return
if selected is not None:
selected.set_data(width=1)
selected = None
plt.view.interactive = False
for v in fig.visuals_at(event.pos):
if isinstance(v, vp.LinePlot):
selected = v
break
plt.view.interactive = True
if selected is not None:
selected.set_data(width=3)
update_cursor(event.pos)
Test