1

使用散景 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'}"""
                            ))

我觉得我很接近,但只是错过了一两个关键的东西......任何建议/帮助表示赞赏!

4

1 回答 1

1

Carolyn 的解决方案:https ://discourse.bokeh.org/t/is-there-a-way-to-update-legend-patch-labels-using-a-customjs-callback/4504

......我真的很亲近。

于 2020-01-13T13:30:56.607 回答