Ipywidgets (WIP)

Hey :wave:

What if Streamlit supported ipywidgets natively? Even complex ones such as bqplot, pythreejs, ipyleaflet and some moreā€¦

Well, that would be great, that would even be a real killer feature, but itā€™s not quite there unfortunately :sweat_smile: Embedding simple widgets was straightforward with this tutorial from ipywidgets documentation. But so far:

  • I can interact with widgets but I donā€™t retrieve any value to use in Streamlit
  • Embedding the aforementioned complex widgets need more work, especially to manage JS dependencies with those CORS issues and JS loaded from localhost:8501/ for some reason :cry:

I was even wondering if spawning an ipython kernel would be better to be as compatible as possible, but Iā€™m not sure of thatā€¦

All of this is still exploratory, but hereā€™s a screenshot showing how simple widget renders into Streamlit.

6 Likes

Agreed, I think this would be a killer feature, but as you mention itā€™s not really clear how the best way to accomplish it might be.

2 Likes

Hi there!

ipywidgets support in streamlit would be great! You would gain many widgets libraries for free.

I think spawning an IPython kernel is not mandatory for streamlit to support ipywidgets. I am one of the main author of another Python kernel for Jupyter that supports ipywidgets and third-party widgets libraries without depending on IPython, itā€™s named xeus-python: https://github.com/jupyter-xeus/xeus-python. So I would say itā€™s possible for you to support them.

Now, it will still be a bit of work to do, both on the back-end and on the front-end. On the back-end youā€™ll need to implement a custom Comm logic, see https://jupyter-notebook.readthedocs.io/en/stable/comms.html#comms. And on the front-end youā€™ll need a Widget Manager that spawns the widgets and deals with the communication with the back-end. For example, there is a JupyterLab widget manager for JupyterLab: https://github.com/jupyter-widgets/ipywidgets/tree/master/packages/jupyterlab-manager.

I might not be able to answer all technical questions about this, I am not really aware of how the Widgets Manager works. But I guess those two links are good starting points for you.

2 Likes

Thanks for following up @martinRenou, itā€™s super helpful as I had a hard time navigating the implementation of the web examples :slight_smile:.

So the custom Comm logic is the part where you can decouple the backend/frontend communication. In my thinking you could not break the back/front sync and manage it manually. If this is possible then it could make things doable :thinking: Iā€™ll try when I have some timeā€¦

So the custom Comm logic is the part where you can decouple the backend/frontend communication

Yes, although this is done in xeus-python by monkey patching IPython. Itā€™s not a great solution but it works.
Basically ipywidgets depends on IPython and ipykernelā€™s Comm implementation (see https://github.com/jupyter-widgets/ipywidgets/blob/b164aa2fe9d0f141d60a6a84a2fca2fa7f426b43/ipywidgets/__init__.py#L22 and https://github.com/jupyter-widgets/ipywidgets/blob/5170757c4e9b93731ac840640ebf5dd499f6d47c/ipywidgets/widgets/widget.py#L12). So you will need to monkey patch those modules prior to import ipywidgets in order to have ipywidgets using your Comm implementation.

2 Likes

Hello @martinRenou, thanks for those details and starting points! Iā€™ll also try to investigate on whatā€™s possible in the following days.

In the screenshot I posted, I used ipywidgetā€™s html manager. Couldnā€™t we use it further instead of implementing a new widget manager? I donā€™t know if there is any limitation with it yet.

The HTML manager is a static rendering of the widget, so there is no communication with the Python back-end, itā€™s only the JavaScript part of the widget.

I suspect youā€™ll want to listen to widget model changes in Python and react on those changes? If not, the HTML manager is enough for you indeed.

1 Like

We also work on Voila, which I like to see as a good competitor to streamlit :wink:

You can see here in the Voila code-base that we reuse the JupyterLab widget manager for rendering widgets: (looks like I am not able to post links anymore on this post, and some of my answers were marked as spam?? :frowning:) youā€™ll find the file I want to point to on the Voila Github repository under voila/js/src/manager.js

I am sure this could be useful for you as well.

Thank you alot! Gonna check this out!

Yes I just saw that, sorry for the disturbance. Apparently you posted too many links with a recent account for Discourse :sweat_smile: I restored your posts but I have to check why you cannot post links anymore.

Hereā€™s the link you wanted to share: https://github.com/voila-dashboards/voila/blob/master/js/src/manager.js

1 Like

Hi All,
Any update on widgets components? pandas profiling is working fine with ā€˜streamlit_pandas_profilingā€™

pywedge package helps to create plots dynamically. trying to embed that with streamlit.
Anyone worked on this stuff .please guide us

Hello @saitej123,

Ipywidgets is something that we all really want to have supported out-of-the-box in Streamlit. Unfortunately it needs a little bit of time and work to get it done.

Streamlit pandas profiling relies on an HTML export function to display profile reports. It doesnā€™t use ipywidgets.

Iā€™m afraid youā€™d need to draw charts by yourself. If that could help you, streamlit supports plotly charts that are used by pywedge as well : https://docs.streamlit.io/en/stable/api.html#streamlit.plotly_chart

2 Likes

Any updates on supporting ipywidets and ipyleaflet? Folium has very limited interactive functionality. There is no way to retrieve drawn shapes on the map programmatically using folium. Please consider supporting ipyleaflet, which provides very rich interactive functionality.

3 Likes

Hereā€™s one way of using ipywidgets with pythreejs:

import pythreejs as THREE

base = THREE.Mesh(
    THREE.BoxBufferGeometry(20, 0.1, 20),
    THREE.MeshLambertMaterial(color='green', opacity=0.5, transparent=True),
    position=(0, 0, 0),
)
cube = THREE.Mesh(
    THREE.BoxBufferGeometry(10, 10, 10),
    THREE.MeshLambertMaterial(color='green', opacity=0.5, transparent=False),
    position=(0, 5, 0),
)

view_width = 800
view_height = 600
target = (0, 5, 0)
camera = THREE.CombinedCamera(position=[60, 60, 60], width=view_width, height=view_height)
camera.mode = 'orthographic'
camera.lookAt(target)
camera.zoom = 4
orbit = THREE.OrbitControls(controlling=camera, target=target)

lights = [
    THREE.PointLight(position=[100, 0, 0], color="#ffffff"),
    THREE.PointLight(position=[0, 100, 0], color="#bbbbbb"),
    THREE.PointLight(position=[0, 0, 100], color="#888888"),
    THREE.AmbientLight(intensity=0.2),
]

scene = THREE.Scene(children=[base, cube, camera] + lights)

renderer = THREE.Renderer(scene=scene, camera=camera, controls=[orbit],
                    width=view_width, height=view_height)


from ipywidgets import embed
snippet = embed.embed_snippet(views=renderer)
html = embed.html_template.format(title="", snippet=snippet)

import streamlit.components.v1 as components
components.html(html, width=view_width, height=view_height)
2 Likes

Using ipywidgets like this will lose the bidirectional functionality.

1 Like