HI, I am working on a little widget with holoviews
and panel
- it consists of reading a pandas.dataFrame
and display a curve for each column. The interaction I need is to be able to add/remove columns from the plot. In my real use case there are too many columns so I can’t use the legend interaction already provided by bokeh+holoviews
.
I made a little example that ‘’’ kind of works ‘’’ but I am probably doing it wrong /…
The code is:
import holoviews as hv
import numpy as np
import pandas as pd
import colorcet as cc
import panel as pn
pn.extension()
hv.extension("bokeh")
# generate some data
def get_data():
data = {
"1998": np.random.rand(365),
"1999": np.random.rand(365),
"2000": np.random.rand(365),
"2002": np.random.rand(365),
"2003": np.random.rand(365),
}
df = pd.DataFrame(data, index=range(0, 365))
return df
# utility to help me placing the month label around the 2nd week of each month
def split_list(a, n):
k, m = divmod(len(a), n)
return list(
list(a[i * k + min(i, m) : (i + 1) * k + min(i + 1, m)]) for i in range(n)
)
def get_ticks(df, pos):
splitter = split_list(df.index, 12)
months = [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec",
]
xticks_map = [i for i in zip([splitter[i][pos] for i in range(0, 12)], months)]
return xticks_map
# plotting method
def get_mplot(df, cols=None):
if cols:
df = df[cols]
if len(df.columns) == 0:
print("No coumns selected")
return None
grid_style = {
"grid_line_color": "black",
"grid_line_width": 1.1,
"minor_ygrid_line_color": "lightgray",
"minor_xgrid_line_color": "lightgray",
"xgrid_line_dash": [4, 4],
}
colors = cc.glasbey_light[: len(list(df.columns))]
xticks_map = get_ticks(df, 15)
multi_curve = [
hv.Curve((df.index, df[v]), label=str(v)).opts(
xticks=xticks_map,
xrotation=45,
width=900,
height=400,
line_color=colors[i],
gridstyle=grid_style,
show_grid=True,
)
for i, v in enumerate(df)
]
mplot = hv.Overlay(multi_curve)
return mplot
# get the data
df = get_data()
# create a multi-choice widget
years = pn.widgets.MultiChoice(
name="Years", options=list(df.columns), margin=(0, 20, 0, 0)
)
# bind plot and multi-choice
@pn.depends(years)
def get_plot(years):
df = get_data()
if years:
df = df[years]
mplot = get_mplot(df, years)
return mplot
pn.Column("Plot!", get_plot, pn.Row(years), width_policy="max").servable()
For convenience, I stored the code online as notebook on a gist:
My issue is with the interaction between holoviz
and panel
at cell #7
when I define the @pn.depends
method - the only way I got it to work is to “reloading” the data at each interaction … (cell_out: [#21], [#3], in df = get_data()
) which obviously slows down the whole app if the data starts to increase.
Do you have any hints on how to avoid reload the dataset?