ipympl
ipympl copied to clipboard
Version 0.5.0+ no longer displays output after widget interaction
I have not labeled this as a "bug report" as I am not sure whether this is a new feature or regression.
I am developing a package for the processing of NMR spectra that makes extensive use of the ipympl backend: https://github.com/NMRPy/nmrpy
As part of this there are a number of widgets (interactive matplotlib graphs) for phasing and peak picking of the NMR spectra. Some of these widgets print output to the cell output area (below the ipympl widget) after user interaction, using simple print() function calls in the code. In some cases further user input is required for which I have made use of an ipywidgets.FloatText() which is then also displayed in the output area.
As of version 0.5.0 this cell output area is no longer displayed. The widget interaction with the ipympl graphs still works but the text output from print() calls and the ipywidgets output are not there.
- Is this intentional or a regression?
- If intentional, is there a way to get the output area back, or an alternative where to direct text output after interaction with a graph (or instantiate an
ipywidgetswidget) so that it is displayed to the user?
This functionality is crucial to my application and currently I am thus stuck with using ipympl<0.5.0. BTW this is using notebook, not jupyterlab.
Thanks for opening an issue.
I am not really sure what could happen here. Could it be that the events that are supposed to print outputs are not triggered since 0.5.0? Are you sure the code is actually running?
If your code is actually running but nothing is displayed: A more robust way to print stuffs in the output under the plot is to use the Output widget from ipywidgets, then you can put your plot and your Output in a box:
from ipywidgets import Output, VBox
out = Output()
# Create figure and fill the output
# Display the figure and the output
display(VBox(children=(fig.canvas, out)))
This would work in classical Jupyter Notebook, in JupyterLab and in Voila. While your solution using prints only works in Jupyter Notebook, and it is quite weak, as the Jupyter Notebook interface does not really know where to put the outputs.
I'm not 100% sure if I've understood this correct, but I believe what you're experiencing is how unless you create a widgets.Output, then use your print function with that Output, and make sure to display() that Output widget, the output won't be created.
I've quickly made an example below, and you can read more in the docs here. It is definitely confusing at first, but quite flexible!
button = ipywidgets.Button(description='Hello there')
output = ipywidgets.Output()
def print_hello(*args):
print('Does not work')
with output:
print('Does work')
button.on_click(print_hello)
display(ipywidgets.HBox([button, output]))

If you're using jupyter lab, you may also notice outputs appearing in the "log" in the status bar at the bottom of the window.
Great minds think alike ;)
Thanks for the quick replies, this has been very helpful!
Minimal example:
class MyFigure:
def __init__(self):
self.fig, self.ax = plt.subplots()
self.ax.plot([1,3,2])
self.fig.canvas.mpl_connect('button_press_event', self.press)
def press(self, event):
x = np.round(event.xdata, 2)
y = np.round(event.ydata, 2)
print('button press coordinates: ', x, y)
mf = MyFigure()
This works in ipympl<0.5 but not in 0.5.0+. I could get it to work with ipywidgets.Output() and this solves my issue. I was just wondering if this change is documented somewhere and that using the Output widget is now required? I was breaking my head trying to figure out why my code was no longer working until I realized ipympl had been updated. What is the rationale? Is the idea that all output will be required to be piped through the Output widget?
Thanks!
Can confirm. In the old ipympl (0.4.x) version the text appears, in the new version it does not. ipywidgets version is the same (7.5.1) in both cases.
I think ipympl is mature enough to justify spending some time on proper documentation (I've said I'd do that before, let's see what I can manage this weekend). But I guess the current issue is about release notes, which is particularly justified since the API (or equivalent to that) is changing with new releases.
What might have changed is the widget extension JavaScript side. I am not sure exactly what made this change.
What is the rationale?
Actually using print without using the Output widget is not really a good practice here.
The Jupyter Notebook interface will try its best to put the result of the print somewhere that makes sense, in your case under the Plot because that's the origin of the callback that printed something. But what do you expect to happen if the plot is displayed multiple times on the Notebook? What the Notebook interface will do in this case: It will put the print result under the last created plot. But that's not really what you want, you want it under all plots.
That's the reason for JupyterLab to not print anything from callbacks, because it does not know under which cell to put the print and takes the decision to put it in the log pane instead.
Using the Output widget allows you to decide where you put the prints., if you display the output widget multiple times the print statement will be dispatched to all outputs. That is more robust than relying on what the interface does (An interface like Voila will just ignore your print statement if you don't use an Output).
I think ipympl is mature enough to justify spending some time on proper documentation
:100: I won't have time this week-end but I can definitely help later.
Thanks for the great explanation - makes sense.
It would be great to have some documentation, agreed! Even if a change like this were mentioned in the release notes it would have helped me a a lot. Having said that I realize that this is an open-source project and people's resources are limited. Unfortunately I don't know enough about ipympl internals to be able to contribute myself.
Thanks - I also benefited from the explanations! I was also puzzled as to why this used to work in the past.
Interestingly however I cannot see the output of print() calls in callback functions even with %matplotlib notebook.