# Matplotlib draw in console instead of cell output when call in widget event callback

**URL:** <https://discourse.jupyter.org/t/matplotlib-draw-in-console-instead-of-cell-output-when-call-in-widget-event-callback/22178>\
**Category:** JupyterLab\
**Tags:** help-wanted\
**Created:** [October 31, 2023, 8:24am UTC](https://discourse.jupyter.org/t/matplotlib-draw-in-console-instead-of-cell-output-when-call-in-widget-event-callback/22178 "2023-10-31T08:24:48Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![link89](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.jupyter.org/link89/32/11472_2.png) [@link89](https://discourse.jupyter.org/u/link89)\
**Post date:** [October 31, 2023, 8:24am UTC](https://discourse.jupyter.org/t/matplotlib-draw-in-console-instead-of-cell-output-when-call-in-widget-event-callback/22178/1 "2023-10-31T08:24:48Z")

</div>

Here is the code to reproduce the problem

```python
%matplotlib inline
import matplotlib.pyplot as plt
import asyncio
import numpy as np

def wait_for_change(widget, value):
    future = asyncio.Future()
    def getvalue(change):
        # make the new value available
        future.set_result(change.new)
        widget.unobserve(getvalue, value)
    widget.observe(getvalue, value)
    return future
    
def draw(scale):
    x = np.arange(0, scale*np.pi,0.1) # start,stop,step
    y = np.sin(x)
    plt.plot(x,y)
    plt.show()

from ipywidgets import IntSlider
slider = IntSlider()

async def f():
    for i in range(100):
        print('did work %s'%i)
        x = await wait_for_change(slider, 'value')
        draw(x)
        print('async function continued with value %s'%x)
asyncio.ensure_future(f())
slider

```

The expected behavior is to draw image in cell, but turn out in console log instead. Is there anything I can do to fix this problem?

 ![image](https://canada1.discourse-cdn.com/flex031/uploads/jupyter/original/2X/d/d941929a9fe7a3f2a75695ffbf2b644c17f840b0.png)

---

<div class="post-metadata">

**Author:** ![fomightez](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.jupyter.org/fomightez/32/495_2.png) [@fomightez](https://discourse.jupyter.org/u/fomightez)\
**Post date:** [October 31, 2023, 12:26pm UTC](https://discourse.jupyter.org/t/matplotlib-draw-in-console-instead-of-cell-output-when-call-in-widget-event-callback/22178/2 "2023-10-31T12:26:53Z")

</div>

Actually there’s several issues going on here.

I think the main one is that now with ipywidgets explicitly handling the output is necessary to control what goes to `output` vs. the Log console. You’ve noticed this using JupyterLab; however, since Jupyter Notebook 7+ is built on the same tech, it is necessary there now, too.

The second half of my posts [here](https://discourse.jupyter.org/t/jupyterlab-output-in-log-rather-than-cell/13419/2) covers what you need to do to improve your code to current best practice to control output.  
Additional posts addressing this practice with ipywidgets can be found [here](https://discourse.jupyter.org/search?q=ipywidgets%20log%20%40fomightez).

Additionally, I think though that matplotlib isn’t compatible with aysncio? I may completely misinterpreting a comment [here](https://discourse.jupyter.org/t/threading-with-matplotlib-and-ipywidgets/14674/2):

> [@Threading with Matplotlib and ipywidgets](https://discourse.jupyter.org/t/threading-with-matplotlib-and-ipywidgets/14674/2):
>
> Here’s a basic pattern: it delegates the asyncio stuff to an interval-based loop. Ideally, the `do_work` would _also_ be `async`, but matplotlib _isn’t_.

* * *

There always seems to be multiple ways to do these things; however, I’m not seeing the need for asyncio here. You can use ipywidgets `interactive` and if you want the print prompts you include you can add them, sending them to the `Output` widget, see [here](https://ipywidgets.readthedocs.io/en/stable/examples/Output%20Widget.html). I think my code below addresses **maybe** much of what you were trying to do in your code example. I think you wanted to limit the user to repeating the plot 100 times? I didn’t implement that because I wasn’t following quite if that was the purpose or if it was necessary. (I think I can easily add it but not quite getting if it was needed and not wanting to slide 100 times to test it, I left it out for now.) Feel free to clarify and if my implementation lacks something else, please let me know?  
It is largely based on [here](https://stackoverflow.com/a/74551129/8508004):

```python
import matplotlib.pyplot as plt
import ipywidgets as widgets
import numpy as np
from IPython import display 

out = widgets.Output()

i = 0

def PlotAndNote(scale):
    global i
    x = np.arange(0, scale*np.pi,0.1) # start,stop,step
    y = np.sin(x)
    plt.plot(x,y)
    with out:
        if scale == 0:
            print('did work %s'%i)
            i+=1
        else:
            print('did work %s'%i)
            print('plotting continued with value %s'%scale)
            i+=1

scale_slider=widgets.IntSlider(min=0,max=100,value=0, continuous_update = False) #Create our intslider such that the range is [0,100] and default is 0; and use `continuous_update = False` to restrict execution to mouse release events,see https://ipywidgets.readthedocs.io/en/stable/examples/Using%20Interact.html#disabling-continuous-updates

gui = widgets.interactive(PlotAndNote, scale=scale_slider) #Create our interactive graphic with the slider as the argument
out_vbox = widgets.VBox([gui,out])
out_vbox

```

I left out `%matplotlib inline` as I think that is the default these days.

You can see the code work [in temporary Jupyter sessions with ipywidgets installed already spawned via MyBinder.org by clicking here](https://notebooks.gesis.org/binder/v2/gh/fomightez/communication_voila/HEAD).

---

<div class="post-metadata">

**Author:** ![link89](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.jupyter.org/link89/32/11472_2.png) [@link89](https://discourse.jupyter.org/u/link89)\
**Post date:** [November 1, 2023, 2:33am UTC](https://discourse.jupyter.org/t/matplotlib-draw-in-console-instead-of-cell-output-when-call-in-widget-event-callback/22178/3 "2023-11-01T02:33:08Z")

</div>

Thank you. I found a work around that works for me by creating figure outside the callback, and pass the handler to the event callback so that it can update the figure by calling the `canvas.draw` method.  
Ref

- [Comprehensive Example — ipympl (matplotlib.org)](https://matplotlib.org/ipympl/examples/full-example.html#changing-a-line-plot-with-a-slider)

But what I hope is for ipywidget to support blocking execution instead of callback, I found some issues on github and I also post one on SO.

- [Question: Block kernel until ipywidget’s initial rendering has completed · Issue #3144 · jupyter-widgets/ipywidgets (github.com)](https://github.com/jupyter-widgets/ipywidgets/issues/3144)
