Closed ianhi closed 4 years ago
First off, I totally agree that we should make the documentation clearer. I've been asked to do this previously but haven't quite finished a first draft of it.
There is actually already a kind of "context manager" that you should be using instead of the plt.ion/ioff approach - ipywidgets.widgets.Output
! I was also using your approach until recently. One of the particularly nice things about the Output
widget is that you can do all your "figure generation" in one cell, and show it in a different!
The output widget is a "area" widget that contains other widgets, but is not displayed until it is explicitly so, either by returning it at the end of a notebook cell, or calling the IPython.display.display()
function on it. (The latter is automatically imported as display
in all ipython/jupyter kernels.
So, an similar example to yours becomes the following:
o = widgets.Output()
with o:
plt.figure()
plt.plot([1,2,3])
display(o)
Note that
with widgets.Output() as o:
...
doesn't work, since the object o
is deleted at the end of it.
I haven't looked into whether it might be possible to change that.
I didn't really respond to your suggestion, but I'd be curious what you think, bearing my first reply in mind.
Think of an output widget as a way of capturing output that would normally be displayed in a cell output.
In other words, it is a container for output, not a container for widgets. Naturally, since an output can contain widgets, an output widget can contain widgets alongside text and other rich displays.
The context manager discussion should definitely happen in matplotlib/matplotlib (I left a comment over there already).
The current model that pyplot uses for managing open figures is very tied to desktop GUIs (as that is what we were working with) and the idea that you only have 1 view of it.
If I am understanding this right, the issue is that sometimes you want plt.figure()
to make a stand-alone widget that get put on the screen and other times you want it to make the widget, but not display it because later you are going to manually pack it into a bigger layout?
If I am understanding this right, the issue is that sometimes you want plt.figure() to make a stand-alone widget that get put on the screen and other times you want it to make the widget, but not display it because later you are going to manually pack it into a bigger layout?
Yup! I ran into this when working with XYZT stacks of microscopy images. I have several classes in python module that manage viewing these stacks and for things like per image manual segmentation (lasso selector) or cell labelling. Then these classes all have methods like:
def __init__(self,arr):
"""
inputs
--------
arr : structured array
with attributes, 'pos', 'time', 'z', 'name', 'image (X,Y)'
"""
....
# boring initialization stuff
plt.ioff()
self.fig = plt.figure()
plt.ion()
self.ax = plt.gca()
self.displayed = self.ax.imshow(self.arr['image'][self.t_idx][0])
# boring initialization + defining some control sliders
# other functions
def _ipython_display_(self):
display(widgets.VBox([self.z_slider,self.t_slider,self.fig.canvas]))
There is actually already a kind of "context manager" that you should be using instead of the plt.ion/ioff
I don't think that the output widget is the best way to solve my problem. It certainly works, but I'd prefer for no output to be generated when creating my object rather than to have to capture extraneous output. My bad on not posting an example of my actual use case.
Though, this is great to know about for the original example I posted which I definitely run into when playing around with things in the notebook. It's also interesting to thing about throwing these into a sidecar output.
Why is it preferred to use the output rather than suppress the output? It seems like this makes it more difficult to manipulate the canvas position with various widget layout tools.
I've been asked to do this previously but haven't quite finished a first draft of it.
If you want feedback on a draft I'd be happy to provide some, my learning of all this is fresh enough that I'll bet I remain capable of wildly misinterpreting documentation so I could be a stress test for it...
Context manager has now happened in matplotlib :tada: !
I think it will be included in the 3.4 release. Usage will be:
with plt.ion():
# ...
Often when I'm using the widget backend in jupyterlab and want to do something like define a small layout of ipywidgets and plots I find myself using this pattern:
ioff
andion
to prevent multiple views of the figure showing up. It would be great if more discussion of this was included in the documentation (https://github.com/matplotlib/ipympl/issues/208) and examplesioff
as a context manager at least in the context of this backend. I propsed this on the matplotlib repo https://github.com/matplotlib/matplotlib/issues/17013 but that may not have been the right place for it as it would be useful primarily for this backendCould this backend redefine
ioff
like so:I imagine this occuring in the ipympl
__init__.py
. This would enable the above example to be the slightly cleaner:Another issue where the usage of
ioff
/ion
came up is: https://github.com/matplotlib/ipympl/issues/203 though there was no discussion of the context manager there.Currently I just always import pyplot as plt and just redefine
plt.ioff
to be the above class which works fairly well.