question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

display `print` in callbacks in the notebook

See original GitHub issue
import matplotlib.pyplot as plt

fig, ax = plt.subplots()
n = 0

def printer(event):
    global n
    print(f'in event {event}')
    n += 1
 

fig.canvas.mpl_connect('button_press_event', printer)

when run in IPython prints out to stdout on every mouse click. In jlab + ipympl the prints don’t show up anywhere I can find…

From https://ipywidgets.readthedocs.io/en/stable/examples/Output Widget.html it looks like this can work via:

output = widgets.Output()
display(fig.canvas, output)

n = 0
def printer(event):
    global n
    with output:
        print(f'in event {event}')
    n += 1
    
fig.canvas.mpl_connect('button_press_event', printer)

but I suspect there is a way for this to work automatically…

Issue Analytics

  • State:open
  • Created 4 years ago
  • Reactions:1
  • Comments:8 (5 by maintainers)

github_iconTop GitHub Comments

2reactions
tacaswellcommented, Jul 7, 2019

A slightly more thought out version:

'''
make sure prints in callbacks make it to the notebook

See https://ipywidgets.readthedocs.io/en/stable/examples/Output%20Widget.html

    By default, calling `print` in a ipywidgets callback results in the output
    being lost (because it is not clear _where_ it should go).  You can explictily
    capture that the text to a given output area using at Output widget.

This is a wrapper for `plt.subplots` that makes sure
  a) an ipywidgets.widgets.Output is created with each Figure
  b) the `mpl_connect` on the canvas is monkey-patched such that all
     user callbacks run in a context where the stdout is captured and sent

to that output area.
'''

import matplotlib.pyplot as plt


def _monkey_patch_pyplot():
    import matplotlib.pyplot as plt
    import functools
    from IPython.display import display
    import ipywidgets as widgets
    import weakref

    @functools.wraps(plt.figure)
    def figure(*args, **kwargs):
        fig = figure._figure(*args, **kwargs)
        fig._output = output = widgets.Output()
        display(output)

        orig_mpl_connect = fig.canvas.mpl_connect

        @functools.wraps(orig_mpl_connect)
        def mpl_connect(key, cb, **kwargs):
            # try to use a WeakMethod to make sure we don't keep objects alive
            # to match the behavior of the base mpl_connect
            try:
                r = weakref.WeakMethod(cb)
            except TypeError:
                def r():
                    return cb

            def wrapper(*args, **kw):
                cb = r()

                with output:
                    if cb is not None:
                        cb(*args, **kw)

            orig_mpl_connect(key, wrapper, **kwargs)

        # mokeny patch the canvas
        fig.canvas.mpl_connect = mpl_connect
        return fig

    # stash the orginal
    figure._figure = plt.figure
    # monkey patch pyplot (!?)
    plt.figure = figure
    plt._print_hacked = True


# make sure we only do this once!
if getattr(plt, '_print_hacked', False):
    ...
else:
    _monkey_patch_pyplot()

# clean up after our selves and do not polute the user's namespace
del _monkey_patch_pyplot
del plt

0reactions
jasongroutcommented, Aug 20, 2021

But this does not. It shows “hello 1” in the global log widget. But “hello 2” is never shown.

It would be interesting to see if “hello 2” gets transmitted to the frontend over the websocket connection. If it does, there’s probably a change in jupyterlab we could make to get it into the log.

In general, running code outside of the framework of the kernel execute or comm messages (like in this async case) messes with the output capturing and redirection that the ipython kernel does.

Read more comments on GitHub >

github_iconTop Results From Across the Web

callback function doesn't print, unless ran by Jupyter
I call an API with a callback function that prints what comes out of the API call. If I run this code in...
Read more >
Widget Events — Jupyter Widgets 7.6.2 documentation
The callback will be called with one argument, the clicked button widget ... To capture print s (or any other kind of output)...
Read more >
Part 3. Basic Callbacks | Dash for Python Documentation | Plotly
Graph component to display new data. We could also update the style of a component or even the available options of a dcc.Dropdown...
Read more >
Writing your own callbacks | TensorFlow Core
Callbacks are useful to get a view on internal states and ... print("Start epoch {} of training; got log keys: {}".format(epoch, keys))
Read more >
Using with Jupyter — Bokeh 2.4.1 Documentation
To display Bokeh plots inline in a classic Jupyter notebook, ... connecting plot events and Bokeh's built-in widgets directly to Python callback code....
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found