使用Bokeh,如何获得 Renderer
的 GlyphRenderer
(或Annotation
)句柄?这可能吗?
我希望能够使用交互式图例来打开和关闭Band
(这是Annotation
),因此我需要能够将Renderers
的列表传递给LegendItem
构造函数。
这段代码:
maxline = fig.line(x='Date', y=stn_max, line_width=0.5, legend=stn_max, name="{}_line".format(stn_max), color=stn_color, alpha=0.75, source=source)
minline = fig.line(x='Date', y=stn_min, line_width=0.5, legend=stn_min, name="{}_line".format(stn_min), color=stn_color, alpha=0.75, source=source)
band = bkm.Band(base='Date', lower=stn_min, upper=stn_max, fill_alpha=0.50, line_width=0.5, fill_color=stn_color, source=source)
bkm.LegendItem(label=stn, renderers=[maxline, minline, band])
产生此错误...
ValueError: expected an element of List(Instance(GlyphRenderer)), got seq with invalid items [Band(id='1091', ...)]
最佳答案
对于LegendItem
,只能将GlyphRenderer
的实例传递到其renderers
属性,并且Band
不是基于GlyphRenderer
的,因此会产生错误。在下面的代码中,band可见性通过回调进行切换:
from bokeh.plotting import figure, show
from bokeh.models import Band, ColumnDataSource, Legend, LegendItem, CustomJS
import pandas as pd
import numpy as np
x = np.random.random(2500) * 140 - 20
y = np.random.normal(size = 2500) * 2 + 5
df = pd.DataFrame(data = dict(x = x, y = y)).sort_values(by = "x")
sem = lambda x: x.std() / np.sqrt(x.size)
df2 = df.y.rolling(window = 100).agg({"y_mean": np.mean, "y_std": np.std, "y_sem": sem})
df2 = df2.fillna(method = 'bfill')
df = pd.concat([df, df2], axis = 1)
df['lower'] = df.y_mean - df.y_std
df['upper'] = df.y_mean + df.y_std
source = ColumnDataSource(df.reset_index())
p = figure(tools = "pan,wheel_zoom,box_zoom,reset,save")
scatter = p.scatter(x = 'x', y = 'y', line_color = None, fill_alpha = 0.3, size = 5, source = source)
band = Band(base = 'x', lower = 'lower', upper = 'upper', source = source)
p.add_layout(band)
p.title.text = "Rolling Standard Deviation"
p.xaxis.axis_label = 'X'
p.yaxis.axis_label = 'Y'
callback = CustomJS(args = dict(band = band), code = """
if (band.visible == false)
band.visible = true;
else
band.visible = false; """)
legend = Legend(items = [ LegendItem(label = "x", renderers = [scatter, band.source.selection_policy]) ])
legend.click_policy = 'hide'
scatter.js_on_change('visible', callback)
p.add_layout(legend)
show(p)
结果: