如何基于无序x、y、z数据生成Numpy网格并绘制Matplotlib填充等高线图?
嘿,我明白你现在的困扰——用循环给mesh_z赋值虽然能搞定,但总觉得不够优雅,而且数据量大的话效率也不高对吧?其实有两种更高效简洁的方法,完全不用手动循环,一起来看看:
方法1:纯Numpy向量式操作(高效首选)
利用np.unique的return_inverse参数,我们可以直接拿到原始数据在去重后数组中的位置索引,然后一步完成mesh_z的填充,全程没有循环:
import numpy as np import matplotlib.pyplot as plt x_data = [2, 2, 2, 3, 3, 3, 1, 1, 1, 4, 4, 4] y_data = [16, 64, 32, 64, 32, 16, 16, 32, 64, 32, 16, 64] z_data = [64, 31, 29, 78, 72, 63, 93, 40, 54, 35, 44, 3] # 获取去重后的x/y值,以及原始值对应的索引位置 x_unique, x_idx = np.unique(x_data, return_inverse=True) y_unique, y_idx = np.unique(y_data, return_inverse=True) # 定义mesh的形状(去重后x的长度 × 去重后y的长度) mesh_shape = (len(x_unique), len(y_unique)) # 直接通过索引映射填充mesh_z,不用循环! mesh_z = np.zeros(mesh_shape) mesh_z[x_idx, y_idx] = z_data # 生成meshgrid时注意用indexing='ij',和我们的索引维度对应 mesh_x, mesh_y = np.meshgrid(x_unique, y_unique, indexing='ij') # 绘制填充等高线图 plt.contourf(mesh_x, mesh_y, mesh_z) plt.colorbar() plt.xlabel('X') plt.ylabel('Y') plt.show()
这里的关键是return_inverse参数——它返回的是原始数组每个元素在去重后数组中的下标,这样我们就能直接用这些下标作为mesh_z的索引,一次性把所有z值填进去,比循环快得多,尤其是数据量大的时候。
方法2:用Pandas透视表(简洁易读)
如果你熟悉Pandas,用pivot方法可以一行搞定数据的二维转换,代码可读性拉满:
import pandas as pd import numpy as np import matplotlib.pyplot as plt x_data = [2, 2, 2, 3, 3, 3, 1, 1, 1, 4, 4, 4] y_data = [16, 64, 32, 64, 32, 16, 16, 32, 64, 32, 16, 64] z_data = [64, 31, 29, 78, 72, 63, 93, 40, 54, 35, 44, 3] # 把数据转成DataFrame df = pd.DataFrame({'x': x_data, 'y': y_data, 'z': z_data}) # 透视表直接把x作为行、y作为列,z作为值自动填充 pivot_df = df.pivot(index='x', columns='y', values='z') # 从透视表中提取对应的mesh数据 mesh_x, mesh_y = np.meshgrid(pivot_df.columns, pivot_df.index) mesh_z = pivot_df.values # 绘图 plt.contourf(mesh_x, mesh_y, mesh_z) plt.colorbar() plt.show()
Pandas会自动帮你处理去重、排列和填充,完全不用关心索引的问题,代码非常简洁,适合快速验证和小数据量场景。
方法对比
- Numpy方法:纯向量操作,没有Python级别的循环,效率最高,适合处理大规模数据;
- Pandas方法:代码更直观,易读性强,适合数据探索和小批量数据处理。
你的原始循环方法虽然可行,但每次循环都要执行一次布尔索引匹配,当数据量变大时,这种逐元素操作的效率会明显低于上面两种向量式方法。
内容的提问来源于stack exchange,提问作者Lenwo
相关产品推荐
相关产品推荐

