结合matplotlib的鼠标按键事件和pick事件
Combining matplotlib's mouse button events with pick events
基于鼠标按钮和按键事件的组合,将不同的功能应用于散点图的点。当按下鼠标左键时,调用 matplotlib 的 Lasso 小部件,并使用包含的点功能 1 发生。当按下 Shift+LMB
时,会绘制一个 Lasso
并且功能 2 会与包含的点一起发生。当按下 Alt+LMB
时,将绘制 Lasso
并使用包含的点功能 3 发生。最后但并非最不重要的一点是,当我按下 RMB
时,会触发一个拾取事件,并给出散点图中所选点的索引。
自从我添加了 pick
事件后,上述功能正常工作,直到 第一次 触发了 pick
事件。当它被触发时,似乎 canvas 被锁定,我无法使用任何其他功能。尽管我得到了所选点的索引,但我没有收到任何错误,并且 canvas 变得没有响应。
我修改了从问题中提取的代码,这实际上是我想做的。
代码:
import logging
import matplotlib
from matplotlib.widgets import Lasso
from matplotlib.colors import colorConverter
from matplotlib.collections import RegularPolyCollection
from matplotlib import path
import numpy as np
import matplotlib.pyplot as plt
from numpy.random import rand
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
class Datum(object):
colorin = colorConverter.to_rgba('red')
colorShift = colorConverter.to_rgba('cyan')
colorCtrl = colorConverter.to_rgba('pink')
colorout = colorConverter.to_rgba('blue')
def __init__(self, x, y, include=False):
self.x = x
self.y = y
if include:
self.color = self.colorin
else:
self.color = self.colorout
class LassoManager(object):
def __init__(self, ax, data):
self.axes = ax
self.canvas = ax.figure.canvas
self.data = data
self.Nxy = len(data)
facecolors = [d.color for d in data]
self.xys = [(d.x, d.y) for d in data]
fig = ax.figure
self.collection = RegularPolyCollection(fig.dpi, 6, sizes=(100,),facecolors=facecolors, offsets = self.xys, transOffset = ax.transData)
ax.add_collection(self.collection)
self.pick=self.canvas.mpl_connect('pick_event', self.onpick)
self.cid = self.canvas.mpl_connect('button_press_event', self.onpress)
self.keyPress = self.canvas.mpl_connect('key_press_event', self.onKeyPress)
self.keyRelease = self.canvas.mpl_connect('key_release_event', self.onKeyRelease)
self.lasso = None
self.shiftKey = False
self.ctrlKey = False
def callback(self, verts):
logging.debug('in LassoManager.callback(). Shift: %s, Ctrl: %s' % (self.shiftKey, self.ctrlKey))
facecolors = self.collection.get_facecolors()
p = path.Path(verts)
ind = p.contains_points(self.xys)
for i in range(len(self.xys)):
if ind[i]:
if self.shiftKey:
facecolors[i] = Datum.colorShift
elif self.ctrlKey:
facecolors[i] = Datum.colorCtrl
else:
facecolors[i] = Datum.colorin
print self.xys[i]
else:
facecolors[i] = Datum.colorout
self.canvas.draw_idle()
self.canvas.widgetlock.release(self.lasso)
del self.lasso
def onpress(self, event):
if self.canvas.widgetlock.locked(): return
if event.inaxes is None: return
self.lasso = Lasso(event.inaxes, (event.xdata, event.ydata), self.callback)
# acquire a lock on the widget drawing
self.canvas.widgetlock(self.lasso)
def onKeyPress(self, event):
logging.debug('in LassoManager.onKeyPress(). Event received: %s (key: %s)' % (event, event.key))
if event.key == 'alt':
self.ctrlKey = True
if event.key == 'shift':
self.shiftKey = True
def onKeyRelease(self, event):
logging.debug('in LassoManager.onKeyRelease(). Event received: %s (key: %s)' % (event, event.key))
if event.key == 'alt':
self.ctrlKey = False
if event.key == 'shift':
self.shiftKey = False
def onpick(self,event):
if event.mouseevent.button == 3:
index = event.ind
print('onpick scatter:', index, np.take(x, index), np.take(y, index))
if __name__ == '__main__':
x,y =rand(2,100)
data = [Datum(*xy) for xy in zip(x,y)]
fig = plt.figure()
ax = plt.axes()
ax.scatter(x,y,picker=True)
lman = LassoManager(ax, data)
plt.show()
关于可能导致此故障的原因有什么建议吗?提前致谢。
您这次遇到的问题是,当您点击一位艺术家时,您同时生成了 PickEvent
和 MouseEvent
。 MouseEvent
锁定 canvas 并阻止您之后做任何其他事情。
最好的解决方案是防止 MouseEvent
在 PickEvent
之后被触发,但我不知道是否有办法做到这一点。相反,我添加了一个测试来检查 onpress()
是否在 onpick()
之后调用以禁用锁定机制。
import logging
import matplotlib
from matplotlib.widgets import Lasso
from matplotlib.colors import colorConverter
from matplotlib.collections import RegularPolyCollection
from matplotlib import path
import numpy as np
import matplotlib.pyplot as plt
from numpy.random import rand
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
class Datum(object):
colorin = colorConverter.to_rgba('red')
colorShift = colorConverter.to_rgba('cyan')
colorCtrl = colorConverter.to_rgba('pink')
colorout = colorConverter.to_rgba('blue')
def __init__(self, x, y, include=False):
self.x = x
self.y = y
if include:
self.color = self.colorin
else:
self.color = self.colorout
class LassoManager(object):
def __init__(self, ax, data):
self.axes = ax
self.canvas = ax.figure.canvas
self.data = data
self.Nxy = len(data)
facecolors = [d.color for d in data]
self.xys = [(d.x, d.y) for d in data]
fig = ax.figure
self.collection = RegularPolyCollection(fig.dpi, 6, sizes=(100,),facecolors=facecolors, offsets = self.xys, transOffset = ax.transData)
ax.add_collection(self.collection)
self.cid = self.canvas.mpl_connect('button_press_event', self.onpress)
self.keyPress = self.canvas.mpl_connect('key_press_event', self.onKeyPress)
self.keyRelease = self.canvas.mpl_connect('key_release_event', self.onKeyRelease)
self.pick=self.canvas.mpl_connect('pick_event', self.onpick)
self.lasso = None
self.shiftKey = False
self.ctrlKey = False
self.pickEvent = False
def callback(self, verts):
logging.debug('in LassoManager.callback(). Shift: %s, Ctrl: %s' % (self.shiftKey, self.ctrlKey))
facecolors = self.collection.get_facecolors()
p = path.Path(verts)
ind = p.contains_points(self.xys)
for i in range(len(self.xys)):
if ind[i]:
if self.shiftKey:
facecolors[i] = Datum.colorShift
elif self.ctrlKey:
facecolors[i] = Datum.colorCtrl
else:
facecolors[i] = Datum.colorin
print self.xys[i]
else:
facecolors[i] = Datum.colorout
self.canvas.draw_idle()
self.canvas.widgetlock.release(self.lasso)
del self.lasso
def onpress(self, event):
logging.debug('in LassoManager.onpress(). Event received: %s' % event)
if self.pickEvent:
self.pickEvent = False
return
if self.canvas.widgetlock.locked(): return
if event.inaxes is None: return
self.lasso = Lasso(event.inaxes, (event.xdata, event.ydata), self.callback)
# acquire a lock on the widget drawing
self.canvas.widgetlock(self.lasso)
def onKeyPress(self, event):
logging.debug('in LassoManager.onKeyPress(). Event received: %s (key: %s)' % (event, event.key))
if event.key == 'alt':
self.ctrlKey = True
if event.key == 'shift':
self.shiftKey = True
def onKeyRelease(self, event):
logging.debug('in LassoManager.onKeyRelease(). Event received: %s (key: %s)' % (event, event.key))
if event.key == 'alt':
self.ctrlKey = False
if event.key == 'shift':
self.shiftKey = False
def onpick(self, event):
logging.debug('in LassoManager.onpick(). Event received: %s' % event)
self.pickEvent = True
if event.mouseevent.button == 3:
index = event.ind
print 'onpick scatter: ', index, np.take(x, index), np.take(y, index)
if __name__ == '__main__':
x,y =rand(2,100)
data = [Datum(*xy) for xy in zip(x,y)]
fig = plt.figure()
ax = plt.axes()
ax.scatter(x,y,picker=True)
lman = LassoManager(ax, data)
plt.show()
基于鼠标按钮和按键事件的组合,将不同的功能应用于散点图的点。当按下鼠标左键时,调用 matplotlib 的 Lasso 小部件,并使用包含的点功能 1 发生。当按下 Shift+LMB
时,会绘制一个 Lasso
并且功能 2 会与包含的点一起发生。当按下 Alt+LMB
时,将绘制 Lasso
并使用包含的点功能 3 发生。最后但并非最不重要的一点是,当我按下 RMB
时,会触发一个拾取事件,并给出散点图中所选点的索引。
自从我添加了 pick
事件后,上述功能正常工作,直到 第一次 触发了 pick
事件。当它被触发时,似乎 canvas 被锁定,我无法使用任何其他功能。尽管我得到了所选点的索引,但我没有收到任何错误,并且 canvas 变得没有响应。
我修改了从
代码:
import logging
import matplotlib
from matplotlib.widgets import Lasso
from matplotlib.colors import colorConverter
from matplotlib.collections import RegularPolyCollection
from matplotlib import path
import numpy as np
import matplotlib.pyplot as plt
from numpy.random import rand
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
class Datum(object):
colorin = colorConverter.to_rgba('red')
colorShift = colorConverter.to_rgba('cyan')
colorCtrl = colorConverter.to_rgba('pink')
colorout = colorConverter.to_rgba('blue')
def __init__(self, x, y, include=False):
self.x = x
self.y = y
if include:
self.color = self.colorin
else:
self.color = self.colorout
class LassoManager(object):
def __init__(self, ax, data):
self.axes = ax
self.canvas = ax.figure.canvas
self.data = data
self.Nxy = len(data)
facecolors = [d.color for d in data]
self.xys = [(d.x, d.y) for d in data]
fig = ax.figure
self.collection = RegularPolyCollection(fig.dpi, 6, sizes=(100,),facecolors=facecolors, offsets = self.xys, transOffset = ax.transData)
ax.add_collection(self.collection)
self.pick=self.canvas.mpl_connect('pick_event', self.onpick)
self.cid = self.canvas.mpl_connect('button_press_event', self.onpress)
self.keyPress = self.canvas.mpl_connect('key_press_event', self.onKeyPress)
self.keyRelease = self.canvas.mpl_connect('key_release_event', self.onKeyRelease)
self.lasso = None
self.shiftKey = False
self.ctrlKey = False
def callback(self, verts):
logging.debug('in LassoManager.callback(). Shift: %s, Ctrl: %s' % (self.shiftKey, self.ctrlKey))
facecolors = self.collection.get_facecolors()
p = path.Path(verts)
ind = p.contains_points(self.xys)
for i in range(len(self.xys)):
if ind[i]:
if self.shiftKey:
facecolors[i] = Datum.colorShift
elif self.ctrlKey:
facecolors[i] = Datum.colorCtrl
else:
facecolors[i] = Datum.colorin
print self.xys[i]
else:
facecolors[i] = Datum.colorout
self.canvas.draw_idle()
self.canvas.widgetlock.release(self.lasso)
del self.lasso
def onpress(self, event):
if self.canvas.widgetlock.locked(): return
if event.inaxes is None: return
self.lasso = Lasso(event.inaxes, (event.xdata, event.ydata), self.callback)
# acquire a lock on the widget drawing
self.canvas.widgetlock(self.lasso)
def onKeyPress(self, event):
logging.debug('in LassoManager.onKeyPress(). Event received: %s (key: %s)' % (event, event.key))
if event.key == 'alt':
self.ctrlKey = True
if event.key == 'shift':
self.shiftKey = True
def onKeyRelease(self, event):
logging.debug('in LassoManager.onKeyRelease(). Event received: %s (key: %s)' % (event, event.key))
if event.key == 'alt':
self.ctrlKey = False
if event.key == 'shift':
self.shiftKey = False
def onpick(self,event):
if event.mouseevent.button == 3:
index = event.ind
print('onpick scatter:', index, np.take(x, index), np.take(y, index))
if __name__ == '__main__':
x,y =rand(2,100)
data = [Datum(*xy) for xy in zip(x,y)]
fig = plt.figure()
ax = plt.axes()
ax.scatter(x,y,picker=True)
lman = LassoManager(ax, data)
plt.show()
关于可能导致此故障的原因有什么建议吗?提前致谢。
您这次遇到的问题是,当您点击一位艺术家时,您同时生成了 PickEvent
和 MouseEvent
。 MouseEvent
锁定 canvas 并阻止您之后做任何其他事情。
最好的解决方案是防止 MouseEvent
在 PickEvent
之后被触发,但我不知道是否有办法做到这一点。相反,我添加了一个测试来检查 onpress()
是否在 onpick()
之后调用以禁用锁定机制。
import logging
import matplotlib
from matplotlib.widgets import Lasso
from matplotlib.colors import colorConverter
from matplotlib.collections import RegularPolyCollection
from matplotlib import path
import numpy as np
import matplotlib.pyplot as plt
from numpy.random import rand
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
class Datum(object):
colorin = colorConverter.to_rgba('red')
colorShift = colorConverter.to_rgba('cyan')
colorCtrl = colorConverter.to_rgba('pink')
colorout = colorConverter.to_rgba('blue')
def __init__(self, x, y, include=False):
self.x = x
self.y = y
if include:
self.color = self.colorin
else:
self.color = self.colorout
class LassoManager(object):
def __init__(self, ax, data):
self.axes = ax
self.canvas = ax.figure.canvas
self.data = data
self.Nxy = len(data)
facecolors = [d.color for d in data]
self.xys = [(d.x, d.y) for d in data]
fig = ax.figure
self.collection = RegularPolyCollection(fig.dpi, 6, sizes=(100,),facecolors=facecolors, offsets = self.xys, transOffset = ax.transData)
ax.add_collection(self.collection)
self.cid = self.canvas.mpl_connect('button_press_event', self.onpress)
self.keyPress = self.canvas.mpl_connect('key_press_event', self.onKeyPress)
self.keyRelease = self.canvas.mpl_connect('key_release_event', self.onKeyRelease)
self.pick=self.canvas.mpl_connect('pick_event', self.onpick)
self.lasso = None
self.shiftKey = False
self.ctrlKey = False
self.pickEvent = False
def callback(self, verts):
logging.debug('in LassoManager.callback(). Shift: %s, Ctrl: %s' % (self.shiftKey, self.ctrlKey))
facecolors = self.collection.get_facecolors()
p = path.Path(verts)
ind = p.contains_points(self.xys)
for i in range(len(self.xys)):
if ind[i]:
if self.shiftKey:
facecolors[i] = Datum.colorShift
elif self.ctrlKey:
facecolors[i] = Datum.colorCtrl
else:
facecolors[i] = Datum.colorin
print self.xys[i]
else:
facecolors[i] = Datum.colorout
self.canvas.draw_idle()
self.canvas.widgetlock.release(self.lasso)
del self.lasso
def onpress(self, event):
logging.debug('in LassoManager.onpress(). Event received: %s' % event)
if self.pickEvent:
self.pickEvent = False
return
if self.canvas.widgetlock.locked(): return
if event.inaxes is None: return
self.lasso = Lasso(event.inaxes, (event.xdata, event.ydata), self.callback)
# acquire a lock on the widget drawing
self.canvas.widgetlock(self.lasso)
def onKeyPress(self, event):
logging.debug('in LassoManager.onKeyPress(). Event received: %s (key: %s)' % (event, event.key))
if event.key == 'alt':
self.ctrlKey = True
if event.key == 'shift':
self.shiftKey = True
def onKeyRelease(self, event):
logging.debug('in LassoManager.onKeyRelease(). Event received: %s (key: %s)' % (event, event.key))
if event.key == 'alt':
self.ctrlKey = False
if event.key == 'shift':
self.shiftKey = False
def onpick(self, event):
logging.debug('in LassoManager.onpick(). Event received: %s' % event)
self.pickEvent = True
if event.mouseevent.button == 3:
index = event.ind
print 'onpick scatter: ', index, np.take(x, index), np.take(y, index)
if __name__ == '__main__':
x,y =rand(2,100)
data = [Datum(*xy) for xy in zip(x,y)]
fig = plt.figure()
ax = plt.axes()
ax.scatter(x,y,picker=True)
lman = LassoManager(ax, data)
plt.show()