NumPy的两篇聊完了。今天说Matplotlib——Python的画图库。

做机器人算法开发,画图和写算法一样重要。你写了一个路径规划算法,不画出来怎么知道对不对?你跑了一个SLAM系统,不可视化轨迹怎么知道漂移了多少?

先说个事。

我之前面试一个做SLAM的候选人,聊到他的算法效果。他说"精度还不错"。面试官问:"你怎么评估的?有没有可视化的对比?"

他说:"我算了一个RMSE数值。"

面试官又问:"能把轨迹画出来看看吗?"

他愣了一下,说:"代码里没有画图的部分。"

这就有点减分了。做算法不画图,就像做实验不记录数据——你自己可能心里有数,但别人没法验证。

Matplotlib基础:五分钟画出第一张图

import matplotlib.pyplot as plt
import numpy as np

# 最简单的折线图
x = np.linspace(0, 10, 100)
y = np.sin(x)

plt.plot(x, y)
plt.xlabel("Time (s)")
plt.ylabel("Value")
plt.title("Sensor Signal")
plt.grid(True)
plt.savefig("signal.png", dpi=150)
plt.show()

这几行代码就能生成一张带标题、坐标轴标签、网格线的正弦波图。savefig保存图片到文件,show在窗口中显示。

在Jupyter Notebook里,加一行%matplotlib inline就能让图直接嵌在代码下方,做数据分析的时候特别方便。

机器人开发中的常用图表

散点图——画点云和地图

# 模拟2D激光雷达扫描
angles = np.linspace(-np.pi/2, np.pi/2, 360)
ranges = 5.0 + np.random.randn(360) * 0.1

x = ranges * np.cos(angles)
y = ranges * np.sin(angles)

plt.scatter(x, y, s=1, c='blue')
plt.axis('equal')
plt.title("Lidar Scan")
plt.show()

多子图——对比不同算法

fig, axes = plt.subplots(1, 3, figsize=(15, 5))

# 原始路径
axes[0].plot(path_x, path_y, 'b-')
axes[0].set_title("Original Path")

# 平滑后
axes[1].plot(smooth_x, smooth_y, 'g-')
axes[1].set_title("Smoothed Path")

# 对比
axes[2].plot(path_x, path_y, 'b-', label="Original")
axes[2].plot(smooth_x, smooth_y, 'r--', label="Smoothed")
axes[2].legend()

plt.tight_layout()
plt.savefig("path_comparison.png")

热力图——画代价地图

# 模拟代价地图
costmap = np.random.rand(50, 50)
costmap[20:30, 20:30] = 1.0  # 障碍物

plt.imshow(costmap, cmap='hot', interpolation='nearest')
plt.colorbar(label="Cost")
plt.title("Cost Map")
plt.show()

SLAM轨迹可视化

做SLAM最常用的一种图:估计轨迹vs真实轨迹的对比。

def plot_trajectory(estimated, ground_truth):
    """
    estimated, ground_truth: shape (N, 3), 每行是 [x, y, theta]
    """
    fig, ax = plt.subplots(1, 1, figsize=(8, 8))
    
    ax.plot(ground_truth[:, 0], ground_truth[:, 1], 
            'b-', linewidth=2, label="Ground Truth")
    ax.plot(estimated[:, 0], estimated[:, 1], 
            'r--', linewidth=2, label="Estimated")
    
    # 标记起点和终点
    ax.plot(ground_truth[0, 0], ground_truth[0, 1], 'go', markersize=10, label="Start")
    ax.plot(ground_truth[-1, 0], ground_truth[-1, 1], 'rs', markersize=10, label="End")
    
    ax.set_xlabel("X (m)")
    ax.set_ylabel("Y (m)")
    ax.set_title("SLAM Trajectory Comparison")
    ax.legend()
    ax.grid(True)
    ax.axis('equal')
    
    plt.tight_layout()
    plt.savefig("trajectory.png", dpi=150)
    plt.show()

这种图一画出来,算法效果一目了然。漂移了多少、哪里有回环校正、整体趋势对不对,全都能看到。

动态更新:实时显示传感器数据

Matplotlib还支持动态更新图表,适合实时显示传感器数据:

from matplotlib.animation import FuncAnimation

fig, ax = plt.subplots()
scatter = ax.scatter([], [], s=1)
ax.set_xlim(-10, 10)
ax.set_ylim(-10, 10)

def update(frame):
    # 每帧更新扫描数据
    angles = np.linspace(-np.pi/2, np.pi/2, 360)
    ranges = get_latest_scan()  # 获取最新扫描数据
    x = ranges * np.cos(angles)
    y = ranges * np.sin(angles)
    scatter.set_offsets(np.column_stack([x, y]))
    return scatter

ani = FuncAnimation(fig, update, interval=100)
plt.show()

这个在做调试工具的时候很有用——你可以实时看到激光雷达的扫描画面、机器人的位置更新等。

如果是三维数据的可视化,Matplotlib的mpl_toolkits.mplot3d模块也能应付。比如画三维点云或者三维轨迹,用ax.scatter3D和ax.plot3D就行。不过对于大规模的三维点云(几十万个点以上),Matplotlib会比较吃力,这时候建议用Open3D或者Mayavi这类专业的三维可视化库。

调试图表的小技巧

实际项目中画图经常需要反复调整参数,这里分享几个提效技巧。第一,用plt.subplots()一次性创建多个子图,比多次调用plt.figure()快很多。第二,在循环里画图一定要加plt.close()释放内存,不然跑几百次迭代后内存就爆了。第三,保存高清用plt.savefig并设置dpi=300和bbox_inches=tight,这样出来的图放报告里不会糊。面试时如果说调试SLAM算法全靠Matplotlib,面试官会觉得你确实干过实事。

给正在准备面试的你

Matplotlib在面试中很少直接考,但在实际工作中是必备技能。如果你面试的时候能展示几张自己画的算法效果图——SLAM轨迹对比、路径规划可视化、传感器数据分析图——比说一百句"我算法精度很高"都有说服力。

建议把你做过的算法项目都画几张图,保存到portfolio里。面试的时候拿出来,效果非常好。

下篇聊深度相机原理对比——结构光、ToF、双目各自优劣。这是传感器方向的基础知识,面试中经常被问到。


如果这篇文章对你有帮助,欢迎点赞、在看、转发三连。 你的支持是我持续更新的最大动力。

「机器人软件开发面试·从入门到精通」连载系列 上一篇:第72篇 NumPy进阶——矩阵运算与机器人运动学计算 下一篇预告:第74篇 ROS2中的Python——和C++节点的混合编程

有任何问题欢迎评论区留言,我会尽量回复。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐