使用 asyncio 对 matplotlib 中的鼠标单击事件做出反应
react to mouse click events in matplotlib using asyncio
我正在尝试制作一个简单的用户界面,用户可以在其中选择图像中的一些像素坐标。我想用 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 来响应或收集事件?
我找到了同时使用 asyncio 和 matplotlib 的解决方案。
基本上,主要问题似乎是 matplotlib 的 gui 必须在主线程中 运行 并且 运行 绘图 gui 将阻塞主线程中的所有其他内容。我对此的解决方案是 运行 另一个线程中的异步循环并使用 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()
我正在尝试制作一个简单的用户界面,用户可以在其中选择图像中的一些像素坐标。我想用 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 来响应或收集事件?
我找到了同时使用 asyncio 和 matplotlib 的解决方案。
基本上,主要问题似乎是 matplotlib 的 gui 必须在主线程中 运行 并且 运行 绘图 gui 将阻塞主线程中的所有其他内容。我对此的解决方案是 运行 另一个线程中的异步循环并使用 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()