带有 matplotlib 图的 ipywidget 总是显示两个轴

ipywidget with matplotlib figure always shows two axes

我正在尝试创建一个 ipywidget 界面,其中包含一个 matplotlib 图形,该图形会在更改滑块时更新。它原则上有效,但它总是创建一个额外的图形。

代码如下:

import numpy as np
import matplotlib.pyplot as plt
from ipywidgets import widgets
from IPython.display import display, clear_output

# make a grid

x = np.linspace(0, 5, 100)
X, Y = np.meshgrid(x, x)

# create the layout with slider

out = widgets.Output(layout=widgets.Layout(height='300px', width = '400px', border='solid'))
slider = widgets.IntSlider(value=1, min=1, max=5)
w = widgets.VBox(children=(out, slider))

# axes to plot into

ax = plt.axes()

display(w)

def update(value):
    i = slider.value
    Z = np.exp(-(X / i)**2 - (Y / i)**2)
    ax.pcolormesh(x, x, Z, vmin=0, vmax=1, shading='auto')
    with out:
        clear_output(wait=True)
        display(ax.figure)

slider.observe(update)
update(None)

这是不需要的输出

小部件有效,只有上部输出更新,但我不明白为什么下部输出也存在或如何摆脱它。我是否漏掉了一些明显的东西?

您可以使用小部件后端 %matplotlib widget,我 认为 是为此设计的。您需要将 %matplotlib widget 放在顶部(或在 matplotlib 内容被引入之前)。

更新:还有一些指导形式 matplotlib here 及以下,重点补充。

Note

To get the interactive functionality described here, you must be using an interactive backend. The default backend in notebooks, the inline backend, is not. backend_inline renders the figure once and inserts a static image into the notebook when the cell is executed. Because the images are static, they can not be panned / zoomed, take user input, or be updated from other cells.

您的示例可以简化为:

%matplotlib widget
import numpy as np
import matplotlib.pyplot as plt
from ipywidgets import widgets
from IPython.display import display, clear_output

x = np.linspace(0, 5, 100)
X, Y = np.meshgrid(x, x)

slider = widgets.IntSlider(value=1, min=1, max=5)

ax = plt.axes()
display(slider)
def update(value):
    i = slider.value
    Z = np.exp(-(X / i)**2 - (Y / i)**2)
    ax.pcolormesh(x, x, Z, vmin=0, vmax=1, shading='auto')

slider.observe(update)
update(None)

jayveesa 的回答是避免这种输出的好方法。我想为您的问题 why 添加一个答案。

The widget works, and only the upper output is updated, but I do not understand why the lower output also exists or how to get rid of it. Am I missing something obvious?

这里要做的一件有启发性的事情是注释掉 display 数字

更新中的行

def update(value):
    i = slider.value
    Z = np.exp(-(X / i)**2 - (Y / i)**2)
    ax.pcolormesh(x, x, Z, vmin=0, vmax=1, shading='auto')
    # with out:
        # clear_output(wait=True)
        # display(ax.figure)
update(None)

如果你这样做,你将只会看到一个绘图输出。这是因为当您使用 jupyter 笔记本的 %matplotlib inline 后端时,在单元格中创建的任何图形都将在单元格完成 运行 时关闭并显示。 (请参阅此处核心 matplotlib 开发人员的解释:https://github.com/matplotlib/matplotlib/issues/18248#issuecomment-675177108)。因此,黑色轮廓包围的图形来自 display(ax.figure),下方的图形来自较早创建的图形。