
本文详解如何在 bokeh 中实现散点图的颜色映射,使点的颜色依据 y 值(如温度)着色,但色彩标尺(colorbar)范围由独立的 z 列表(如完整温区 0–100℃)定义,解决数据维度不一致与归一化映射的核心难点。
本文详解如何在 bokeh 中实现散点图的颜色映射,使点的颜色依据 y 值(如温度)着色,但色彩标尺(colorbar)范围由独立的 z 列表(如完整温区 0–100℃)定义,解决数据维度不一致与归一化映射的核心难点。
在 Bokeh 中为散点图实现“语义正确”的颜色映射,关键在于区分两个概念:着色依据的数据列(即每个点实际对应的物理量,如观测温度 y)与色彩标尺的参考范围(即该物理量的理论/标称全量程,如 z = [0, 1, ..., 99])。当 z 长度与 x/y 不同(例如 len(z)=100 而 len(y)=50)时,不能直接将 z 作为颜色字段,而应将其用作定义 LinearColorMapper 的 low 和 high 边界——这确保了颜色映射具备可比性与可复用性(例如多图对比、跨实验一致性)。
以下为完整实现流程(含可运行示例):
✅ 步骤 1:准备数据并明确映射逻辑
import random from bokeh.plotting import figure, show from bokeh.models import ColumnDataSource, LinearColorMapper, ColorBar from bokeh.palettes import Spectral6 # 模拟数据:50个观测点 x = list(range(1, 51)) y = random.sample(range(0, 100), 50) # 实际观测温度(单位:℃) # 独立的标称温区:代表仪器量程或标准参考范围(0–99℃),长度=100 ≠ len(y) z = list(range(0, 100)) # ✅ 关键:z 不参与绘图数据构造,仅用于定义 color mapper 的范围 color_low, color_high = min(z), max(z) # → 0, 99
✅ 步骤 2:构建 ColumnDataSource
source 必须包含所有绘图所需字段,其中用于着色的字段(此处为 'temperature')应直接使用原始 y 值(无需归一化!Bokeh 会自动按 low/high 缩放):
source = ColumnDataSource(dict(
x=x,
y=y,
temperature=y # 字段名需与 cmap.field_name 严格一致
))✅ 步骤 3:配置 LinearColorMapper 并绑定 palette
指定 field_name 为数据源中的着色字段名,low/high 设为 z 定义的标称范围:
cmap = LinearColorMapper(
field_name='temperature',
palette=Spectral6,
low=color_low, # ← 来自 z,非 min(y)
high=color_high # ← 来自 z,非 max(y)
)✅ 步骤 4:绘制散点图 + 添加 colorbar
p = figure(
title="Temperature Observations (Color Scale: 0–99℃)",
width=700, height=500,
x_axis_label="Sample Index", y_axis_label="Temperature (℃)"
)
# 使用字典语法传递 color:字段 + 变换器
scatter = p.scatter(
x='x', y='y',
size=12,
source=source,
color={'field': 'temperature', 'transform': cmap},
line_color="white", line_width=0.5
)
# 添加 colorbar(可选但强烈推荐)
color_bar = ColorBar(
color_mapper=cmap,
label_standoff=12,
border_line_color=None,
location=(0, 0),
title="Temperature (℃)"
)
p.add_layout(color_bar, 'right')
show(p)⚠️ 注意事项与最佳实践
- 不要对 y 归一化再传入 source:常见误区是先 y_norm = (y - min_z) / (max_z - min_z) 再存入 source。这会导致 colorbar 标签失真(显示 0–1 而非 0–99℃)。Bokeh 的 LinearColorMapper 会在渲染时自动完成线性映射。
- z 仅用于定义范围,不需与 y 长度一致:z 可以是任意长度的数值序列(如 np.linspace(0, 99, 256)),只要能准确表达物理量程即可。
- 处理离群值:若 y 中存在明显异常值(如 y=[..., 150]),建议显式设置 low/high 为 z 的极值,避免 colormap 被拉伸失真。
- palette 选择:Spectral6 是离散调色板;若需连续渐变,改用 Viridis256 或 Plasma256,并确保 LinearColorMapper 的 palette 参数匹配。
通过以上结构化步骤,你不仅能正确实现颜色映射,更能确保可视化结果具备科学严谨性——颜色直观反映物理意义(如温度高低),且标尺范围稳定可解释,为后续多组数据对比与报告输出奠定基础。










