Bokeh 入门第五步:Glyph 属性向量化与调色板颜色映射实战
2026/9/13 14:35:08 网站建设 项目流程

Bokeh 入门第五步:Glyph 属性向量化与调色板颜色映射实战

【免费下载链接】bokehInteractive Data Visualization in the browser, from Python项目地址: https://gitcode.com/GitHub_Trending/bo/bokeh

导读

在 Bokeh 中,Glyph(图形元素)的视觉属性(颜色、大小、透明度等)不仅可以设为固定值,还可以绑定到数据向量,让每个数据点的外观随其数据值动态变化。本文基于 Bokeh 官方入门系列第五篇指南,讲解三种核心技法:直接向量化颜色向量化颜色与半径、以及使用linear_cmap配合内置调色板完成连续色带映射。读完本文,你将掌握如何用数据驱动的方式一键生成"颜色即数值、大小即数值"的信息可视化,并为后续学习log_cmapfactor_cmap等更复杂的颜色变换打下基础。


一、什么是属性向量化:从固定值到数据驱动

在之前的入门指南(first_steps_4.rst)中,我们通过直接赋值的方式定制图形,例如fill_color="blue"这样把某个颜色固定到整个 Glyph 上。这种写法下,一个 Glyph 的所有数据点共享同一个视觉属性。

向量化(Vectorizing)则完全不同:当我们把一个"长度与数据点数量相同的序列"传给某个视觉属性时,Bokeh 会逐点取值,让每个数据点拥有独立的属性值。这是 Bokeh 中最常用、也最直观的"数据驱动可视化"手段——颜色本身就成为了一维数据的可视化通道。

从源码实现看,Bokeh 的 Glyph 属性实际上都是DataSpec(数据规格),既可以接收标量(如"blue"15),也可以接收与数据等长的序列或字段名,由底层统一分发到每个数据点。理解这一点后,下面的例子就水到渠成。


二、向量化颜色:让颜色跟随数据变化

2.1 核心思路

不再使用固定的fill_color="blue",而是准备一个与 y 等长的颜色列表,把它传给fill_color参数。Bokeh 会把列表中的每个颜色依次应用到对应的数据点上,实现"每个点的颜色由该点的数据值决定"。

2.2 完整可运行示例

import random from bokeh.plotting import figure, show # 生成数据:x 取 0~25,y 为 0~99 之间的随机整数 x = list(range(0, 26)) y = random.sample(range(0, 100), 26) # 根据 y 的值生成 RGB 十六进制颜色列表: # 红色通道固定 255,绿色通道由 (value * 255) / 100 计算,蓝色通道固定 255 colors = [f"#{255:02x}{int((value * 255) / 100):02x}{255:02x}" for value in y] # 创建绘图对象 p = figure( title="Vectorized colors example", sizing_mode="stretch_width", max_width=500, height=250, ) # 同时添加折线与散点渲染器 p.line(x, y, line_color="blue", line_width=1) p.scatter(x, y, fill_color=colors, line_color="blue", size=15) show(p)

对应文件:first_steps_5_vectorize_color.py

2.3 要点解读

  • 颜色公式拆解f"#{255:02x}{int((value * 255) / 100):02x}{255:02x}"将 y 值(0~100)线性缩放到 0~255 的绿色通道数值,再用02x格式化为两位十六进制字符串,拼成#RRGGBB形式。y 越大,绿色越强,颜色越亮。
  • 折线是标量、散点是向量p.line(...)仍使用固定的line_color="blue",而p.scatter(..., fill_color=colors)使用向量。二者可以共存于同一图中,互不干扰。
  • 数据点颜色与数值一一对应:在本例中,每个圆点的填充色直接反映了该点的 y 值大小——这就是"颜色的向量化"。

如果需要更规范地做"数值 → 颜色"的映射(尤其是数据量较大或需要科学配色时),推荐使用第三节的linear_cmap方式,而非手写十六进制字符串。


三、向量化颜色与大小:半径也可以随数据变化

3.1 核心思路

向量化不只适用于颜色。把同样的原理应用到渲染器的radius(半径)参数上,就能让散点的大小同时携带数据信息,形成"颜色 + 大小"双通道编码。

3.2 完整可运行示例

import numpy as np from bokeh.plotting import figure, show # 生成 1000 个随机数据点 N = 1000 x = np.random.random(size=N) * 100 y = np.random.random(size=N) * 100 # 根据数据生成半径和颜色:半径约为 y 的 2%,颜色随 y 线性变化 radii = y / 100 * 2 colors = [f"#{255:02x}{int((value * 255) / 100):02x}{255:02x}" for value in y] # 创建指定尺寸的绘图对象 p = figure( title="Vectorized colors and radii example", sizing_mode="stretch_width", max_width=500, height=250, ) # 添加圆形渲染器:radius 与 fill_color 均为数据驱动的向量 p.circle( x, y, radius=radii, fill_color=colors, fill_alpha=0.6, line_color="lightgrey", ) show(p)

对应文件:first_steps_5_vectorize_color_and_size.py

3.3 要点解读

  • radius直接接收数组radii = y / 100 * 2让每个圆点的半径与其 y 值成正比。注意 Bokeh 中radius使用的是数据坐标系下的长度单位(与size的屏幕像素单位不同),因此随缩放而变化。
  • 向量化的组合运用:同一个 Glyph 上可以同时向量化多个属性——本例同时向量化了radiusfill_color,并辅以固定值fill_alpha=0.6line_color="lightgrey",兼顾数据表达与视觉整洁。
  • 透明度缓解重叠:1000 个点大量重叠时,fill_alpha=0.6让重叠区域的密度得以通过颜色深浅体现出来,是密集散点图的常用技巧。

四、调色板颜色映射:用linear_cmap一键完成"数值 → 颜色"

4.1 Bokeh 内置调色板体系

Bokeh 自带数十种预定义的调色板(palette),覆盖三大家族的经典配色:

  • Brewer 系列:来自 ColorBrewer 的定性/顺序/发散配色,如BluesRedsSpectralPaired等;
  • D3 系列:来自 D3.js 分类色板,如Category10Category20等;
  • Matplotlib 系列:来自 Matplotlib 的连续色图,如ViridisPlasmaTurbo等。

从源码可以看到,这些调色板以字典形式集中定义在 src/bokeh/palettes.py 中,例如第 1412 行的brewer字典(含YlGnBluesSpectralSet1等 35 个命名色板)、第 1454 行的d3字典,以及第 1376 行的Turbo256元组。每个调色板通常还按离散数量分级,例如Turbo支持 3~11 与 256 级。完整清单见参考文档bokeh.palettes(对应源码 src/bokeh/palettes.py)。

4.2linear_cmap函数与四个必需参数

linear_cmap定义在 src/bokeh/transform.py,作用是创建一个客户端侧的LinearColorMapper变换,把某个数据列线性映射到调色板。其必需参数为:

参数含义
field_name要映射颜色的数据字段名(即数据序列)
palette使用的调色板(如Turbo256
low映射到调色板**最左端(最小颜色)**的最低值
high映射到调色板**最右端(最大颜色)**的最高值

从源码签名还可看到几个可选参数:

  • low_color(默认None):数据值低于low时使用的颜色;为None时低于low的值被钳制映射到调色板第一个颜色;
  • high_color(默认None):数据值高于high时使用的颜色;为None时高于high的值被钳制映射到调色板最后一个颜色;
  • nan_color(默认"gray"):数据缺失或映射失败时使用的默认颜色。

创建好 mapper 后,把它赋值给渲染器的color参数即可完成映射。

4.3 完整可运行示例

from bokeh.io import show from bokeh.palettes import Turbo256 from bokeh.plotting import figure from bokeh.transform import linear_cmap # 生成数据:y 为 x 的平方 x = list(range(-32, 33)) y = [i**2 for i in x] # 创建线性颜色映射器:字段 "y"、调色板 Turbo256、映射范围为 y 的最小值到最大值 mapper = linear_cmap(field_name="y", palette=Turbo256, low=min(y), high=max(y)) # 创建绘图对象 p = figure(width=500, height=250) # 创建圆形渲染器并应用颜色映射器 p.scatter(x, y, color=mapper, size=10) show(p)

对应文件:first_steps_5_color_mapping.py

4.4 要点解读

  • field_name是列名而非数组:与第一节直接传颜色列表不同,linear_cmap接收的是字段名字符串(这里是"y"),Bokeh 会在内部对数据列逐点执行映射,这正是LinearColorMapper作为客户端侧变换的职责所在。
  • low/high决定色带覆盖范围:本例用min(y)/max(y)让整条色带恰好覆盖数据全范围;你也可以手动指定更小或更大的范围,此时超出范围的数据点会被钳制(clamp)到端点颜色。
  • color=一键搞定填充与描边p.scatter(..., color=mapper)同时作用于填充色与描边色,是linear_cmap最简洁的用法。
  • 数据分布与视觉分布:由于 y 是二次函数,中间区域点密集但数值小,两端点稀疏但数值大,使用Turbo256(256 级渐变)可以清晰呈现数值的连续变化——这正是连续色带相比手工构造颜色列表的优势。

五、延伸:log_cmapfactor_cmap与其他属性向量化

linear_cmap只是 Bokeh 颜色变换家族的一员,同样定义在 src/bokeh/transform.py 中:

  • log_cmap(源码位置):对数尺度线性映射,参数与linear_cmap完全一致。适用于数值跨越多个数量级的数据(如星系距离、人口密度等),映射前对数值取对数,避免少量大值把色带整体"压扁"。
  • factor_cmap(源码位置):针对分类数据的颜色映射,额外接受factors参数(与调色板一一对应的类别因子序列),将每个类别映射到调色板中的对应颜色;还可通过start/end切片处理多级因子,nan_color处理缺失值。
  • transform(field_name, transform)(源码位置):通用入口,可将任意客户端侧Transform应用到数据列上,是上述各*_cmap的基础设施。

此外,向量化不仅限于颜色与半径。Bokeh 的众多 Glyph 属性(如sizeline_widthfill_alphaline_dash等)都支持向量化赋值,可以组合出极为丰富的数据编码方案。分类数据的颜色/填充纹样/标记映射还可参考factor_hatchfactor_mark(源码位置)。

更系统的颜色映射与数据变换教程,可继续阅读用户指南中的 数据颜色映射与数据变换章节(对应锚点ug_basic_data_color_mappingug_basic_data_transforming)。


六、从源码看linear_cmap的底层机制

为了深入理解linear_cmap到底做了什么,我们看它在 src/bokeh/transform.py 中的实现:

def linear_cmap( field_name: str, palette: PaletteLike, low: float, high: float, low_color: ColorType | None = None, high_color: ColorType | None = None, nan_color: ColorType = "gray", ) -> Field: ''' Create a ``DataSpec`` dict that applies a client-side ``LinearColorMapper`` transformation to a ``ColumnDataSource`` column. ... ''' return Field( field_name, LinearColorMapper( palette=palette, low=low, high=high, nan_color=nan_color, low_color=low_color, high_color=high_color, ), )

从中可以提炼出三个关键事实:

  1. 返回类型是Fieldlinear_cmap并不直接返回颜色数组,而是返回一个Field——即DataSpec的封装,内部包含字段名与变换器。这意味着它属于"声明式"配置:真正把数据映射成颜色发生在浏览器端(BokehJS)的LinearColorMapper中,而不是在 Python 侧预计算。
  2. 客户端侧变换(client-side transform):由于映射发生在浏览器内,当数据源动态更新(例如服务端推送新数据)时,颜色会自动重新计算,无需重新发起请求——这是 Bokeh 交互式可视化的核心优势之一。
  3. 钳制与缺省策略内置于 mapperlow/high之外的越界值、以及NaN等缺失值,分别由low_color/high_color/nan_color三个参数在映射器内部处理,保证了任何输入数据都能得到确定的输出颜色。

同样的模式也适用于log_cmap(底层为LogColorMapper)与factor_cmap(底层为CategoricalColorMapper),三者共享Field+ 具体ColorMapper的架构,只是映射算法不同。


七、小结:三种数据驱动着色的选型建议

需求场景推荐方案对应章节
少量点、快速原型,颜色逻辑简单手动构造颜色列表传入fill_color第二节
大量点、需要同时编码两个维度向量化radiusfill_color第三节
需要专业科学配色、动态数据、健壮的颜色映射linear_cmap+ 内置调色板第四节
数值跨越多个数量级log_cmap第五节
类别型数据的颜色区分factor_cmap第五节

向量化是 Bokeh 数据驱动可视化的基石能力:颜色、大小、透明度、线宽等属性都可以是数据的函数。掌握本文的三种写法后,建议继续阅读官方入门系列的后续章节(first_steps_6.rst 及之后),学习布局组合与交互工具,把数据驱动的视觉编码应用到完整的数据应用中。

【免费下载链接】bokehInteractive Data Visualization in the browser, from Python项目地址: https://gitcode.com/GitHub_Trending/bo/bokeh

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询