我有一个显示两个子图的简单代码,并允许用户在记录这些点击的x,y
坐标时左键单击第二个子图。
问题在于,点击以选择要缩放的区域并拖动子图也会被识别为左键单击。
有没有办法区分和过滤掉这些左键点击?
import numpy as np
import matplotlib.pyplot as plt
def onclick(event, ax):
# Only clicks inside this axis are valid.
if event.inaxes == ax:
if event.button == 1:
print(event.xdata, event.ydata)
# Draw the click just made
ax.scatter(event.xdata, event.ydata)
ax.figure.canvas.draw()
elif event.button == 2:
# Do nothing
print("scroll click")
elif event.button == 3:
# Do nothing
print("right click")
else:
pass
fig, (ax1, ax2) = plt.subplots(1, 2)
# Plot some random scatter data
ax2.scatter(np.random.uniform(0., 10., 10), np.random.uniform(0., 10., 10))
fig.canvas.mpl_connect(
'button_press_event', lambda event: onclick(event, ax2))
plt.show()
答案 0 :(得分:5)
您可以在先前移动鼠标后检查是否释放了鼠标按钮。因为对于缩放和平移,您可以调用该函数仅在没有发生先前移动时绘制新点。
import numpy as np
import matplotlib.pyplot as plt
class Click():
def __init__(self, ax, func, button=1):
self.ax=ax
self.func=func
self.button=button
self.press=False
self.move = False
self.c1=self.ax.figure.canvas.mpl_connect('button_press_event', self.onpress)
self.c2=self.ax.figure.canvas.mpl_connect('button_release_event', self.onrelease)
self.c3=self.ax.figure.canvas.mpl_connect('motion_notify_event', self.onmove)
def onclick(self,event):
if event.inaxes == self.ax:
if event.button == self.button:
self.func(event, self.ax)
def onpress(self,event):
self.press=True
def onmove(self,event):
if self.press:
self.move=True
def onrelease(self,event):
if self.press and not self.move:
self.onclick(event)
self.press=False; self.move=False
def func(event, ax):
print(event.xdata, event.ydata)
ax.scatter(event.xdata, event.ydata)
ax.figure.canvas.draw()
fig, (ax1, ax2) = plt.subplots(1, 2)
# Plot some random scatter data
ax2.scatter(np.random.uniform(0., 10., 10), np.random.uniform(0., 10., 10))
click = Click(ax2, func, button=1)
plt.show()
答案 1 :(得分:3)
区分点击和拖动/缩放(无论是右键单击还是左键单击)的一种方法是测量按钮按下和按钮释放之间的时间,然后执行按钮释放上的操作,而不是按钮按。
import numpy as np
import matplotlib.pyplot as plt
import time
MAX_CLICK_LENGTH = 0.1 # in seconds; anything longer is a drag motion
def onclick(event, ax):
ax.time_onclick = time.time()
def onrelease(event, ax):
# Only clicks inside this axis are valid.
if event.inaxes == ax:
if event.button == 1 and ((time.time() - ax.time_onclick) < MAX_CLICK_LENGTH):
print(event.xdata, event.ydata)
# Draw the click just made
ax.scatter(event.xdata, event.ydata)
ax.figure.canvas.draw()
elif event.button == 2:
print("scroll click")
elif event.button == 3:
print("right click")
else:
pass
fig, (ax1, ax2) = plt.subplots(1, 2)
# Plot some random scatter data
ax2.scatter(np.random.uniform(0., 10., 10), np.random.uniform(0., 10., 10))
fig.canvas.mpl_connect('button_press_event', lambda event: onclick(event, ax2))
fig.canvas.mpl_connect('button_release_event', lambda event: onrelease(event, ax2))
plt.show()
答案 2 :(得分:0)
我意识到这是一个老问题,但是我也遇到了同样的问题,我想我找到了一个整洁的解决方案。但是,它目前仅适用于Qt后端(其他后端也可能存在类似的解决方案)。这个想法是matplotlib在缩放或平移时会更改光标形状,因此您可以进行检查。这是经过修改的代码:
import numpy as np
import matplotlib
matplotlib.use('qt5agg')
import matplotlib.pyplot as plt
def onclick(event, ax):
# Only clicks inside this axis are valid.
try: # use try/except in case we are not using Qt backend
zooming_panning = ( fig.canvas.cursor().shape() != 0 ) # 0 is the arrow, which means we are not zooming or panning.
except:
zooming_panning = False
if zooming_panning:
print("Zooming or panning")
return
if event.inaxes == ax:
if event.button == 1:
print(event.xdata, event.ydata)
# Draw the click just made
ax.scatter(event.xdata, event.ydata)
ax.figure.canvas.draw()
elif event.button == 2:
# Do nothing
print("scroll click")
elif event.button == 3:
# Do nothing
print("right click")
else:
pass
fig, (ax1, ax2) = plt.subplots(1, 2)
# Plot some random scatter data
ax2.scatter(np.random.uniform(0., 10., 10), np.random.uniform(0., 10., 10))
fig.canvas.mpl_connect(
'button_press_event', lambda event: onclick(event, ax2))
plt.show()
答案 3 :(得分:0)
我的答案不适用于所有后端,但是,它适用于 jupyter 笔记本后端 nbAgg,类似于 @Rincewind 答案
%matplotlib notebook
import numpy as np
import matplotlib.pyplot as plt
import ipywidgets as wdg
def onclick(event, ax):
# Only clicks inside this axis are valid.
if event.inaxes != ax:
return
# Not adding points when zooming or paning
ptr_type = str(fig.canvas.toolbar.cursor)
pick = 'Cursors.POINTER'
if ptr_type != pick:
return
if event.button == 1:
print(event.xdata, event.ydata)
# Draw the click just made
ax.scatter(event.xdata, event.ydata)
ax.figure.canvas.draw()
elif event.button == 2:
# Do nothing
print("scroll click")
elif event.button == 3:
# Do nothing
print("right click")
else:
pass
fig, (ax1, ax2) = plt.subplots(1, 2)
# Plot some random scatter data
ax2.scatter(np.random.uniform(0., 10., 10), np.random.uniform(0., 10., 10))
ka = fig.canvas.mpl_connect(
'button_press_event', lambda event: onclick(event, ax2))
plt.show()