控制 ipywidgets Vbox 中的显示顺序(使用 matplotlib 小部件时)?
Controlling order of display in ipywidgets Vbox (when matplotlib widget is used)?
这太他妈烦人了...使用:
Python 3.8.10 (default, Sep 28 2021, 16:10:42) [GCC 9.3.0]
matplotlib 3.5.0
ipywidgets 7.6.5
jupyter 1.0.0
所以,考虑这个例子:
import IPython.display
from IPython.display import display
from ipywidgets import widgets, Layout
%matplotlib widget
import matplotlib as mpl
import matplotlib.pyplot as plt
widget_01 = widgets.HTML("<p>Hello, world</p>")
widget_02 = widgets.Output(layout=Layout(width='100%'))
widget_03 = widgets.Output(layout=Layout(width='100%'))
with widget_02:
IPython.display.clear_output(True)
display(widgets.HTMLMath("<p>Try equation: $x_y = y_x$</p>"))
myvbox = widgets.VBox([
widget_01,
widget_02,
widget_03
],)
display(myvbox)
with widget_03:
IPython.display.clear_output(True)
display(widgets.HTMLMath("<p>In the next episode...</p>"))
所以,我有一个“Vbox”,它有三个元素,“widget_01”,“widget_02”,“widget_03”;这三个元素放在一个列表中,它(不像字典)有一个顺序,所以我可以指望“widget_01”是“第一”,“widget_02”是“第二”,等等.由于这是一个“VBox”,即 Vertical Box,我希望列表中的“第一个”项目呈现在顶部,它下面的“第二个”项目(即在中间),以及等等。
事实上,这就是最简单情况下的输出结果:
好的,很酷 - 现在,让我们将“widget_02”变成 matplotlib widget
:
import IPython.display
from IPython.display import display
from ipywidgets import widgets, Layout
%matplotlib widget
import matplotlib as mpl
import matplotlib.pyplot as plt
widget_01 = widgets.HTML("<p>Hello, world</p>")
widget_02 = widgets.Output(layout=Layout(width='100%'))
widget_03 = widgets.Output(layout=Layout(width='100%'))
with widget_02:
IPython.display.clear_output(True)
fig = plt.figure(figsize=(10,1), dpi=90)
fig.canvas.toolbar_visible = False
ax = fig.add_subplot(111)
ax.plot([0,1,2], [0,1,2])
myvbox = widgets.VBox([
widget_01,
widget_02,
widget_03
],)
display(myvbox)
with widget_03:
IPython.display.clear_output(True)
display(widgets.HTMLMath("<p>In the next episode...</p>"))
好吧,现在 - 无论出于何种原因 - “widget_02”(成为情节)不再位于中间,而是最后(底部):
我的意思是,我确定 update “widget_03” 在我更新绘图后 - 但我希望 VBox 保持小部件的顺序?
所以 - 如果我在同一个 VBox 中更新不同的小部件,我如何才能按照它在 ipywidgets VBox 中列出的顺序呈现 Matplotlib 小部件,even渲染情节?
好的,我在这里找到了解决方案:Displaying a previously created Matplotlib figure in a widget · Issue #203 · matplotlib/ipympl,看来...
事实证明问题不是“控制位置”本身,而是:
- 事实上
fig = plt.figure...
调用实际上会自行产生输出,而不管 (with
) 输出上下文;可以通过 plt.ioff()
禁用 matplotlib 交互模式来防止
- 事实上,要显示交互式 matplotlib 小部件,我们应该
display(fig.canvas)
(不仅仅是 display(fig)
)
所以,在 OP 中,甚至没有 display(fig)
- 所以 matplotlib 小部件的整个输出都是由于 fig = plt.figure...
调用。
因此,要获得所需的输出,如 VBox 中指定的那样(widget_01 文本在顶部,widget_02 绘图在中间,widget_03 文本在底部):
...可以使用以下更正后的代码:
import IPython.display
from IPython.display import display
from ipywidgets import widgets, Layout
%matplotlib widget
import matplotlib as mpl
import matplotlib.pyplot as plt
widget_01 = widgets.HTML("<p>Hello, world</p>")
widget_02 = widgets.Output(layout=Layout(width='100%'))
widget_03 = widgets.Output(layout=Layout(width='100%'))
with widget_02:
widget_02.clear_output(wait=True)
plt.ioff() # "turn off interactive mode so figure doesn't show"
fig = plt.figure(figsize=(10,1), dpi=90)
fig.canvas.toolbar_visible = False
ax = fig.add_subplot(111)
ax.plot([0,1,2], [0,1,2])
plt.ion() # "figure still doesn't show"
display(fig.canvas) # "It's the canvas attribute that is the interactive widget, not the figure"
myvbox = widgets.VBox([
widget_01,
widget_02,
widget_03
],)
display(myvbox)
with widget_03:
IPython.display.clear_output(True)
display(widgets.HTMLMath("<p>In the next episode...</p>"))
在 ax.plot([0,1,2], [0,1,2])
之后调用 plt.show()
为我解决了你的问题。
请参阅下面的代码:
import IPython.display
from IPython.display import display
from ipywidgets import widgets, Layout
import matplotlib as mpl
import matplotlib.pyplot as plt
widget_01 = widgets.HTML("<p>Hello, world</p>")
widget_02 = widgets.Output(layout=Layout(width='100%'))
widget_03 = widgets.Output(layout=Layout(width='100%'))
with widget_02:
IPython.display.clear_output(True)
fig = plt.figure(figsize=(10,1), dpi=90)
fig.canvas.toolbar_visible = False
ax = fig.add_subplot(111)
ax.plot([0,1,2], [0,1,2])
plt.show()
myvbox = widgets.VBox([
widget_01,
widget_02,
widget_03
],)
display(myvbox)
with widget_03:
IPython.display.clear_output(True)
display(widgets.HTMLMath("<p>In the next episode...</p>"))
输出如下所示:
这太他妈烦人了...使用:
Python 3.8.10 (default, Sep 28 2021, 16:10:42) [GCC 9.3.0]
matplotlib 3.5.0
ipywidgets 7.6.5
jupyter 1.0.0
所以,考虑这个例子:
import IPython.display
from IPython.display import display
from ipywidgets import widgets, Layout
%matplotlib widget
import matplotlib as mpl
import matplotlib.pyplot as plt
widget_01 = widgets.HTML("<p>Hello, world</p>")
widget_02 = widgets.Output(layout=Layout(width='100%'))
widget_03 = widgets.Output(layout=Layout(width='100%'))
with widget_02:
IPython.display.clear_output(True)
display(widgets.HTMLMath("<p>Try equation: $x_y = y_x$</p>"))
myvbox = widgets.VBox([
widget_01,
widget_02,
widget_03
],)
display(myvbox)
with widget_03:
IPython.display.clear_output(True)
display(widgets.HTMLMath("<p>In the next episode...</p>"))
所以,我有一个“Vbox”,它有三个元素,“widget_01”,“widget_02”,“widget_03”;这三个元素放在一个列表中,它(不像字典)有一个顺序,所以我可以指望“widget_01”是“第一”,“widget_02”是“第二”,等等.由于这是一个“VBox”,即 Vertical Box,我希望列表中的“第一个”项目呈现在顶部,它下面的“第二个”项目(即在中间),以及等等。
事实上,这就是最简单情况下的输出结果:
好的,很酷 - 现在,让我们将“widget_02”变成 matplotlib widget
:
import IPython.display
from IPython.display import display
from ipywidgets import widgets, Layout
%matplotlib widget
import matplotlib as mpl
import matplotlib.pyplot as plt
widget_01 = widgets.HTML("<p>Hello, world</p>")
widget_02 = widgets.Output(layout=Layout(width='100%'))
widget_03 = widgets.Output(layout=Layout(width='100%'))
with widget_02:
IPython.display.clear_output(True)
fig = plt.figure(figsize=(10,1), dpi=90)
fig.canvas.toolbar_visible = False
ax = fig.add_subplot(111)
ax.plot([0,1,2], [0,1,2])
myvbox = widgets.VBox([
widget_01,
widget_02,
widget_03
],)
display(myvbox)
with widget_03:
IPython.display.clear_output(True)
display(widgets.HTMLMath("<p>In the next episode...</p>"))
好吧,现在 - 无论出于何种原因 - “widget_02”(成为情节)不再位于中间,而是最后(底部):
我的意思是,我确定 update “widget_03” 在我更新绘图后 - 但我希望 VBox 保持小部件的顺序?
所以 - 如果我在同一个 VBox 中更新不同的小部件,我如何才能按照它在 ipywidgets VBox 中列出的顺序呈现 Matplotlib 小部件,even渲染情节?
好的,我在这里找到了解决方案:Displaying a previously created Matplotlib figure in a widget · Issue #203 · matplotlib/ipympl,看来...
事实证明问题不是“控制位置”本身,而是:
- 事实上
fig = plt.figure...
调用实际上会自行产生输出,而不管 (with
) 输出上下文;可以通过plt.ioff()
禁用 matplotlib 交互模式来防止
- 事实上,要显示交互式 matplotlib 小部件,我们应该
display(fig.canvas)
(不仅仅是display(fig)
)
所以,在 OP 中,甚至没有 display(fig)
- 所以 matplotlib 小部件的整个输出都是由于 fig = plt.figure...
调用。
因此,要获得所需的输出,如 VBox 中指定的那样(widget_01 文本在顶部,widget_02 绘图在中间,widget_03 文本在底部):
...可以使用以下更正后的代码:
import IPython.display
from IPython.display import display
from ipywidgets import widgets, Layout
%matplotlib widget
import matplotlib as mpl
import matplotlib.pyplot as plt
widget_01 = widgets.HTML("<p>Hello, world</p>")
widget_02 = widgets.Output(layout=Layout(width='100%'))
widget_03 = widgets.Output(layout=Layout(width='100%'))
with widget_02:
widget_02.clear_output(wait=True)
plt.ioff() # "turn off interactive mode so figure doesn't show"
fig = plt.figure(figsize=(10,1), dpi=90)
fig.canvas.toolbar_visible = False
ax = fig.add_subplot(111)
ax.plot([0,1,2], [0,1,2])
plt.ion() # "figure still doesn't show"
display(fig.canvas) # "It's the canvas attribute that is the interactive widget, not the figure"
myvbox = widgets.VBox([
widget_01,
widget_02,
widget_03
],)
display(myvbox)
with widget_03:
IPython.display.clear_output(True)
display(widgets.HTMLMath("<p>In the next episode...</p>"))
在 ax.plot([0,1,2], [0,1,2])
之后调用 plt.show()
为我解决了你的问题。
请参阅下面的代码:
import IPython.display
from IPython.display import display
from ipywidgets import widgets, Layout
import matplotlib as mpl
import matplotlib.pyplot as plt
widget_01 = widgets.HTML("<p>Hello, world</p>")
widget_02 = widgets.Output(layout=Layout(width='100%'))
widget_03 = widgets.Output(layout=Layout(width='100%'))
with widget_02:
IPython.display.clear_output(True)
fig = plt.figure(figsize=(10,1), dpi=90)
fig.canvas.toolbar_visible = False
ax = fig.add_subplot(111)
ax.plot([0,1,2], [0,1,2])
plt.show()
myvbox = widgets.VBox([
widget_01,
widget_02,
widget_03
],)
display(myvbox)
with widget_03:
IPython.display.clear_output(True)
display(widgets.HTMLMath("<p>In the next episode...</p>"))
输出如下所示: