Could we have Plotly FigureWidget support?

Issue:

I have been creating dashboards for exploring data, and finding relations between each other. I have been using Power BI, but it has a lot of limitations, gets very frustrating and there isn’t much flexibility in what you can make. I want to use Streamlit instead (else Panel), but a requirement I have is interactions between plots - so selecting an area of a scatter plot, or selecting a slice of a pie chart should be able to update tables and the rest of the plots. I already have plotly experience, in addition to a bank of plotly and streamlit functions, so I would prefer to use streamlit over Panel, but this interactivity isn’t currently easy to do with Streamlit.

However, plotly have recently released a FigureWidget class which can majorly help with this as it can output the indices of the selected points. However this doesn’t seem to be explicitly supported by Streamlit.

I have included the relevant links:

Question:

a) is there any plans on being able to input a FigureWidget into a streamlit.plotly_chart object or similar? As you can then add callbacks to this FigureWidget object, such as update the input dataframe on selection, using widget_object.data[0].on_selection(fn_to_cut_down_df).
b) I noticed that Streamlit Components has been launched, which seems like it may make this kind of thing possible, but currently you need to link it to a frontend file. Is there any way to add a streamlit component which is this FigureWidget object, which can then be used in the above way? Or would it be simple to create a component to pull out the df indices selected on the plot and send them to Python?

I don’t have any React or JS experience sadly, I’ve mainly used Python - but I’m happy to learn, I’m just a little stuck on where to start.

I am using Streamlit 0.63.0, with Python 3.7.7 with miniconda. Additionally I use Windows 10 and Google Chrome.

Thanks in advance!

2 Likes

Hi @givemecoffee,

I’ve been thinkering too with the idea of a plotly scatterplot where you can select some points and return their indices to filter data for the next plot. I don’t have a definitive, “generic” solution for this, but if you’re building only for your specific needs it should be possible to use Components to control Plotly.js plots directly.


As an introduction, plotly.py is a Python client which generates a JSON spec that plotly.js consumes to render a plot. Actually streamlit.plotly_graph dumps the JSON spec from the Figure and passes it to react-plotly for rendering :slight_smile: . You could easily replicate this using Streamlit components to train yourself !

Then there’s FigureWidget which is another Python class that renders Plotly graphs but in the ipywidgets model. At first glance, when rendering FigureWidget, a plotly.js graph is mounted and communication between the plotly.js plot and Python FigureWidget is done through ipywidgets’ event model.
There’s no “dump Python class in a JSON format to pass it to plotly.js for rendering”. FigureWidget is tightly coupled to ìpywidgets event model so that when you do widget_object.data[0].on_selection(fn_to_cut_down_df) it sends a custom event to plotly.js through ipywidgets, then the JS plot updates itself with this info.
You could try and extract all the callbacks events from FigureWidget to try and pass them to react-plotly with Streamlit Components but … I’m not sure, it looks time-consuming and demanding at first glance :confused: but that may be my ignorance of how ipywidgets work.


For now the faster but very specific approaches would be :

  1. You can build a single specific Plotly.js component with a lasso selection event inside, have Python send a dataframe through Components to your lasso interactive plot and return indices out from the selection, as you suggest actually, and then use those indices to filter data for the next plot.
  2. You could build one single component which contains all your plotly.js plots and any cross interactivity in JS, so you encapsulate everything in a single Component with multiple plots.

I don’t have an answer for integrating ipywidgets in Streamlit Components, because I don’t know much how we can capture their event system. We have opened a discussion on this here Ipywidgets (WIP) if you have info on this. If anyone has a better idea I’m interested too :slight_smile:

Fanilo

2 Likes

This would help me too!

2 Likes

Thank you for the reply - it has actually helped for me to understand how the different bits of plotly work :slight_smile:

I’ll give the first option a go, when I get a chance at least - would you suggest editing the source plotly.js file? I’d better get learning JS :wink:

If I get anywhere I’ll update you and share the code :smile:

Zac

1 Like

:+1:t4: You can follow the bidirectional tutorial from the docs.
You can install plotly.js through npm with npm add plotly.js when in the frontend folder, then import it in your js file. Hopefully the plotly.js doc is enough for you to render a JSON spec from plotly.py

Don’t hesitate to take a good look at all the examples from the components-template + source code from any component from the gallery :slight_smile:

3 Likes

Hey @givemecoffee I made you a quick tutorial if you want XD

8 Likes

Oh this looks great, I’ll take a look now - thanks for all your links! I’ve taken a look through the bidirection tutorial, but it’s confused me a bit, mainly because I’m just not used to anything other than pure python or python + SQL, so I’ll look through the plotly.js doc and hopefully that may help!

Thanks again :smiley: That tutorial looks great

1 Like

This tutorial rocks! I like how you use react hooks to keep things simple and clean!

I’m not 100% sure but I think you could use fig.to_dict() to transmit data and drop that JSON.parse() on javascript-side, and you may also do that to_dict() call automatically inside your function wrapper to show that it simplifies the usage of the final function.

Other than that, I hope it’ll show that making components is not that hard, even with no javascript nor react experience! And I’m looking forward to reading your incoming frontend/React tutorial :smiley:

3 Likes

Eheh I think that was my first try but I remember I got a numpy.ndarray not serializable :confused: so resorted to stringifying the json instead. Good idea for the to_dict in the wrapper I’ll edit that part :slight_smile:
Anyway thanks y’all xD I wrote this on the fly without checking too much if it even made sense so I’m happy it’s actually helpful

4 Likes

Great tutorial @andfanilo, thanks!
Is there a way to pip install it?

1 Like

Hey @dbbz,

I haven’t built a wheel for it yet but the source code is available if you want to do it yourself : https://github.com/andfanilo/streamlit_scatterplot_selection. I’ll do it in the week.

Also would recommend you the Bokeh version which is pip installable and much maintained :slight_smile:

Fanilo

Thanks a lot @andfanilo :slight_smile:

The wheel is now available on the Github project, along with an example in the README.

There’s probably some bugs (I didn’t touch this for months XD) so don’t hesitate to put an issue on the repo.

Good luck!
Fanilo

Nice :slight_smile: THanks @andfanilo!
For some reason, it doesn’t print the selected points on my machine(s). But that also concerns other components, so the issue might be elsewhere.
Thanks again @andfanilo you’re awesome!

This is how HoloViz Panel did it. Quite intuitive if you ask me…

1 Like