Inspired by a tweet in the Streamlit community I wanted to demonstrate that BI Dashboards with cross filtering are very easy to develop with the HoloViz ecosystem compared to the combination of Streamlit, Plotly, custom components, session state and experimental features in the tweet.
The complexity of the Streamlit example is just another indication to me that Streamlit not the easiest way … for lots of use cases including crossfiltering.
In the process I learned HoloViews linked brushing (cross filtering) bar charts/ histograms only works for numerical and datetime data. So a trick was to convert categorical data like day
to numerical data and then just display the string
labels on the axis.
import numpy as np
import pandas as pd
import panel as pn
import plotly.express as px
from holoviews.selection import link_selections
import hvplot.pandas
pn.extension(sizing_mode="stretch_width", template="fast")
pn.state.template.param.update(
site="Awesome Panel", title="Interactive Data Exploration w. Cross Filtering"
)
hvplot.extension("bokeh") # bokeh or plotly
DAY_TO_INT = {"Thur": 4, "Fri": 5, "Sat": 6, "Sun": 7,}
DAY_TICKS = [(val, key) for key, val in DAY_TO_INT.items()]
HEIGHT = 400
def load_dataset():
df = px.data.tips()
df["count"] = 1
df["size"] = df["size"].astype(str)
df["day_int"] = df["day"].map(DAY_TO_INT)
return df
df = pn.state.as_cached("tips", load_dataset)
bill_to_tip_figure = df.hvplot.scatter(
x="total_bill", y="tip", responsive=True, tools=["box_select"]
)
day_figure = df.hvplot.hist(
"day_int", xlabel="day", ylabel="number of orders", responsive=True
).opts(xticks=DAY_TICKS)
size_to_time_figure = df.sort_values("size").hvplot.heatmap(
x="size", y="time", C="count", reduce_function=np.sum, colorbar=False, responsive=True
)
selections = link_selections.instance()
layout = pn.panel(selections(bill_to_tip_figure + size_to_time_figure + day_figure), height=HEIGHT)
pn.Column(
f"## Tips Dataset ({len(df)} orders)", layout,
"**Data Apps the easy way**: No need for session state, custom components, experimental features, ..."
).servable()
To run it use
panel serve name_of_script.py
I think this code is short, much simpler and works much, much better than the streamlit code which requires a lengthy youtube video to explain.
If any one knows how to make the bars wider let me know. Thanks.