区分button_press_event与matplotlib中的拖放和缩放点击

时间:2018-01-25 15:24:27

标签: python matplotlib

我有一个显示两个子图的简单代码,并允许用户在记录这些点击的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()

4 个答案:

答案 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()