Bokeh Contour Plots 完全指南:等值线与填充区域的 Python 可视化实现
2026/9/14 13:59:57 网站建设 项目流程

Bokeh Contour Plots 完全指南:等值线与填充区域的 Python 可视化实现

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

导读

本文围绕 Bokeh 的figure.contour()等高线绘图能力展开,讲解如何在二维四边形网格上计算并渲染等值线(contour lines)与等值线之间的填充区域(filled regions)。你将学会从简单的笛卡尔网格示例出发,掌握标量与向量视觉属性、调色板插值规则、ContourRendererContourColorBar的配套用法,并进一步实现基于bokeh serve的动画等高线以及掩码数组等高级技巧。全文以仓库中的用户指南 contour.rst 为主体,结合 contour.py 源码与 contour_simple.py、contour_polar.py、contour_animated.py 三个真实示例逐层展开。

什么是 Contour Plot

等高线图(Contour plot)用于在二维四边形网格(two-dimensional quadrilateral grids)上计算并渲染等值线,即数值恒定的曲线。Bokeh 的等高线功能有两个显著特点:

  • 一次函数调用即可同时渲染等值线相邻等值线之间的填充多边形
  • 网格本身不限于笛卡尔坐标系,极坐标等任意四边形网格同样支持。

等值线对应的二维数据约定为z,它定义在xy网格之上;levels则给出要计算等值线所依据的数值序列。Bokeh 自 3.0 版本起加入等高线支持,后续版本仍在持续改进。

简单示例:一条语句画出等值线与填充区域

先看仓库中完整的入门示例 contour_simple.py:

import numpy as np from bokeh.palettes import Sunset8 from bokeh.plotting import figure, show # 待轮廓化的数据是两个高斯函数的和 x, y = np.meshgrid(np.linspace(0, 3, 40), np.linspace(0, 2, 30)) z = 1.3*np.exp(-2.5*((x-1.3)**2 + (y-0.8)**2)) - 1.2*np.exp(-2*((x-1.8)**2 + (y-1.3)**2)) p = figure(width=550, height=300, x_range=(0, 3), y_range=(0, 2)) levels = np.linspace(-1, 1, 9) contour_renderer = p.contour(x, y, z, levels, fill_color=Sunset8, line_color="black") colorbar = contour_renderer.construct_color_bar() p.add_layout(colorbar, "right") show(p)

这段代码包含四个关键环节,逐一说明如下。

数据约定:z 定义在 x、y 网格上

  • xynp.meshgrid生成,是规则间距的笛卡尔网格;
  • z是形状为(ny, nx)的二维数组,本例中是两个高斯函数的叠加;
  • levels = np.linspace(-1, 1, 9)给出需要计算的 9 个等值层级。

视觉属性的标量与向量语义

line_colorfill_color都是figure.contour可选关键字参数

  • 指定line_color才会绘制等值线;
  • 指定fill_color才会绘制填充多边形;
  • 二者既可以是标量(scalar),也可以是向量(vector)视觉属性。

重要长度约定:等值线视觉属性(如line_color)的向量长度为len(levels),而填充多边形视觉属性(如fill_colorhatch_color)的向量长度为len(levels)-1。原因在于等值线在每一层 level 上各有一组,而填充区域位于每对相邻 level 之间。

本例中line_color="black"是标量,因此每条等值线都渲染为纯黑实线;fill_color=Sunset8是向量(8 种颜色),于是相邻层级之间的填充区域以不同颜色呈现——这里的Sunset8恰好长度也是 8,与len(levels)-1 = 8精确匹配。

颜色条由 ContourRenderer 自动构建

右侧的颜色条通过ContourRenderer.construct_color_bar()获得,它自动复用等高线图的填充与线条视觉属性,无需手工同步颜色。随后用p.add_layout(colorbar, "right")放置到画布右侧。其底层实现见 contour_renderer.py:方法内部以fill_rendererline_rendererlevels以及由 levels 生成的FixedTicker构造一个 ContourColorBar 模型。

极坐标网格示例:向量视觉属性全面进阶

仓库中的 contour_polar.py 展示了极坐标网格与更多视觉属性:

import numpy as np from bokeh.palettes import Cividis from bokeh.plotting import figure, show # 数据是极坐标网格上的二维正弦波 radius, angle = np.meshgrid(np.linspace(0, 1, 20), np.linspace(0, 2*np.pi, 120)) x = radius*np.cos(angle) y = radius*np.sin(angle) z = 1 + np.sin(3*angle)*np.sin(np.pi*radius) p = figure(width=550, height=400) levels = np.linspace(0, 2, 11) contour_renderer = p.contour( x=x, y=y, z=z, levels=levels, fill_color=Cividis, hatch_pattern=["x"]*5 + [" "]*5, hatch_color="white", hatch_alpha=0.5, line_color=["white"]*5 + ["black"] + ["red"]*5, line_dash=["solid"]*6 + ["dashed"]*5, line_width=[1]*6 + [2]*5, ) colorbar = contour_renderer.construct_color_bar(title="Colorbar title") p.add_layout(colorbar, "right") show(p)

环绕自身的极坐标网格

网格由radius(20 个点)与angle(120 个点)网格化后投影到直角坐标得到,z随角度与半径正弦变化,因此网格在圆周方向自行环绕。极坐标网格与笛卡尔网格在 API 层面没有差别,xyz依然是一一对应的数组。

line、fill、hatch 三组视觉属性

此例用到了三类视觉属性,它们对应源码 contour.py 中引入的LinePropsFillPropsHatchProps三个属性混合类:

  • line 属性line_colorline_dashline_width
  • fill 属性fill_colorfill_alpha等;
  • hatch 属性hatch_patternhatch_colorhatch_alpha

本例中的向量长度全部符合约定:11 个 levels,因此 line 类向量长度为 11,fill/hatch 类向量长度为 10。向量化让"强调正负层级"这类需求变得直接——例如line_color前 5 个为白色、中间 1 个为黑色、后 5 个为红色,配合line_width前 6 个为 1、后 5 个为 2,正值区与负值区的等值线在粗细、颜色、虚实上都被区分开来。

颜色属性的两种额外指定方式

所有视觉属性都支持标量或正确长度的向量,但line_colorfill_colorhatch_color这类颜色视觉属性还额外支持两种便捷写法,其实现位于 contour.py 的 _color 函数:

  1. 任意长度颜色序列的自动重采样:传入的颜色序列若长度不等于所需长度(过长或过短),会被bokeh.palettes.interp_palette线性插值重采样到所需长度。长度为 256 的调色板(如Cividis256)在这种场景下特别有用。
  2. 调色板集合(Palette Collection):如Cividis,它本质上是"从调色板长度(颜色数)到调色板"的字典。若集合中恰好存在所需长度的调色板则直接使用;若所需长度超出集合覆盖范围,则取长度最接近的调色板做线性插值。插值细节见 _palette_from_collection:先在集合中精确查找,超长则对最长调色板插值,过短则对最短调色板插值。

颜色条的标题

construct_color_bar()接受任意关键字参数并透传给ContourColorBar构造函数,用于设置titleBaseColorBar属性。此外,由于ContourColorBar同时持有填充渲染器与线条渲染器(见 legends.py),它可以展示 hatch 图案与线型,这是普通颜色条不具备的能力。

动画等高线:在 Bokeh Server 中循环更新数据

等高线的计算发生在 Python 侧,因此用bokeh serve运行脚本即可轻松实现动画。仓库中的完整示例位于 contour_animated.py,运行方式:

bokeh serve --show contour_animated.py

动画的关键动作序列如下:

  1. 照常调用figure.contour(...),并保存返回的ContourRenderer对象;
  2. 计算更新后的z数组(例如从文件读取或实时计算得到);
  3. 将新的z保持不变xylevels一起传给bokeh.plotting.contour.contour_data,生成等高线数据对象;
  4. 调用ContourRenderer.set_data传入新的等高线数据对象;
  5. 回到第 2 步循环执行。

这一流程对应源码中的两个关键 API:

  • contour_data:返回一个ContourData数据类对象,内部包含FillData(填充多边形的 xs/ys 与lower_levels/upper_levels)和LineData(等值线 xs/ys 与levels)两部分;
  • ContourRenderer.set_data:把新数据写入内部的fill_rendererline_rendererColumnDataSource,同时保留旧的填充/线条视觉属性(只替换 xs、ys 与 levels 相关字段),从而实现视觉样式不重置的数据刷新。

需要说明的是,此动画方案的前提是网格、等高线层级与视觉属性保持不变。若这些也需要动态改变,虽然技术上可行,但必须小心处理画布边界变化以及视觉属性到等高线层级的重新分配;更稳妥的做法是移除旧的等高线图,再新建一个替换。

高级细节

必填与可选参数

figure.contour的签名见 _figure.py。唯一必填的关键字参数是:

  • z:二维数组,即待轮廓化的数据;
  • levels:等值层级序列;
  • fill_colorline_color至少指定一个

xy均为可选参数:

  • x可以是与z.shape相同的二维数组,或长度为nx = z.shape[1]的一维数组,且必须单调有序;
  • y可以是与z.shape相同的二维数组,或长度为ny = z.shape[0]的一维数组,且必须单调有序;
  • 两者都省略时,默认使用两个方向间距均为 1 的笛卡尔网格(等价于np.arange(nx)np.arange(ny))。

levels必须严格递增。源码 _validate_levels 会做三件事:拒绝缺失或空 levels、强制转换为float数组、校验相邻差值必须大于 0;若 levels 少于 2 个,填充区域将自动关闭(因为没有相邻层级对)。

排除网格点:Masked Array 与 NaN

要从等高线计算中排除某些网格点,有两种等价方式:

  1. z使用 NumPy 掩码数组(masked array),被掩码的网格点不参与计算;
  2. 将这些网格点的z值设为np.nan

源码层面,from_contour的 docstring(见 contour.py)明确说明:z可以是掩码数组,且任何无效值(np.infnp.nan)同样会被排除。

底层图形与计算引擎

  • 等值线使用MultiLine图形实现,填充多边形使用MultiPolygons图形实现(填充多边形的line_width被置为 0、line_alpha置为 0,避免填充区域边缘出现额外描边,见 contour.py);
  • 等高线几何计算由ContourPy完成。在 _contour_coords 中,Bokeh 以LineType.ChunkCombinedNan获取等值线(同一层级的多条线以np.nan分隔存储在一个数组中),以FillType.OuterOffset获取填充多边形(每个多边形由外边界与零个或多个孔洞组成),再转换为绘图所需的坐标数据结构;
  • 填充数据通过contourpy.ContourGenerator.filled(lower, upper)逐对相邻层级计算,等值线通过contourpy.ContourGenerator.lines(level)逐层级计算。

快速对照:API 一览

关注点用法仓库依据
创建等高线p.contour(x, y, z, levels, **visuals)_figure.py
底层构造器from_contour(x, y, z, levels, **visuals)contour.py
生成可复用的数据对象contour_data(x, y, z, levels, want_fill, want_line)contour.py
更新渲染器数据renderer.set_data(contour_data_obj)contour_renderer.py
构建颜色条renderer.construct_color_bar(title=...)contour_renderer.py
长度约定线:len(levels);填充/hatch:len(levels)-1contour.py
颜色自动插值任意长度序列经interp_palette重采样;调色板集合取最近长度插值[contour.py](https://link.gitcode.com/i/cfcf56ff5ba7c73055d696d583a7f517#L302-L310, L383-L404)

小结与建议

从入门到进阶,Bokeh 的等高线功能覆盖了:标量与向量视觉属性的一行式渲染、极坐标等非笛卡尔网格、自动同步样式的ContourColorBar、基于contour_data+set_data的服务端动画,以及掩码数组排除网格点等边界处理。建议下一步直接运行仓库中的三个示例(contour_simple.py、contour_polar.py、contour_animated.py)逐一验证上述行为;动画示例记得使用bokeh serve --show启动,因为等高线计算发生在 Python 进程中,静态 HTML 页面无法驱动这类循环刷新。

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

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

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

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

立即咨询