Closed prodat1 closed 11 months ago
You can bind a mouse_pos event with kivy and then used the motion_notify_event from figure canvas. See example above:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
import numpy as np
import matplotlib.pyplot as plt
from kivy_matplotlib_widget.uix.graph_widget import MatplotFigure
from kivy.core.window import Window
def enter_axes(event):
print('enter_axes', str(event.inaxes) + 'event' + \
event.inaxes.figure.texts[0].get_text()[-1])
#+ 'event' + event.inaxes.figure.texts[0].figure.texts[0].get_text()[-1]
event.inaxes.patch.set_facecolor('yellow')
event.canvas.draw()
def leave_axes(event):
print('leave_axes', str(event.inaxes) + 'event' + \
event.inaxes.figure.texts[0].get_text()[-1])
event.inaxes.patch.set_facecolor('white')
event.canvas.draw()
def enter_figure(event):
print('enter_figure', str(event.canvas.figure) + 'event' + \
event.canvas.figure.texts[0].get_text()[-1])
event.canvas.figure.patch.set_facecolor('red')
event.canvas.draw()
def leave_figure(event):
print('leave_figure', str(event.canvas.figure) + 'event' + \
event.canvas.figure.texts[0].get_text()[-1])
event.canvas.figure.patch.set_facecolor('grey')
event.canvas.draw()
def motion_notify(event):
print(f"event.x: {event.x}, event.y: {event.y}")
kv = """
<Test>:
orientation: 'vertical'
Button:
size_hint_y: None
height: 40
"""
Builder.load_string(kv)
class Test(BoxLayout):
def __init__(self, *args, **kwargs):
super(Test, self).__init__(*args, **kwargs)
self.add_plot()
def get_fc(self, i):
fig1 = plt.figure()
fig1.suptitle('mouse hover over figure or axes to trigger events' +
str(i))
ax1 = fig1.add_subplot(111)
# ax1 = fig1.add_subplot(211)
# ax2 = fig1.add_subplot(212)
wid = MatplotFigure()
# wid.
wid.figure = fig1
wid.axes = ax1
wid.xmin,wid.xmax=ax1.get_xlim()
wid.ymin,wid.ymax=ax1.get_ylim()
wid.figure.canvas.mpl_connect('figure_enter_event', enter_figure)
wid.figure.canvas.mpl_connect('figure_leave_event', leave_figure)
wid.figure.canvas.mpl_connect('axes_enter_event', enter_axes)
wid.figure.canvas.mpl_connect('axes_leave_event', leave_axes)
wid.figure.canvas.mpl_connect('motion_notify_event', motion_notify)
wid.figure.canvas.entered_figure = True
def _on_mouse_pos(*args):
'''Kivy Event to trigger the following matplotlib events:
`motion_notify_event`, `leave_notify_event` and
`enter_notify_event`.
'''
pos = args[1]
newcoord = wid.to_widget(pos[0], pos[1], relative=True)
x = newcoord[0]
y = newcoord[1]
inside = wid.collide_point(*pos)
if inside:
wid.figure.canvas.motion_notify_event(x, y, guiEvent=None)
if not inside and not wid.figure.canvas.entered_figure:
wid.figure.canvas.leave_notify_event(guiEvent=None)
wid.figure.canvas.entered_figure = True
elif inside and wid.figure.canvas.entered_figure:
wid.figure.canvas.enter_notify_event(guiEvent=None, xy=(pos[0], pos[1]))
wid.figure.canvas.entered_figure = False
Window.bind(mouse_pos=_on_mouse_pos)
return wid
def add_plot(self):
self.add_widget(self.get_fc(1))
self.add_widget(BoxLayout(size_hint_y=None,height=40))
self.add_widget(self.get_fc(2))
class TestApp(App):
def build(self):
return Test()
if __name__ == '__main__':
TestApp().run()```
This is an other example with a pick_event
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.backend_bases import MouseEvent
from kivy_matplotlib_widget.uix.graph_widget import MatplotFigure
from kivy.core.window import Window
def onpick(event):
thisline = event.artist
print(event)
xdata = thisline.get_xdata()
ydata = thisline.get_ydata()
ind = event.artist.contains(event.mouseevent)[1]['ind']
if len(ind)!=0:
points = tuple([xdata[ind][0], ydata[ind][0]])
print('onpick points:', points)
kv = """
<Test>:
orientation: 'vertical'
Button:
size_hint_y: None
height: 40
"""
Builder.load_string(kv)
class Test(BoxLayout):
def __init__(self, *args, **kwargs):
super(Test, self).__init__(*args, **kwargs)
self.add_plot()
def get_fc(self, i):
fig1 = plt.figure()
fig1.suptitle('mouse hover over figure or axes to trigger events' +
str(i))
ax1 = fig1.add_subplot(111)
line, = ax1.plot(np.random.rand(100), 'o',
picker=True, pickradius=5)
wid = MatplotFigure()
wid.figure = fig1
wid.axes = ax1
wid.xmin,wid.xmax=ax1.get_xlim()
wid.ymin,wid.ymax=ax1.get_ylim()
wid.figure.canvas.mpl_connect('pick_event', onpick)
def onPressed(instance,event):
pos = [event.x,event.y]
newcoord = wid.to_widget(pos[0], pos[1], relative=True)
x = newcoord[0]
y = newcoord[1]
inside = wid.collide_point(*pos)
if inside:
if event.button == 'left':
s = 'pick_event'
mouseevent = MouseEvent(s, wid.figure.canvas, x, y, wid.figure.canvas._button, wid.figure.canvas._key,
guiEvent=None)
wid.figure.canvas.pick_event(mouseevent,line)
print("left mouse clicked")
Window.bind(on_touch_down = onPressed)
return wid
def add_plot(self):
self.add_widget(self.get_fc(1))
self.add_widget(BoxLayout(size_hint_y=None,height=40))
self.add_widget(self.get_fc(2))
class TestApp(App):
def build(self):
return Test()
if __name__ == '__main__':
TestApp().run()```
@prodat1 feel free to close this issue if I correctly answer your purpose.
@prodat1 I have read again your question and maybe this example will be better for your purpose (I still don't know what you're trying to do). https://github.com/mp-007/kivy_matplotlib_widget/blob/main/examples/example_custom_touch_widget/line_data.py It used kivy on_touch_down/on_touch_move/on_touch_up to manage the touch/mouse press and move event.
I am using the graph_widget.py in my project. The MatplotFigure is integrated in a KV-String
self.ids["myPlot"].figcanvas.mpl_connect('motion_notify_event', on_motion)
The event is never called. Is there another way of accessing the events, is this a bug or am I missing something?