我正在尝试创建一个bokeh图表,用于显示美国各州,并根据一些数据对每个州进行着色。现在,使用这个教程,我创建了这个图表,但我还想增强它,并添加一个滑块,以改变显示的值。例如,显示不同的年份。
通过这个教程的帮助,我成功地添加了滑块,而底层数据确实会根据悬停文本更改,但颜色没有重新计算,因此视觉表示与值不匹配。
这是我使用的代码,来自Jupyter笔记本,任何想要尝试的人都可以重现。
通过这个教程的帮助,我成功地添加了滑块,而底层数据确实会根据悬停文本更改,但颜色没有重新计算,因此视觉表示与值不匹配。
这是我使用的代码,来自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)
示例图:
![第一种可视化](https://istack.dev59.com/hBwn9.webp)
![第二种可视化](https://istack.dev59.com/TQBap.webp)
我的目标是,当我改变滑块时,图表上的颜色应该改变。现在我认为JS回调应该调用某种重绘或重新计算,但我没有找到任何相关文档。有没有办法实现这个功能?
source.change.emit()
没有任何作用,在 JS 控制台中,我会收到一个错误,提示TypeError: source.change is undefined
。不过使用source.trigger("change")
似乎可以解决这个问题。 - Brabullasource.trigger('change')
改为source.change.emit()
。 - HYRY