如何在Matplotlib中绘制指定两点间、可指定波数且兼容多子图的波浪箭头
实现Matplotlib多子图兼容的波浪箭头绘制方法
之前做可视化需求时,正好需要在Matplotlib里给指定两点加带自定义波浪数的箭头,还得兼容多子图场景。参考了Ian Roberts提出的一个实用但已关闭的问题,加上hayk的优质解答,我花了不少时间调整代码适配多子图,现在把这个通用方法分享出来,大家不用再踩坑啦!
核心功能
- 支持在任意两点间绘制带自定义波浪数量的箭头
- 完美兼容Matplotlib多子图布局
- 可自定义箭头样式、波浪幅度等参数
实现代码
import matplotlib.pyplot as plt import numpy as np def draw_wavy_arrow(ax, x_start, y_start, x_end, y_end, num_waves=3, wave_amplitude=0.05, **arrow_kwargs): """ 在指定Axes上绘制两点间的波浪箭头 参数: ax: matplotlib.axes.Axes 对象,要绘制箭头的子图 x_start, y_start: 箭头起点坐标 x_end, y_end: 箭头终点坐标 num_waves: 波浪的数量,默认3 wave_amplitude: 波浪的幅度,默认0.05(相对坐标轴范围) **arrow_kwargs: 传递给plt.arrow的额外参数,比如color、linewidth等 """ # 获取坐标轴范围,计算相对幅度的实际值 x_range = ax.get_xlim()[1] - ax.get_xlim()[0] y_range = ax.get_ylim()[1] - ax.get_ylim()[0] abs_wave_amplitude = wave_amplitude * np.sqrt(x_range**2 + y_range**2) # 计算两点间的向量与长度 dx = x_end - x_start dy = y_end - y_start length = np.sqrt(dx**2 + dy**2) # 生成沿线段分布的归一化参数与波浪偏移 t = np.linspace(0, 1, 100 * num_waves) wave = abs_wave_amplitude * np.sin(2 * np.pi * num_waves * t) # 计算垂直于线段的单位向量,用于生成波浪偏移方向 perp_x = -dy / length perp_y = dx / length # 计算波浪线上的所有点坐标 x_points = x_start + dx * t + wave * perp_x y_points = y_start + dy * t + wave * perp_y # 绘制波浪线 ax.plot(x_points, y_points, **arrow_kwargs) # 在终点绘制箭头(稍微缩短起点避免和波浪线重叠) arrow_x_start = x_points[-20] arrow_y_start = y_points[-20] arrow_dx = x_end - arrow_x_start arrow_dy = y_end - arrow_y_start ax.arrow(arrow_x_start, arrow_y_start, arrow_dx, arrow_dy, head_width=0.02 * np.sqrt(x_range**2 + y_range**2), head_length=0.03 * np.sqrt(x_range**2 + y_range**2), fc=arrow_kwargs.get('color', 'black'), ec=arrow_kwargs.get('color', 'black')) # 示例用法 if __name__ == "__main__": # 创建1行2列的多子图布局 fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 4)) # 第一个子图:5个波浪的红色箭头 ax1.plot([0, 1], [0, 1], 'k--') draw_wavy_arrow(ax1, 0, 0, 1, 1, num_waves=5, wave_amplitude=0.08, color='red', linewidth=2) ax1.set_title('5个波浪的箭头') ax1.set_xlim(-0.1, 1.1) ax1.set_ylim(-0.1, 1.1) # 第二个子图:2个波浪的蓝色箭头 ax2.plot([0, 0.5], [1, 0], 'b--') draw_wavy_arrow(ax2, 0, 1, 0.5, 0, num_waves=2, wave_amplitude=0.05, color='blue', linewidth=1.5) ax2.set_title('2个波浪的箭头') ax2.set_xlim(-0.1, 0.6) ax2.set_ylim(-0.1, 1.1) plt.tight_layout() plt.show()
使用说明
- 调用时必须传入目标子图的
ax对象,这是兼容多子图的核心 num_waves可以自由调整波浪数量,数值越大波浪越密集wave_amplitude是相对幅度,会根据子图坐标轴范围自动计算实际偏移,避免不同尺度子图中波浪大小失衡- 通过
**arrow_kwargs可以传递Matplotlib线条和箭头的样式参数,比如颜色、线宽等
内容的提问来源于stack exchange,提问作者user46147




