使用散景 1.4 和 Python 3.7。我有一组补丁,我想根据来自同一个 ColumnDataSource 的两个不同的键(和标签)来改变颜色主题。我想坚持使用一个 ColumnDataSource,因为我的真实文件非常大,并且几何(即 xs 和 ys)在我想要作为主题的两件事之间是常见的。
请参阅我的工作示例:
from bokeh.io import show
from bokeh.models import ColumnDataSource,CustomJS, widgets, LinearColorMapper
from bokeh.palettes import RdBu6, Spectral11
from bokeh.plotting import figure
from bokeh.layouts import layout, column, row
source = ColumnDataSource(dict(
xs=[[1,2,2], [1,2,2], [3,4,4], [3,4,4]],
ys=[[3,3,4], [1,1,2], [3,3,4], [1,1,2]],
s1=[0, 50, 75, 50],
s2=[0, 25, 50, 75],
label_1=['Blue', 'Orangy', 'Red', 'Orangy'],
label_2=['S', 'P', 'E', 'C']
))
cmap1 = LinearColorMapper(palette='RdBu6', low = 0, high = 75)
cmap2 = LinearColorMapper(palette='Spectral11', low = 0, high = 75)
p = figure(x_range=(0, 7), y_range=(0, 5), plot_height=300)
patches = p.patches( xs='xs', ys='ys', fill_color={'field':'s1','transform':cmap1}
, legend_field='label_1', source=source)
b = widgets.Button(label = 'RdBu')
b.js_on_click(CustomJS(args=dict(b=b,source=source,patches=patches,cmap1=cmap1,cmap2=cmap2,p=p),
code="""if (b.label == 'RdBu')
{b.label='Spectral';
patches.glyph.fill_color = {field: 's2',transform:cmap2};}
else if (b.label == 'Spectral')
{b.label='RdBu';
patches.glyph.fill_color = {field: 's1',transform:cmap1}}"""
))
layout=column(row(p),row(b))
show(layout)
这会产生this,然后 在单击按钮时产生this 。您可以看到,随着颜色的变化,甚至图例中的颜色发生变化,回调的 fill_color 更新部分工作正常,但我一直无法找到一种方法来指示 CustomJS 正确更新图例条目,以便在第二图像将有 4 个条目,其中 'S'、'P'、'E' 和 'C' 作为图例标签。
据我所知,当我创建 patch 对象并指定 legend_field 参数时,它使用某种 groupby/aggregate 函数为我构造一个图例,为我生成唯一的图例条目,然后将该图例添加到图形对象?
因此,这使我走上了尝试深入研究 p.legend 的道路:
p.legend.items #returns a list containing one LegendItem object
p.legend.items[0].label #returns a dictionary: {'field': 'label_1'}
我尝试将 p.legend.items[0].label['field'] = 'label_2' 放在回调之外,它按我希望的那样工作 - 图例现在显示为 S、P、E、C。但是当我尝试将其放入回调代码中时,它似乎没有更新:
b.js_on_click(CustomJS(args=dict(b=b,source=source,patches=patches,cmap1=cmap1,cmap2=cmap2,p=p),
code="""if (b.label == 'RdBu')
{b.label='Spectral';
patches.glyph.fill_color = {field: 's2',transform:cmap2};
p.legend.items[0].label['field']='label_2'}
else if (b.label == 'Spectral')
{b.label='RdBu';
patches.glyph.fill_color = {field: 's1',transform:cmap1}
p.legend.items[0].label['field']='label_1'}"""
))
我觉得我很接近,但只是错过了一两个关键的东西......任何建议/帮助表示赞赏!