Hey all!
I made streamlit-observable
, a custom component for rendering Observable notebooks into Streamlit apps. I’ve been wanting this feature in Streamlit for quite some time, so I was pretty excited when Streamlit launched custom components!
If you’re not familiar with Observable notebooks, they’re reactive client-side Javascript notebooks that are really great for making custom data visualizations, especially with D3. There’s a nice community around it, and a ton of examples that you can plug into and remix without much effort. Every notebook is comprised of cells, that each depend on each other to create a DAG of cells that you can hook into, allowing you to inject your own data, configuration, or styling into charts, maps, or animations!
streamlit-observable
does most of the heavily lifting around dealing with the Observable runtime, and offers small API that allows you to redefine cells, observe cell values when they change, and configure how to render them. This was built on top of the standard Streamlit Custom Component typescript template, meaning each embed is isolated in its own iframe.
You can pip install streamlit-observable
to start using it right away, and here’s the project on Github.
Here’s an example Streamlit app that shows off all the cool ways you can use streamlit-observable
. If you don’t want to click there, here’s a few of my favorite examples:
Bar Chart Race with Wikipedia pageviews
import streamlit as st
from streamlit_observable import observable
@st.cache
def get_wiki_data():
# A bunch of code...
return df
df_wiki = get_wiki_data()
observable("Wiki Bar Chart Race",
notebook="d/9bbcce8f2f6834d7",
redefine={
"rawData": df_wiki.to_csv(),
"duration": 200,
"n": 10
},
targets=["chart", "viewof keyframe", "update"],
hide=["update"]
)
Voronoi Map of Trader Joe’s Locations
import streamlit as st
from streamlit_observable import observable
@st.cache
def get_trader_joes():
# a lot of code...
return df
df = get_trader_joes()
observable("Trader Joes Voronoi Map",
notebook="@mbostock/u-s-voronoi-map-o-matic",
targets=["map"],
redefine={
"data": df[["longitude", "latitude", "name"]].to_dict(orient="records")
}
)
Drawing on a Canvas
observers = observable("Example Drawing Canvas",
notebook="@d3/draw-me",
targets=["viewof lineWidth", "viewof strokeStyle", "undo", "viewof strokes"],
observe=["strokes"]
)
Selecting U.S. Counties on a Map
observers = observable("County Brush",
notebook="d/4f9aa5feff9761c9",
targets=["viewof countyCodes"],
observe=["selectedCounties"]
)
selectedCounties = observers.get("selectedCounties")