如何调整工具提示以仅显示散景中滑块选择的列
How to adjust tooltip to display only column selected by slider in Bokeh
我正在尝试使用 Geopandas 和 Bokeh 创建可视化。
数据具有列区域、几何形状和 >100 列(第 1 周、第 2 周、第 3 周等),这些列具有个案数值。
此任务是当鼠标悬停在某个区域上时,工具提示仅显示滑块当前选择的列中的值。
我尝试过的事情:
此选项显示工具提示中的所有列。信息太多
data.plot_bokeh(
slider=[week1,week2,week3],
slider_name="Week:",
figsize=(1600,600))
不确定将什么作为变量放在“案例”旁边,或者如何根据滑块使其动态化。
data.plot_bokeh(
slider=[week1,week2,week3],
slider_name="Week:",
hovertool_string="""<h1>@region_name</h1>
<h3>Cases: ?? </h3>""",
figsize=(1600,600))
Bokeh 必须根据滑块将当前值存储在某处,因为它会根据值正确地为区域着色
- 如果您检查 geoplot.py/
geoplot()
中的 plotly_bokeh 代码,您将在滑块回调 JavaScript 中找到一个内部列 Colormap 设置为与滑块中的值对应的列(代码如下)
- 您没有提供 MWE,因此使用了 OWID COVID 数据和自然地球低分辨率多边形。 (见资料准备)
- 有了这个就可以很简单地定义 hovertool_string 参数来按你想要的方式工作
解决方案
import warnings
# bokeh generates a lot of shapely deprecation warnings
with warnings.catch_warnings():
warnings.simplefilter("ignore")
gdf.plot_bokeh(
slider=[c for c in gdf.columns if c[0:4] == "week"],
slider_name="week ",
colorbar_tick_format="0.0a",
colormap="Inferno",
colormap_range=[
gdf.loc[:, [c for c in gdf.columns if c[0:4] == "week"]].quantile(p).quantile(p)
for p in [0.10, 0.90]
],
hovertool_string="<h3>@name</h3><pre>@Colormap{0.0a}</pre>"
)
输出
plotly_bokeh回调
# Define Callback for Slider widget:
callback = CustomJS(
args=dict(
slider_widget=slider_widget,
geo_source=geo_source,
value2name=value2name,
),
code="""
//Change selection of field for Colormapper for choropleth plot:
var slider_value = slider_widget.value;
var i;
for(i=0; i<value2name.data["Names"].length; i++)
{
if (value2name.data["Values"][i] == slider_value)
{
var name = value2name.data["Names"][i];
}
}
geo_source.data["Colormap"] = geo_source.data[name];
geo_source.change.emit();
""",
)
slider_widget.js_on_change("value", callback)
资料准备
import pandas as pd
import geopandas as gpd
import pandas_bokeh
pandas_bokeh.output_notebook()
df = pd.read_csv(
"https://raw.githubusercontent.com/owid/covid-19-data/master/public/data/owid-covid-data.csv"
).loc[
lambda df: ~df["iso_code"].str.contains("_"),
["iso_code", "date", "total_cases_per_million"],
]
df["date"] = pd.to_datetime(df["date"])
# cases for each week as columns
df2 = (
df.merge(
pd.DataFrame(
{"date": pd.date_range(df["date"].quantile(.1), df["date"].max(), freq="W-MON")}
).assign(week=lambda d: "week" + d.index.astype(str).str.zfill(3)),
on="date",
how="inner",
)
.drop(columns=["date"])
.set_index(["iso_code", "week"])
.unstack("week")
.droplevel(0, 1)
.reset_index()
)
# geometry and cases as columns
gdf = (
gpd.read_file(gpd.datasets.get_path("naturalearth_lowres"))
.loc[:, ["iso_a3", "name", "geometry"]]
.merge(df2, left_on="iso_a3", right_on="iso_code")
)
我正在尝试使用 Geopandas 和 Bokeh 创建可视化。 数据具有列区域、几何形状和 >100 列(第 1 周、第 2 周、第 3 周等),这些列具有个案数值。
此任务是当鼠标悬停在某个区域上时,工具提示仅显示滑块当前选择的列中的值。
我尝试过的事情:
此选项显示工具提示中的所有列。信息太多
data.plot_bokeh(
slider=[week1,week2,week3],
slider_name="Week:",
figsize=(1600,600))
不确定将什么作为变量放在“案例”旁边,或者如何根据滑块使其动态化。
data.plot_bokeh(
slider=[week1,week2,week3],
slider_name="Week:",
hovertool_string="""<h1>@region_name</h1>
<h3>Cases: ?? </h3>""",
figsize=(1600,600))
Bokeh 必须根据滑块将当前值存储在某处,因为它会根据值正确地为区域着色
- 如果您检查 geoplot.py/
geoplot()
中的 plotly_bokeh 代码,您将在滑块回调 JavaScript 中找到一个内部列 Colormap 设置为与滑块中的值对应的列(代码如下) - 您没有提供 MWE,因此使用了 OWID COVID 数据和自然地球低分辨率多边形。 (见资料准备)
- 有了这个就可以很简单地定义 hovertool_string 参数来按你想要的方式工作
解决方案
import warnings
# bokeh generates a lot of shapely deprecation warnings
with warnings.catch_warnings():
warnings.simplefilter("ignore")
gdf.plot_bokeh(
slider=[c for c in gdf.columns if c[0:4] == "week"],
slider_name="week ",
colorbar_tick_format="0.0a",
colormap="Inferno",
colormap_range=[
gdf.loc[:, [c for c in gdf.columns if c[0:4] == "week"]].quantile(p).quantile(p)
for p in [0.10, 0.90]
],
hovertool_string="<h3>@name</h3><pre>@Colormap{0.0a}</pre>"
)
输出
plotly_bokeh回调
# Define Callback for Slider widget:
callback = CustomJS(
args=dict(
slider_widget=slider_widget,
geo_source=geo_source,
value2name=value2name,
),
code="""
//Change selection of field for Colormapper for choropleth plot:
var slider_value = slider_widget.value;
var i;
for(i=0; i<value2name.data["Names"].length; i++)
{
if (value2name.data["Values"][i] == slider_value)
{
var name = value2name.data["Names"][i];
}
}
geo_source.data["Colormap"] = geo_source.data[name];
geo_source.change.emit();
""",
)
slider_widget.js_on_change("value", callback)
资料准备
import pandas as pd
import geopandas as gpd
import pandas_bokeh
pandas_bokeh.output_notebook()
df = pd.read_csv(
"https://raw.githubusercontent.com/owid/covid-19-data/master/public/data/owid-covid-data.csv"
).loc[
lambda df: ~df["iso_code"].str.contains("_"),
["iso_code", "date", "total_cases_per_million"],
]
df["date"] = pd.to_datetime(df["date"])
# cases for each week as columns
df2 = (
df.merge(
pd.DataFrame(
{"date": pd.date_range(df["date"].quantile(.1), df["date"].max(), freq="W-MON")}
).assign(week=lambda d: "week" + d.index.astype(str).str.zfill(3)),
on="date",
how="inner",
)
.drop(columns=["date"])
.set_index(["iso_code", "week"])
.unstack("week")
.droplevel(0, 1)
.reset_index()
)
# geometry and cases as columns
gdf = (
gpd.read_file(gpd.datasets.get_path("naturalearth_lowres"))
.loc[:, ["iso_a3", "name", "geometry"]]
.merge(df2, left_on="iso_a3", right_on="iso_code")
)