实时更改bokeh patches图的颜色

4
我正在尝试创建一个bokeh图表,用于显示美国各州,并根据一些数据对每个州进行着色。现在,使用这个教程,我创建了这个图表,但我还想增强它,并添加一个滑块,以改变显示的值。例如,显示不同的年份。
通过这个教程的帮助,我成功地添加了滑块,而底层数据确实会根据悬停文本更改,但颜色没有重新计算,因此视觉表示与值不匹配。
这是我使用的代码,来自Jupyter笔记本,任何想要尝试的人都可以重现。
from bokeh.io import show, output_notebook
from bokeh.models import (
    ColumnDataSource,
    HoverTool,
    LogColorMapper,
    Range1d, CustomJS, Slider
)
from bokeh.palettes import Inferno256 as palette
from bokeh.plotting import figure

from bokeh.layouts import row, widgetbox

from bokeh.sampledata.us_counties import data as counties
from bokeh.sampledata.us_states import data as states
from bokeh.sampledata.unemployment import data as unemployment
import pandas as pd
import random
output_notebook()
palette.reverse()

states_accumulated ={}
available_state_codes = states.keys()

for key, value in counties.items():
    state_name = value["state"].upper()
    if state_name in states.keys() and "number" not in states[state_name]:
        states[state_name]["number"] = key[0]

for key,state in states.items():
    state["code"] = key

state_list = []

for key,state in states.items():
    state_list.append(state)

unemployment_transf = []
for key,value in unemployment.items():
    unemployment_transf.append({
        "State":key[0],
        "County":key[1],
        "Value":value
    })
unemp_df = pd.DataFrame(unemployment_transf)
unemp_sum = unemp_df.groupby("State").mean()["Value"]
unemp_sum = unemp_sum.sort_index()

unemp_sum_flat = {key:value for key, value in unemp_sum.items()}

for state in state_list:
    state["value"] = unemp_sum_flat[state["number"]]
state_df = pd.DataFrame(state_list)
color_mapper = LogColorMapper(palette=palette)

state_xy = (list(state_df["lons"].values),list(state_df["lats"].values))

max_x = max([max(l) for l in state_xy[0]])
max_y = max([max(l) for l in state_xy[1]])
min_x = min([min(l) for l in state_xy[0]])
min_y = min([min(l) for l in state_xy[1]])

data=dict(
    x=state_xy[0],
    y=state_xy[1],
    name=list(state_df["name"].values),
    used = list(state_df["value"].values)
)

data['1999'] = list(state_df["value"].values)
data['2000'] = [random.randrange(0,10) for i in range(len(state_xy[0]))]
source = ColumnDataSource(data)

TOOLS = "pan,wheel_zoom,reset,hover,save"

p = figure(
    title="States", tools=TOOLS,
    x_axis_location=None, y_axis_location=None
)
p.width=450
p.height = 450
p.x_range= Range1d(-170,-60)
p.y_range = Range1d(min_y-10,max_y+10)
p.grid.grid_line_color = None

renderer = p.patches('x', 'y', source=source,
          fill_color={'field': 'used', 'transform': color_mapper},
          fill_alpha=0.7, line_color="white", line_width=0.5)


hover = p.select_one(HoverTool)
hover.point_policy = "follow_mouse"
hover.tooltips = [
    ("Name", "@name"),
    ("Unemployment rate)", "@used%"),
    ("(Long, Lat)", "($x, $y)"),
]

callback = CustomJS(args=dict(source=source,plot=p,color_mapper = color_mapper,renderer = renderer), code="""
    var data = source.data;
    var year = year.value;
    used = data['used']
    should_be = data[String(year)]
    for (i = 0; i < should_be.length; i++) {
        used[i] = should_be[i];
    } 
""")


year_slider = Slider(start=1999, end=2000, value=1999, step=1,
                    title="year", callback=callback)
callback.args["year"] = year_slider

layout = row(
    p,
    widgetbox(year_slider),
)
show(layout)

示例图:

第一种可视化 第二种可视化

我的目标是,当我改变滑块时,图表上的颜色应该改变。现在我认为JS回调应该调用某种重绘或重新计算,但我没有找到任何相关文档。有没有办法实现这个功能?

2个回答

2

source.change.emit() 追加到 JavaScript 代码中以触发更改事件。


对我来说,source.change.emit() 没有任何作用,在 JS 控制台中,我会收到一个错误,提示 TypeError: source.change is undefined。不过使用 source.trigger("change") 似乎可以解决这个问题。 - Brabulla
1
@Brabulla,你的bokeh版本过旧了。如果你将其升级到最新版,需要将source.trigger('change') 改为 source.change.emit() - HYRY
谢谢,更新解决了问题。我之前使用的是0.12.7版本,现在更新到了0.12.11,它可以正常工作了。 - Brabulla

0
source.trigger("change"); 添加到 CustomJS 中似乎解决了问题,现在随着滑块的变化,颜色也会改变。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接