如何在 matplotlib 中为交互式绘图的 onclick(event) 函数创建类?
Posted
技术标签:
【中文标题】如何在 matplotlib 中为交互式绘图的 onclick(event) 函数创建类?【英文标题】:How to make class for onclick(event) functions for Interactive plot in matplotlib? 【发布时间】:2021-01-14 16:28:53 【问题描述】:我尝试使用一些函数创建交互式 matplotlib 图。我想将这些函数归为一个类(我还是新手,从别人的代码中得到帮助)
import matplotlib.pyplot as plt
def draw_line(startx,starty):
ax = plt.gca()
xy = plt.ginput(1)
x = [startx,xy[0][0]]
y = [starty,xy[0][1]]
line = ax.plot(x,y, picker=True , pickradius = 5 , color = "blue")
ax.figure.canvas.draw()
def onclick(event):
"""
This implements click functionality. If it's a double click do something,
else ignore.
Once in the double click block, if its a left click, wait for a further
click and draw a line between the double click co-ordinates and that click
(using ginput(1) - the 1 means wait for one mouse input - a higher number
is used to get multiple clicks to define a polyline)
"""
ax = plt.gca()
if event.dblclick:
if event.button == 1:
# Draw line
draw_line(event.xdata,event.ydata) # here you click on the plot
else:
pass # Do nothing
if event.button == 1:
pass
def onpick(event):
ax = plt.gca()
"""
Handles the pick event - if an object has been picked, store a
reference to it. We do this by simply adding a reference to it
named 'stored_pick' to the axes object. Note that in python we
can dynamically add an attribute variable (stored_pick) to an
existing object - even one that is produced by a library as in this
case
"""
this_artist = event.artist # the picked object is available as event.artist
ax.picked_object = this_artist
def on_key(event):
"""
Function to be bound to the key press event
If the key pressed is delete and there is a picked object,
remove that object from the canvas
"""
if event.key == u'delete':
ax = plt.gca()
if ax.picked_object:
ax.picked_object.remove()
ax.picked_object = None
ax.figure.canvas.draw()
def applyplt():
fig = plt.gcf()
ax = plt.gca()
cidonclic = fig.canvas.mpl_connect('button_press_event', onclick)
cidonpic = fig.canvas.mpl_connect('pick_event', onpick)
cidonkey = fig.canvas.mpl_connect('key_press_event', on_key)
"""
Basic Plot to test the function.
"""
fig1 = plt.figure(figsize = (10,10))
gs = fig1.add_gridspec(10,10)
ax101 = fig1.add_subplot(gs[:,:])
ax101.set_ylim(0,10)
ax101.set_xlim(0,10)
applyplt()
plt.show()
我想将这些事件函数归为一个class name(object)
(例如:class Drawer(object)
)
如果可以进行任何其他优化,也请提出建议。谢谢!
【问题讨论】:
【参考方案1】:下面是分组到一个类中的函数:
import matplotlib.pyplot as plt
class Interactivity:
def __init__(self, fig = None):
self.fig = plt.gcf() if fig is None else fig
self.ax = self.fig.gca()
self.connections = ()
def __enter__(self):
self.connect()
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.disconnect()
def connect(self):
""" Install the event handlers for the plot. """
self.connections = (
self.fig.canvas.mpl_connect('button_press_event', self.onclick),
self.fig.canvas.mpl_connect('pick_event', self.onpick),
self.fig.canvas.mpl_connect('key_press_event', self.on_key),
)
def disconnect(self):
""" Uninstall the event handlers for the plot. """
for connection in self.connections:
self.fig.canvas.mpl_disconnect(connection)
def draw_line(self, startx, starty):
xy = plt.ginput(1)
x = [startx, xy[0][0]]
y = [starty, xy[0][1]]
self.ax.plot(x, y, picker=True, pickradius=5, color='blue')
self.ax.figure.canvas.draw()
def onclick(self, event):
"""
This implements click functionality. If it's a double click do
something, else ignore.
Once in the double click block, if its a left click, wait for a further
click and draw a line between the double click co-ordinates and that
click (using ginput(1) - the 1 means wait for one mouse input - a
higher number is used to get multiple clicks to define a polyline)
"""
print('onclick')
if event.dblclick:
if event.button == 1:
self.draw_line(event.xdata, event.ydata)
def onpick(self, event):
"""
Handles the pick event - if an object has been picked, store a
reference to it. We do this by simply adding a reference to it
named 'picked_object' to the axes object.
"""
print('onpick')
this_artist = event.artist
# the picked object is available as event.artist
self.ax.picked_object = this_artist
def on_key(self, event):
"""
Function to be bound to the key press event
If the key pressed is delete and there is a picked object,
remove that object from the canvas
"""
print('onkey: ', event.key)
if event.key == 'delete' and self.ax.picked_object:
self.ax.picked_object.remove()
self.ax.picked_object = None
self.ax.figure.canvas.draw()
用法:
# Basic plot to test the functionality
fig = plt.figure(figsize = (10,10))
gs = fig.add_gridspec(10,10)
ax101 = fig.add_subplot(gs[:,:])
ax101.set_ylim(0,10)
ax101.set_xlim(0,10)
with Interactivity():
plt.show()
如您所见,它可以用作上下文处理程序来自动安装和卸载处理程序,或者您可以创建它的实例,然后调用其connect
方法手动安装处理程序(然后稍后可选地调用disconnect
方法来卸载处理程序)。
【讨论】:
以上是关于如何在 matplotlib 中为交互式绘图的 onclick(event) 函数创建类?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 matplotlib 中为 3d plot_surface 设置动画
使用 matplotlib 在 Spyder 中进行交互式(?)绘图