holoviz / panel

Panel: The powerful data exploration & web app framework for Python
https://panel.holoviz.org
BSD 3-Clause "New" or "Revised" License
4.77k stars 519 forks source link

Provide access to Panels power in Streamlit #1074

Open MarcSkovMadsen opened 4 years ago

MarcSkovMadsen commented 4 years ago

I don't know if you are interested, but if you are you can actually enable the use of Panel in Streamlit. I think there would only be small details to solve.

Try running the below app.py file with streamlit run app.py

import altair as alt
import holoviews as hv
import holoviews.plotting.bokeh
import hvplot.pandas
import pandas as pd
import panel as pn
import plotly
import plotly.express as px
import streamlit as st
from bokeh.plotting import figure

pn.config.sizing_mode = "stretch_width"
pn.extension()
pn.extension("vega")
pn.extension("plotly")

data = {"x": [1, 2, 3], "y": [1, 2, 3]}
dataframe = pd.DataFrame(data)

intro = """
[Panel](https://panel.holoviz.org/index.html#) is a framework for creating awesome analytics apps
in Python. It provides a strong integration to the [HoloViz](http://holoviz.org/) ecosystem and many
other python packages.

Panel is a competing framework to Streamlit, but **Panel can also make Streamlit more
awesome**.

Panel is build on top of [Bokeh](https://docs.bokeh.org/en/latest/) and some of it's powers can
actually be used in Streamlit via `st.bokeh_chart`.

The key to use `st.bokeh_chart` is to convert the *Panel component* to a *Bokeh model* using
the method `.get_root()`.

You can use Panel in Streamlit to

- **layout objects** like plots into Columns, Rows, Tabs and Grids.
- **style objects**
    - You can better control the size and color of the components
    - You can specify css classes and use css to style
- get access to **additional cool python libraries** like
[VTK](https://panel.holoviz.org/reference/panes/VTK.html#panes-gallery-vtk).
    - Soon you will even be able to get access to all ipython widgets.
- use **Javascript** in your application.
- and so much more

What you cannot do in Streamlit (without a lot of hacks) is to react to events in the browser like
clicking a table or chart or changing the value of a Panel widget.

Visit the sister site [awesome-panel.org](https://awesome-panel.org) or some of the official
resources like the [Reference Gallery](https://panel.holoviz.org/reference/index.html) and the
[App Gallery](https://panel.holoviz.org/gallery/index.html) for more inspiration.

![Awesome-panel.org](https://github.com/MarcSkovMadsen/awesome-panel/blob/master/assets/images/awesome-panel-full-branded.gif?raw=true)
![Reference Gallery](https://github.com/MarcSkovMadsen/awesome-streamlit/blob/master/gallery/panel_experiments/panel_reference_gallery.png?raw=true)
"""

intro_pane = pn.pane.Markdown(intro, name="Introduction")

hvplot_plot = dataframe.hvplot(x="x", y="y")
hvplot_pane = pn.pane.HoloViews(hvplot_plot, name="Holoviews Plot")

altair_plot = (
    alt.Chart(dataframe).mark_line().encode(x="x", y="y").properties(width="container", height=400)
)
altair_pane = pn.pane.Vega(altair_plot, name="Altair Plot")

plotly_plot = px.line(dataframe, x="x", y="y")
plotly_pane = pn.pane.Plotly(plotly_plot, name="Plotly Plot")

fig = figure()
fig.scatter([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [0, 1, 2, 3, 2, 1, 0, -1, -2, -3])

gspec = pn.GridSpec(sizing_mode="stretch_both", max_height=800, name="GridSpec")

gspec[0, :3] = pn.Spacer(background="#FF0000")
gspec[1:3, 0] = pn.Spacer(background="#0000FF")
gspec[1:3, 1:3] = fig
gspec[3:5, 0] = hv.Curve([1, 2, 3])
gspec[
    3:5, 1
] = "https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png"
gspec[4:5, 2] = pn.Column(
    pn.widgets.FloatSlider(), pn.widgets.ColorPicker(), pn.widgets.Toggle(name="Toggle Me!")
)

if st.checkbox("Only hv_plot?"):
    tabs = pn.Tabs(hvplot_pane)
else:
    tabs = pn.Tabs(intro_pane, hvplot_pane, altair_pane, plotly_pane, gspec)

st.bokeh_chart(tabs.get_root())

You will see it works as long as you are using hv_plot only.

image

If you uncheck you get errors like the below.

image

If the technical problems are solved it could look like

image

I'm running Streamlit 0.55 and Panel 0.8.0.

My guess is that it's actually possible to do more. Both Streamlit and Panel are running on the Tornado server so my guess is that all the callback/ reactive power of Panel could be turned on in Streamlit.

philippjfr commented 4 years ago

@MarcSkovMadsen This may just work now, if not it may work if we enable CDN resources.

Michelpayan commented 4 years ago

Hi, @MarcSkovMadsen I just copied exactly what you did and run it but I got the following, do you know how can it be fixed?:

You are generating standalone HTML/JS output, but trying to use real Python callbacks (i.e. with on_change or on_event). This combination cannot work.

Only JavaScript callbacks may be used with standalone output. For more information on JavaScript callbacks with Bokeh, see:

https://docs.bokeh.org/en/latest/docs/user_guide/interaction/callbacks.html

Alternatively, to use real Python callbacks, a Bokeh server application may be used. For more information on building and running Bokeh applications, see:

https://docs.bokeh.org/en/latest/docs/user_guide/server.html
SamuelBradley commented 2 years ago

I would really like to see this functionality in streamlit. There is one use case where client-server bokeh/panel/holoviz is almost essential and that is streaming large raster data in an interactive plot with Datashader. I have 2 apps already that need this functionality which I would really like to build with streamlit. I assume this may require running/embedding a bokeh server, which is something I've been able to do in the past with Django

jbednar commented 2 years ago

You might want to raise a corresponding issue on the streamlit repo and link it here, as there may be changes needed at either end to make it work smoothly.

robna commented 2 years ago

Is this something that someone started on? I would see it as a brilliant feature if panel and streamlit could be fused that way to provide the benefits of both. For instance when plotting data with altair in panel within a streamlit app, selections on the chart could be funnelled back, e.g. to filter data etc. This is currently not possible using streamlit alone (at least not for sophisticated altair charts)

MarcSkovMadsen commented 2 years ago

Hi @robna

I can't see how the Streamlit architecture could enable something like datashader. And with the 2023 roadmap where they want to move away from having state on the server it would get even more difficult.

But try requesting this on the Streamlit GitHub.

jbednar commented 2 years ago

There are a lot of different ways to handle state, but at least plotly Dash supports Datashader using a stateless model: https://dash.plotly.com/holoviews#visualizing-large-datasets-with-datashader

Being stateless means being unable to use certain optimizations that rely on intermediate state being held on the server, but apart from performance the same UI can be presented even if the server is stateless.

robna commented 2 years ago

thx Marc and jbednar, actually since I posted last time I have read a bit or two about Panel (which I have not been exposed to before). So my resume is in fact that, it would make more sense to "translate" my apps completely from streamlit to panel, as I think the advantages outweigh the effort ;)