【问题标题】:Controlling order of display in ipywidgets Vbox (when matplotlib widget is used)?控制 ipywidgets Vbox 中的显示顺序(使用 matplotlib 小部件时)?
【发布时间】:2022-01-02 22:07:35
【问题描述】:

这太烦人了...使用:

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”;这三个元素被放在一个列表中,它(与 dict 不同)有一个顺序,所以我可以指望“widget_01”是“第一”,“widget_02”是“第二”,依此类推。并且由于这是一个“VBox”,即垂直框,我希望列表中的“第一个”项目呈现在顶部,它下方的“第二个”项目(即在中间),并且以此类推。

事实上,这就是最简单情况下的输出:

好的,很酷 - 现在,让我们将“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 中的不同小部件,我如何才能让 Matplotlib 小部件按照它在 ipywidgets VBox 中列出的顺序呈现?甚至 /p>

【问题讨论】:

    标签: python matplotlib jupyter-notebook ipython ipywidgets


    【解决方案1】:

    好的,我在这里找到了解决方案: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>"))
    

    【讨论】:

      【解决方案2】:

      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>"))
      

      输出看起来像这样:

      【讨论】:

      • 谢谢 - 我有点惊讶,确实如屏幕截图所示工作;但仔细观察,您没有使用 %matplotlib widget 指令,因此您的解决方案中呈现的图只是一个图像,它不是交互式的。如果您查看我提出的解决方案,就会发现该解决方案保留了 matplotlib 小部件的交互性。
      • 这很好。我删除了它,因为%matplotlib widget 行在我的 google colab 和我的 jupyter notebook 上崩溃了。
      猜你喜欢
      • 2021-04-26
      • 1970-01-01
      • 2020-07-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-24
      • 1970-01-01
      相关资源
      最近更新 更多