使用 asyncio 对 matplotlib 中的鼠标单击事件做出反应
Posted
技术标签:
【中文标题】使用 asyncio 对 matplotlib 中的鼠标单击事件做出反应【英文标题】:react to mouse click events in matplotlib using asyncio 【发布时间】:2016-04-23 08:23:46 【问题描述】:我正在尝试制作一个简单的用户界面,用户可以在其中选择图像中的一些像素坐标。我想用matplotlib来做,因此我遇到了这个堆栈溢出问题: Store mouse click event coordinates with matplotlib
给出将点击的坐标存储在全局列表中的解决方案
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(-10,10)
y = x**2
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(x,y)
coords = []
def onclick(event):
global ix, iy
ix, iy = event.xdata, event.ydata
print 'x = %d, y = %d'%(
ix, iy)
global coords
coords.append((ix, iy))
if len(coords) == 2:
fig.canvas.mpl_disconnect(cid)
return coords
cid = fig.canvas.mpl_connect('button_press_event', onclick)
该解决方案工作得很好,但是我想摆脱那些全局变量,并且我认为获取点击坐标对于 asyncio 来说是一项完美的工作。
我天真地尝试了以下代码,但显然不起作用(但它显示了我希望实现的总体思路):
import asyncio
import numpy as np
import matplotlib.pyplot as plt
queue = asyncio.Queue()
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(np.random.rand(10))
@asyncio.coroutine
def onclick(event):
yield from queue.put(event.x)
print('button=%d, x=%d, y=%d, xdata=%f, ydata=%f' % (
event.button, event.x, event.y, event.xdata, event.ydata))
cid = fig.canvas.mpl_connect('button_press_event', onclick)
@asyncio.coroutine
def consume():
while True:
value = yield from queue.get()
print("Consumed", value)
loop = asyncio.get_event_loop()
loop.create_task(plt.show())
loop.create_task(consume())
loop.run_forever()
如何结合使用 matplotlib 和 asyncio 来响应或收集事件?
【问题讨论】:
【参考方案1】:我找到了同时使用 asyncio 和 matplotlib 的解决方案。
基本上,主要问题似乎是 matplotlib 的 gui 必须在主线程中运行,并且运行 plot gui 会阻塞主线程中的所有其他内容。我对此的解决方案是在另一个线程中运行 asyncio 循环并使用 loop.call_soon_thread_safe
和 queue.put_no_wait
。
不确定这是否是一个好的解决方案,但至少到目前为止它似乎有效。
import asyncio
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import threading
queue = asyncio.Queue()
loop = asyncio.get_event_loop()
fig = plt.figure()
img = mpimg.imread('1970_0101_1015_47_1.jpg')
plt.imshow(img)
def onclick(event):
loop.call_soon_threadsafe(queue.put_nowait, (event.x,event.y))
print('button=%d, x=%d, y=%d, xdata=%f, ydata=%f' % (
event.button, event.x, event.y, event.xdata, event.ydata))
cid = fig.canvas.mpl_connect('button_press_event', onclick)
@asyncio.coroutine
def consume():
while True:
value = yield from queue.get()
print("Consumed", value)
def start_async_stuff():
print('lets async!')
loop.create_task(consume())
loop.run_forever()
threading.Thread(target=start_async_stuff).start()
plt.show()
【讨论】:
以上是关于使用 asyncio 对 matplotlib 中的鼠标单击事件做出反应的主要内容,如果未能解决你的问题,请参考以下文章