如何使用 Matplotlib 绘制圆形温度热力图?

来源:网站主作者:孙志远头衔:网络博主
导读:本期聚焦于孙志远创作的《如何使用 Matplotlib 绘制圆形温度热力图?》,敬请观看详情。圆形温度热力图常用于展示环形截面、管道或旋转机械的温度分布,它把角度和半径作为坐标,用颜色表达温度高低。Matplotlib 本身没有专门的圆形热力图函数,但借助极坐标投影与 pcolormesh 或 contourf,可以快速实现。实现关键在于将角度转换为弧度、构造半径网格、选择合适的颜色映射,并处理极坐标下的网格对齐。文中会从数据准备讲起,逐步搭建一个完整的绘制流程,并给出消除中心空白、调整颜色区间、添加极坐标刻度与颜色条的代码示例。文章还讨论了插值、颜色映射选择以及实际数据导入时容易踩到的几个坑。

圆形温度热力图和普通方格热力图最大的区别在于坐标系统:前者使用角度与半径描述位置,后者使用横纵坐标。它特别适合表达管道截面、环形反应器、轴承端面等圆形区域的温度分布,因为物理形状与图形一一对应,观察起来更直观。Matplotlib 没有提供现成的圆形热力图接口,但可以借助极坐标投影加上 pcolormesh 或 contourf 快速构建。实现过程中需要重点处理三件事:把角度从度数转换成弧度、构造与温度数组形状一致的二维角度和半径网格、根据数据范围选择合适的颜色映射。本文会从极坐标网格的构造讲起,逐步给出绘制、美化、导入真实数据的完整代码,并说明中心空白、角度方向、颜色条映射等常见问题的处理方式。

如何使用 Matplotlib 绘制圆形温度热力图?

一、极坐标网格的构造与温度数据组织

在直角坐标热力图中,x 和 y 分别表示水平与垂直位置,z 表示温度。而在圆形热力图中,位置由角度 θ 和半径 r 共同决定,温度仍然作为第三维。Matplotlib 的极坐标投影要求 pcolormesh 的前两个参数分别是角度和半径,并且它们都是二维数组。不少第一次接触的人会直接传入一维的角度和半径数组,结果要么报形状不匹配,要么只画出单条弧带。

正确做法是先确定角度范围和半径范围,再用 numpy.meshgrid 生成二维网格。角度通常取 0 到 2π 的弧度值,半径则从内半径到外半径。内半径不一定是 0,如果被测区域本身是圆环,例如管道截面,可以直接从内壁半径开始,这样能避免中心出现无意义的空白。温度数据也要组织成与网格相同的形状,每一行对应一个半径,每一列对应一个角度。下面这段代码构造了一个从 0 到 360 度、半径从 20 到 50 的示例温度场。

import numpy as np
import matplotlib.pyplot as plt

theta = np.linspace(0, 2 * np.pi, 180)
radius = np.linspace(20, 50, 60)
theta_grid, radius_grid = np.meshgrid(theta, radius)

# 用一个与角度和半径相关的函数模拟温度分布
temperature = 80 + 40 * np.sin(3 * theta_grid) - 0.8 * (radius_grid - 35) ** 2
print(theta_grid.shape, radius_grid.shape, temperature.shape)

这里的 theta_grid 和 radius_grid 都是 60 行 180 列的数组,temperature 的形状也完全相同。角度网格每一行都是相同的角度序列,半径网格每一列都是相同的半径序列。这样 pcolormesh 在绘制时就能知道每个网格单元对应哪个角度区间和半径区间。

二、用 pcolormesh 绘制首个圆形热力图

绘制极坐标热力图需要使用 subplot 的 projection 参数创建极坐标轴。调用方式为 plt.subplots(subplot_kw={'projection': 'polar'}),然后在这个轴上调用 pcolormesh。注意参数顺序不能颠倒:第一个是角度,第二个是半径,第三个是温度值。如果顺序写反,图形会被拉伸成奇怪的形状,而且颜色分布完全错误。

颜色映射是热力图的关键。对于温度数据,coolwarm 是常见选择,它能把低温和高温直观地区分开;如果只关心温度高低变化而不强调正负差异,plasma 或 inferno 的亮度变化更明显。添加颜色条时使用 fig.colorbar,需要把 pcolormesh 返回的对象传进去。下面的代码生成了最基本的圆形温度热力图。

import numpy as np
import matplotlib.pyplot as plt

theta = np.linspace(0, 2 * np.pi, 360)
radius = np.linspace(20, 50, 80)
theta_grid, radius_grid = np.meshgrid(theta, radius)
temperature = 90 + 30 * np.cos(2 * theta_grid) - 0.05 * (radius_grid - 30) ** 3

fig, ax = plt.subplots(subplot_kw={'projection': 'polar'}, figsize=(8, 8))
mesh = ax.pcolormesh(theta_grid, radius_grid, temperature, cmap='coolwarm', shading='auto')
fig.colorbar(mesh, ax=ax, pad=0.1, label='Temperature (°C)')
ax.set_title('Circular Temperature Distribution', va='bottom')
plt.show()

运行这段代码后,会得到一个完整的圆环热力图。如果半径从 0 开始,中心会留出一个半径很小的空白区域,这是极坐标绘制中常见的现象。中心空白不一定需要消除,因为它在物理上可能对应轴心或非测量区;如果确实需要覆盖中心,可以把半径起点设为 0,并增加中心区域的温度插值。

另外,shading='auto' 可以让 Matplotlib 根据网格自动选择着色方式,避免出现网格边界与颜色块错位的问题。对于较新的 Matplotlib 版本,shading 默认值可能改为 'flat',当网格尺寸不均匀时容易出现视觉误差,建议显式设置为 'auto' 或 'nearest'。

三、极坐标细节优化:角度方向、网格与颜色区间

默认情况下,Matplotlib 极坐标的 0 度位置在右侧,角度沿逆时针方向增加。很多工程图纸习惯把 0 度放在正上方,并沿顺时针旋转。可以通过 set_theta_zero_location('N') 和 set_theta_direction(-1) 调整。前者接受 'N'、'E'、'S'、'W' 或弧度值,后者用 1 表示逆时针,-1 表示顺时针。这类细节对圆形温度热力图影响很大,尤其当数据来自圆周分布传感器时,角度起始位置不一致会导致整个温度场旋转。

网格线也值得单独控制。默认的极坐标网格包含角度射线和半径圆环,有时会干扰颜色表达。可以关闭角度网格只保留半径刻度,或者完全隐藏网格后手动添加需要的标注。ax.grid(False) 会关闭所有网格,而 ax.set_xticks 和 ax.set_yticks 可以自定义刻度位置。

温度区间的统一同样重要。如果多张子图共用同一个颜色条,必须保证 Normalize 范围一致。使用 matplotlib.colors.Normalize 或 LogNorm 可以固定映射范围,避免不同图之间颜色不可比。下面这段代码展示了如何固定颜色范围并调整角度方向。

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import Normalize

theta = np.linspace(0, 2 * np.pi, 360)
radius = np.linspace(15, 55, 100)
theta_grid, radius_grid = np.meshgrid(theta, radius)
temp = 70 + 50 * np.sin(4 * theta_grid) - 0.2 * (radius_grid - 35) ** 2

norm = Normalize(vmin=0, vmax=130)
fig, ax = plt.subplots(subplot_kw={'projection': 'polar'}, figsize=(8, 8))
ax.set_theta_zero_location('N')
ax.set_theta_direction(-1)
ax.set_xticks(np.linspace(0, 2 * np.pi, 8, endpoint=False))
ax.set_xticklabels(['0°', '45°', '90°', '135°', '180°', '225°', '270°', '315°'])
ax.set_yticks([20, 35, 50])
ax.set_yticklabels(['20 mm', '35 mm', '50 mm'])
ax.grid(True, linestyle='--', alpha=0.4)
mesh = ax.pcolormesh(theta_grid, radius_grid, temp, cmap='plasma', norm=norm)
fig.colorbar(mesh, ax=ax, pad=0.08, label='Temperature (°C)')
ax.set_title('Optimized Circular Temperature Map', va='bottom')
plt.show()

在这段代码里,Normalize 把颜色映射限制在 0 到 130 摄氏度之间,即使当前数据只覆盖了部分区间,颜色条也会按完整范围显示,便于与其他子图比较。角度刻度被设置为 8 个方向,半径刻度只保留 20、35、50 三个位置,图形更简洁。

四、真实数据导入与常见问题排查

实际项目中温度数据通常不是规则网格,而是来自布置在圆周上的若干传感器。例如 12 个角度位置、5 个径向位置,得到 60 个离散温度读数。要绘制成连续热力图,需要把这些离散点插值到密集的极坐标网格上。scipy.interpolate.griddata 可以完成这项工作,它接受散点坐标和对应值,输出规则网格上的插值结果。

插值前必须将角度从度数转换为弧度,并且注意角度是周期性的。0 度和 360 度在物理上是同一个位置,如果传感器数据只覆盖到 355 度,直接插值会在 355 度到 360 度之间留下空白。解决方法是在数据末尾复制一份 0 度数据并标记为 360 度,形成闭合环。

下面是一个简单的插值示例,假设已有 angle_deg、radius_mm、temp_values 三个一维数组,长度相同。

import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import griddata

# 示例散点数据
angle_deg = np.array([0, 60, 120, 180, 240, 300, 0, 60, 120, 180, 240, 300])
radius_mm = np.array([20, 20, 20, 20, 20, 20, 40, 40, 40, 40, 40, 40])
temp_values = np.array([68, 72, 84, 90, 85, 75, 55, 60, 78, 88, 80, 62])

angle_rad = np.deg2rad(angle_deg)
theta_new = np.linspace(0, 2 * np.pi, 360)
radius_new = np.linspace(20, 40, 60)
theta_grid, radius_grid = np.meshgrid(theta_new, radius_new)

# 把极坐标散点转换为直角坐标后插值
x = radius_mm * np.cos(angle_rad)
y = radius_mm * np.sin(angle_rad)
x_grid = radius_grid * np.cos(theta_grid)
y_grid = radius_grid * np.sin(theta_grid)
temp_grid = griddata((x, y), temp_values, (x_grid, y_grid), method='cubic', fill_value=np.nan)

fig, ax = plt.subplots(subplot_kw={'projection': 'polar'}, figsize=(8, 8))
mesh = ax.pcolormesh(theta_grid, radius_grid, temp_grid, cmap='coolwarm', shading='auto')
fig.colorbar(mesh, ax=ax, pad=0.1, label='Temperature (°C)')
ax.set_title('Interpolated Temperature Field from Sensors', va='bottom')
plt.show()

在插值过程中,如果某些网格点离所有传感器都很远,griddata 会返回 NaN,这时可以在 pcolormesh 前用 np.nan_to_num 替换为平均值,或者设置 fill_value 为某个背景温度。另一个常见错误是忘记转换弧度,直接用度数作为极坐标角度,结果会画出很多重复的扇形。还有人在调用 pcolormesh 时把半径和角度的顺序写反,图形会变成放射状条纹。只要掌握网格构造和坐标转换这两个核心点,圆形温度热力图就能稳定输出。

Matplotlib温度热力图圆形热力图修改时间:2026-10-02 18:14:26

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/1002/64776.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。