首页编程开发Matplotlib【数据可视化(Matplo...

【数据可视化(Matplotlib篇)】46.绘制流线图streamplot()

本系列文章配套代码获取有以下两种途径:

  • 通过百度网盘获取:
链接:https://pan.baidu.com/s/1jG-rGG4QMuZu0t0kEEl7SA?pwd=mnsj 提取码:mnsj
  • 前往GitHub获取
https://github.com/returu/Data_Visualization





流线图是一种用于展示二维矢量场的可视化方式,它通过一系列平滑的曲线来表现场中每一点的流动方向和速度。与箭量图相比,流线图能更清晰地展示流动模式和趋势,是展现向量场、流体运动、电场分布等 “流动型” 数据的重要工具。
01

函数语法


Matplotlib streamplot()函数专门用于绘制流线图,其函数语法如下:
plt.streamplot(x, y, u, v, density=1, linewidth=None               color=None, cmap=None, norm=None, arrowsize=1               arrowstyle='-|>', minlength=0.1, transform=None,                zorder=None, start_points=None, maxlength=4.0                integration_direction='both'                broken_streamlines=True, *, data=None)
其中:
  • 核心参数:
  • x, y数组类型定义向量场的坐标。可以是 1D 数组(将被网格化为 2D)或 2D 数组(必须与 u 和 v 的形状匹配)。如果是 1D 数组,x 的长度对应网格的列数,y 的长度对应网格的行数
  • u, v2D 数组,表示向量场的分量,u 对应 x 方向的速度分量,对应 y 方向的速度分量。必须与 x 和 y 的网格形状相匹配。
  • 流线控制参数
  • density浮点数或元组,默认值为 1,控制流线的密度,值越大,流线越多。若为元组形式 (dx, dy),则分别控制 x 和 y 方向的密度
  • linewidth控制流线宽度,可传入固定值或数组,若为数组,其形状必须与 u 和 v 相同,用于根据数据值改变线宽
  • color颜色或数组,控制线的颜色。若为数组,其形状必须与 u 和 v 相同,用于根据数据值改变颜色
  • cmap当 color 为数组时使用的颜色映射。
  • norm用于将数据值标准化到 [0,1] 范围,配合 colormap 使用。

  • arrowsize流线中箭头的大小,默认值为 1,值越大箭头越明显。

  • arrowstyle箭头样式,可选项包括:‘-‘、’->’、'<-‘、’-[‘、’]-‘ 等

  • minlength流线的最小长度,以轴坐标为单位,默认值为 0.1。

  • start_points手动指定流线的起始点,形状为 (n, 2) 的数组,每行表示一个起始点 (x, y)

  • maxlength流线的最大长度,以平均步长的倍数表示,默认值为 4.0。

  • transform应用于所有流线的变换

  • 其他参数

  • zorder控制绘图元素的堆叠顺序,值越大越靠上。

  • integration_direction控制流线的积分方向,可选项包括:‘both’(同时向前后两个方向积分)、‘forward’只向前积分)、‘backward’只向后积分)。

  • broken_streamlines是否允许流线在遇到NaN或无限值时断开, 默认为True

  • data可索引对象,若提供,参数x, y, u, v, start_points可接受字符串s,解释为data[s]

通过调整这些参数,可以灵活控制流线的视觉效果。

# 创建网格
x = np.linspace(-2, 2, 100)
y = np.linspace(-2, 2, 100)
X, Y = np.meshgrid(x, y)

# 创建矢量场(一个简单的涡旋场)
U = -Y
V = X
# 计算流速大小
speed = np.sqrt(U**2 + V**2)

# 创建图形
plt.figure(figsize=(8, 6))

# 绘制流线图
streamplot = plt.streamplot(X, Y,                  # 网格点的x、y坐标
                            U, V,                  # 对应网格点的x、y方向速度分量
                            density=(2, 1),        # 流线密度(值越大,流线越多越密集)
                            color=speed,           # 根据流速着色
                            cmap='viridis',        # 颜色映射
                            linewidth=2*speed,     # 根据流速调整线宽
                            arrowsize=2,           # 箭头大小
                            arrowstyle='-|>'       # 箭头样式
                           )

# 添加颜色条
plt.colorbar(streamplot.lines, label='流速大小')

plt.title('涡旋流场可视化')
plt.xlabel('X轴')
plt.ylabel('Y轴')
plt.show()

可视化结果如下图所示:


02

使用示例


  • 示例 1:利用返回值修改流线图样式

streamplot()函数返回一个StreamplotSet对象,包含两个重要属性:

  • lines:表示流线的LineCollection对象;

  • arrows:表示箭头的PatchCollection对象。

通过修改这些对象的属性,我们可以实现更精细的样式定制。

import matplotlib.pyplot as plt
import numpy as np

# 生成示例数据 - 漩涡场
x = np.linspace(-3, 3, 30)
y = np.linspace(-3, 3, 30)
X, Y = np.meshgrid(x, y)

# 计算向量场(漩涡效果)
u = -Y
v = X
speed = np.sqrt(u**2 + v**2)  # 计算速度大小用于条件判断

# 创建包含三个子图的画布
fig, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(18, 6))
fig.suptitle('流线图样式修改对比', fontsize=16, fontweight='bold')

# --------------------------
# 1. 原始流线图
# --------------------------
stream1 = ax1.streamplot(
    X, Y, u, v,
    density=1.2,
    arrowsize=1.5,
    color='black'
)
ax1.set_title('1. 原始图', fontsize=14)
ax1.set_xlabel('X轴')
ax1.set_ylabel('Y轴')
ax1.set_aspect('equal')

# --------------------------
# 2. 整体修改后的流线图
# --------------------------
stream2 = ax2.streamplot(
    X, Y, u, v,
    density=1.2,
    arrowsize=1.5
)

# 修改所有流线属性
stream2.lines.set_color('teal')
stream2.lines.set_linewidth(1.5)
stream2.lines.set_alpha(0.8)

# 修改所有箭头属性
stream2.arrows.set_color('crimson')
stream2.arrows.set_alpha(0.9)
stream2.arrows.set_linewidth(1.2)
stream2.arrows.set_zorder(3)  # 确保箭头在流线上方

ax2.set_title('2. 整体修改后', fontsize=14)
ax2.set_xlabel('X轴')
ax2.set_ylabel('Y轴')
ax2.set_aspect('equal')

# --------------------------
# 3. 基于条件修改特定流线
# --------------------------
stream3 = ax3.streamplot(
    X, Y, u, v,
    density=1.2,
    arrowsize=1.5
)

# 根据速度大小设置不同流线的颜色和宽度
# 获取流线的数量(通过路径数量判断)
num_paths = len(stream3.lines.get_paths())
# 存储每个流线的颜色和宽度
colors = []
linewidths = []

# 为每个流线设置属性(基于对应位置的速度)
for i in range(num_paths):
    # 获取当前流线的路径对象
    path = stream3.lines.get_paths()[i]
    # 计算路径中点的索引(取路径顶点的中间位置)
    mid_point_idx = int(len(path.vertices)/2)
    # 获取中点的坐标(x_mid, y_mid)
    x_mid, y_mid = path.vertices[mid_point_idx]
    
    # 找到与中点最接近的速度数据点索引
    # 计算x轴上与x_mid最接近的点的索引
    x_idx = np.argmin(np.abs(x - x_mid))
    # 计算y轴上与y_mid最接近的点的索引
    y_idx = np.argmin(np.abs(y - y_mid))
    # 获取该位置的速度值
    speed_val = speed[y_idx, x_idx]
    
    # 根据速度设置颜色和线宽
    if speed_val > 2.0:
        colors.append('red')
        linewidths.append(2.5)
    elif speed_val > 1.0:
        colors.append('orange')
        linewidths.append(1.8)
    else:
        colors.append('blue')
        linewidths.append(1.0)

# 应用条件样式
stream3.lines.set_color(colors)
stream3.lines.set_linewidth(linewidths)

ax3.set_title('3. 基于速度的条件修改', fontsize=14)
ax3.set_xlabel('X轴')
ax3.set_ylabel('Y轴')
ax3.set_aspect('equal')

# 添加颜色说明图例
from matplotlib.lines import Line2D
legend_elements = [
    Line2D([0], [0], color='blue', lw=1.0, label='低速 (<=1.0)'),
    Line2D([0], [0], color='orange', lw=1.8, label='中速 (1.0-2.0)'),
    Line2D([0], [0], color='red', lw=2.5, label='高速 (>2.0)')
]
ax3.legend(handles=legend_elements, loc='upper right', fontsize=10)

plt.tight_layout()
plt.subplots_adjust(top=0.85)
plt.show()

可视化结果如下图所示:

  • 示例 2:与其他图表结合,增加视觉效果

流线图与其他图表结合使用,可以增强数据可视化的层次感和信息量。

例如,通过叠加散点图、等高线图来增强数据可视化效果:

from matplotlib.colors import LinearSegmentedColormap

# 生成基础数据 - 模拟流体流动场景
x = np.linspace(-5, 5, 50)
y = np.linspace(-5, 5, 50)
X, Y = np.meshgrid(x, y)

# 定义向量场(包含两个漩涡和一个中心障碍物)
u = -1 - X**2 + Y
v = 1 + X - Y**2

# 计算速度大小(用于颜色映射)
speed = np.sqrt(u**2 + v**2)

# 创建自定义颜色映射
colors = [(0.8, 0.9, 1), (0, 0.4, 0.8)]  # 浅蓝色到深蓝色
cmap = LinearSegmentedColormap.from_list('custom_cmap', colors, N=100)

# 创建2x2的子图布局
fig, axes = plt.subplots(1, 2, figsize=(10, 8))

# --------------------------
# 1. 流线图 + 散点图(标记关键点)
# --------------------------
ax1 = axes[0]
# 绘制流线图
stream1 = ax1.streamplot(X, Y, u, v, density=1.2, color=speed, cmap=cmap, linewidth=1)
# 添加颜色条
cbar1 = fig.colorbar(stream1.lines, ax=ax1, shrink=0.5)
cbar1.set_label('速度大小')

# 标记特殊点(停滞点和最大速度点)
stagnation_points = np.array([[0, 1], [-2, -1]])  # 停滞点坐标
max_speed_idx = np.unravel_index(np.argmax(speed), speed.shape)
max_speed_point = np.array([X[max_speed_idx], Y[max_speed_idx]])

# 绘制散点
ax1.scatter(stagnation_points[:, 0], stagnation_points[:, 1], 
           c='red', s=100, marker='x', label='停滞点')

ax1.set_title('1. 流线图 + 散点图', fontsize=14)
ax1.set_xlabel('X轴')
ax1.set_ylabel('Y轴')
ax1.legend()
ax1.set_aspect('equal')

# --------------------------
# 2. 流线图 + 等高线图(叠加标量场)
# --------------------------
ax2 = axes[1]
# 计算压力场(模拟数据,与速度成反比)
pressure = 100 - 0.5 * speed**2

# 绘制填充等高线图表示压力场
contour = ax2.contourf(X, Y, pressure, 20, cmap='viridis', alpha=0.5)
cbar2 = fig.colorbar(contour, ax=ax2, shrink=0.5)
cbar2.set_label('压力值')

# 在等高线图上叠加流线图
stream2 = ax2.streamplot(X, Y, u, v, density=1.2, color='black', linewidth=0.8, arrowsize=1)

ax2.set_title('2. 流线图 + 等高线图', fontsize=14)
ax2.set_xlabel('X轴')
ax2.set_ylabel('Y轴')
ax2.set_aspect('equal')

plt.show()

可视化结果如下图所示:



更多内容可以前往官网查看

https://matplotlib.org/stable/


本篇文章来源于微信公众号: 码农设计师

RELATED ARTICLES

欢迎留下您的宝贵建议

Please enter your comment!
Please enter your name here

- Advertisment -

Most Popular

Recent Comments