问题描述
我正在尝试使用JupyterLab循环更新交互式matplotlib图形。如果我在与循环不同的单元格中创建图,则可以执行此操作,但是我更愿意在该单元格中创建图并运行循环。
简单代码示例:
import matplotlib.pyplot as plt
import time
%matplotlib widget
fig = plt.figure()
for i in range(5):
x = list(range(i+2))
xx = [x**2 for x in x]
plt.clf()
plt.plot(x,xx)
fig.canvas.draw()
time.sleep(1)
如果fig = plt.figure()
与循环位于同一单元格中,则直到循环结束,图形才会更新:
如果在不同的单元格中创建图形,则会得到动态更新,但如果可能的话,我希望能够在同一单元格中创建图形,因此输出位于循环下方:
我在其他问题(here,here和here)中尝试了几种答案,但是,它们似乎不适用于JupyterLab中的交互式图形。我使用jupyter/scipy-notebook码头工人镜像作为我的环境,因此我相信一切都已正确设置。
有什么方法可以在创建图形的同一个单元中获得动态更新?
解决方法
您可以利用IPython事件循环来使用asyncio:
import matplotlib.pyplot as plt
import asyncio
%matplotlib widget
fig = plt.figure()
async def update():
for i in range(5):
print(i)
x = list(range(i + 2))
xx = [x**2 for x in x]
plt.clf()
plt.plot(x,xx)
fig.canvas.draw()
await asyncio.sleep(1)
loop = asyncio.get_event_loop()
loop.create_task(update());
,
如果不想使用asyncio
,可以使用display(...,display_id=True)
获取句柄并在其上使用.update()
:
import matplotlib.pyplot as plt
import time
%matplotlib widget
fig = plt.figure()
hfig = display(fig,display_id=True)
def update():
for i in range(5):
print(i)
x = list(range(i + 2))
xx = [x**2 for x in x]
plt.clf()
plt.plot(x,xx)
fig.canvas.draw()
hfig.update(fig)
time.sleep(1)
update()
plt.close(fig)