You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将Matplotlib分配的颜色传入Bokeh自定义图例?

解决Bokeh自定义图例匹配Matplotlib颜色的问题

我来帮你搞定这个颜色同步的问题!你现在的核心痛点是把Matplotlib分配的颜色对应到Bokeh的自定义图例中,因为没使用ColumnDataSource,得手动完成这个关联,下面一步步拆解:

第一步:把Matplotlib颜色转换成Bokeh兼容格式

Matplotlib输出的颜色通常是RGB/RGBA数组(比如(0.3, 0.6, 0.8)),但Bokeh更认十六进制字符串(比如#4d99cc)。我们可以用Matplotlib自带的工具函数转换:

import matplotlib.colors

# 假设你已经有Matplotlib分配好的颜色(比如来自colormap或手动指定)
mpl_color = (0.3, 0.6, 0.8)
bokeh_color = matplotlib.colors.to_hex(mpl_color)

如果是给多个类别分配颜色(比如用colormap批量取色),可以先建立类别和颜色的映射字典:

import matplotlib.pyplot as plt

categories = ["类别A", "类别B", "类别C"]
# 选一个你用的colormap,这里用viridis举例
cmap = plt.cm.get_cmap("viridis", len(categories))

# 生成类别-十六进制颜色的映射
category_color_map = {
    cat: matplotlib.colors.to_hex(cmap(i)) 
    for i, cat in enumerate(categories)
}

第二步:关联散点渲染器与图例项

因为你没用到ColumnDataSource,应该是按类别逐个绘制散点的。那在绘制每个类别的散点时,要保存对应的渲染器,然后把它和类别、颜色绑定到图例项中:

from bokeh.plotting import figure, show
from bokeh.models import Legend, LegendItem

# 创建画布
p = figure(title="带自定义图例的散点图", x_axis_label="X轴", y_axis_label="Y轴")
legend_items = []

# 假设你的数据按类别分组,比如grouped_data是{类别: (x数据, y数据)}
for cat, (x_data, y_data) in grouped_data.items():
    # 获取该类别的Bokeh格式颜色
    color = category_color_map[cat]
    # 绘制散点,得到这个类别的渲染器
    renderer = p.scatter(x_data, y_data, color=color, size=8, alpha=0.7)
    # 创建图例项,把渲染器和类别绑定
    legend_items.append(LegendItem(label=cat, renderers=[renderer]))

# 创建自定义图例并添加到画布
custom_legend = Legend(items=legend_items, location="top_right")
p.add_layout(custom_legend)

show(p)

如果是Matplotlib自动给散点分配颜色(比如用plt.scatter的c参数)

如果你是通过Matplotlib的散点函数自动给每个点分配颜色(比如基于类别编码),那得先提取每个类别的对应颜色,再同步到Bokeh:

import numpy as np
from sklearn.preprocessing import LabelEncoder

# 示例数据
x = np.random.rand(100)
y = np.random.rand(100)
categories = np.random.choice(["类别A", "类别B", "类别C"], 100)

# 把类别转换成数值(方便Matplotlib取色)
le = LabelEncoder()
cat_numeric = le.fit_transform(categories)

# Matplotlib生成颜色
cmap = plt.cm.viridis
norm = plt.Normalize(cat_numeric.min(), cat_numeric.max())
mpl_colors = cmap(norm(cat_numeric))

# 转换为Bokeh兼容的十六进制颜色
bokeh_colors = [matplotlib.colors.to_hex(c) for c in mpl_colors]

# 建立类别-颜色映射(取每个类别第一个点的颜色即可,假设同类别颜色一致)
category_color_map = {}
for cat, color in zip(categories, bokeh_colors):
    if cat not in category_color_map:
        category_color_map[cat] = color

# 接下来就可以按上面的方法绘制散点和图例了

补充:HoverTool的小建议

虽然你现在没用到ColumnDataSource,但如果要给HoverTool加类别信息,用ColumnDataSource会更省心。比如把每个类别的数据封装成数据源,HoverTool可以直接读取字段:

from bokeh.models import ColumnDataSource, HoverTool

hover = HoverTool(tooltips=[
    ("类别", "@category"),
    ("X值", "@x"),
    ("Y值", "@y")
])

p = figure(tools=[hover])
legend_items = []

for cat in category_color_map.keys():
    # 筛选该类别的数据
    mask = categories == cat
    source = ColumnDataSource(data={
        "x": x[mask],
        "y": y[mask],
        "category": [cat] * len(x[mask])
    })
    renderer = p.scatter("x", "y", source=source, color=category_color_map[cat], size=8)
    legend_items.append(LegendItem(label=cat, renderers=[renderer]))

custom_legend = Legend(items=legend_items, location="top_right")
p.add_layout(custom_legend)

show(p)

这样不仅HoverTool能正常工作,后续的轴切换、年份滑块这类复杂交互,用ColumnDataSource也更容易维护哦!

内容的提问来源于stack exchange,提问作者machump

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 09:17:02