This is so damn irritating... using:
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
So, consider this example:
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>"))
So, I have a "Vbox", which has three elements, "widget_01", "widget_02", "widget_03"; these three elements are put in a list, which (unlike dict) has an order, so I can count on "widget_01" being "first", "widget_02" being "second", and so on. And since this is a "VBox", that is, Vertical Box, I'd expect the "first" item in the list to be rendered on top, the "second" item below it (that is, in the middle), and so on.
And indeed, that is how the output looks like in the simplest case:
Ok, cool - now, let's just make "widget_02" into 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>"))
Well, now - for whatever reason - "widget_02" (which became a plot) is not in the middle anymore, but is instead last (at bottom):
I mean, I sure update "widget_03" after I update the plot - but I'd expect the VBox to keep the order of widgets?
So - how can I have a Matplotlib widget rendered in the order it is listed into an ipywidgets VBox, even if I update a different widget in the same VBox after I have rendered the plot?
CodePudding user response:
Calling plt.show()
after ax.plot([0,1,2], [0,1,2])
solves your issue for me.
See code below:
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>"))
And the output looks like that:
CodePudding user response:
... the following corrected code can be used:
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>"))