How can overlay multiple lines on the same figure in bokeh
?
This is what I've tried; consider the fallowing data.
import pandas as pd
df = pd.DataFrame(
{
"seq": list(range(5)) + list(range(5)),
"a": ["foo"] * 5 + ["bar"] * 5,
"b": np.concatenate(
(np.linspace(1, 5, 5, dtype=int), np.linspace(1, 5, 5, dtype=int) + 3)
),
}
)
I can draw a scatter plot like this:
cds1 = ColumnDataSource(df)
myfig = figure(y_range=(-1, 10), height=400, width=400)
myfig.scatter(
"seq",
"b",
source=cds1,
marker=factor_mark("a", ["circle", "diamond"], ["foo", "bar"]),
color=factor_cmap("a", Category10[3], ["foo", "bar"]),
size=10,
)
show(myfig)
I would like the points to be connected, but I cannot use factor_cmap
with figure.line
. So I tried creating views and calling one at a time like this:
foo = GroupFilter(column_name="a", group="foo")
bar = GroupFilter(column_name="a", group="bar")
myfig2 = figure(y_range=(-1, 10), height=400, width=400)
myfig2.line("seq", "b", source=cds1, view=CDSView(filter=foo), color=Category10[3][0])
myfig2.line("seq", "b", source=cds1, view=CDSView(filter=bar), color=Category10[3][1])
show(myfig2)
But then I get errors like this: ERROR:bokeh.core.validation.check:E-1024 (CDSVIEW_FILTERS_WITH_CONNECTED): CDSView filters are not compatible with glyphs with connected topology such as Line or Patch: GlyphRenderer(id='p1094', ...)
.
I would rather not use figure.multi_line
as I would like to toggle the visibility of each line from a CustomJS
callback by resetting cds1.data
in JS. Any ideas how I can proceed? Or maybe there is a better way to achieve this besides resetting cds1.data
?
You can use pandas groupby
and draw a scatter and a line renderer for each group.
Using the legend you can link the renderers and with the click_policy
of the legend object you can define how it behaves.
from bokeh.models import ColumnDataSource, FactorRange
from bokeh.plotting import figure, show, output_notebook
output_notebook()
p = figure(y_range=(-1, 10), height=400, width=400)
for name, group in df.groupby('a'):
if name == 'foo':
color = 'blue'
marker = 'circle'
else:
color = 'orange'
marker = 'diamond'
p.line('seq', 'b', source=group, color=color, legend_label=name)
p.scatter('seq', 'b', source=group, marker=marker, color=color, size=7, legend_label=name)
p.legend.click_policy="hide"
show(p)