matplotlib绘制3D曲面时qhull Delaunay三角剖分错误如何解决
错误成因
- 数据读取逻辑错误:你使用
np.genfromtxt读取带4个字段的结构化数组后,直接用zip(*data)解包会得到4组序列(对应x/y/z/k四个字段),赋值给x/y/z三个变量时会出现隐式截断,把k字段的值混入z轴数据,导致输入给三角剖分的坐标数据完全错乱。 - 输入数据不符合Delaunay三角剖分要求:
plot_trisurf依赖qhull库对xy平面的点做三角剖分,若数据中存在重复的(x,y)坐标、共线点过多、存在空值,都会触发剖分失败的报错。 - 分类变量未做分组处理:你的数据中包含取值为0/1的分类变量k,不同k类的样本混在一起绘制曲面,会导致xy平面的点分布不符合连续曲面的剖分逻辑。
修复方案
首先修正数据读取逻辑,提前做数据清洗,可根据需求选择两种绘图方案:
方案1:按k值分组绘制三角曲面(保留原始数据分布)
修复后的代码如下:
import numpy as np import matplotlib.pyplot as plt # 修正数据读取逻辑,直接提取对应字段 data = np.genfromtxt("data.csv", delimiter=",", names=["x", "y","z","k"]) x = data['x'] y = data['y'] z = data['z'] k = data['k'] # 数据清洗:去除空值、去重xy重复的点 valid_mask = ~np.isnan(x) & ~np.isnan(y) & ~np.isnan(z) x, y, z, k = x[valid_mask], y[valid_mask], z[valid_mask], k[valid_mask] # 去重:保留每个(x,y)坐标的第一个样本 _, unique_idx = np.unique(np.column_stack((x, y)), axis=0, return_index=True) x, y, z, k = x[unique_idx], y[unique_idx], z[unique_idx], k[unique_idx] # 按k值分组绘图 fig = plt.figure(figsize=(12,6)) for idx, k_val in enumerate([0,1]): mask = k == k_val x_k, y_k, z_k = x[mask], y[mask], z[mask] ax = fig.add_subplot(1, 2, idx+1, projection='3d') ax.set_xlabel('X') ax.set_ylabel('Y') ax.set_zlabel('Optimal-Selection') ax.set_xlim(0,1) ax.set_ylim(0,1) ax.set_zlim(0,1) ax.set_title(f'k = {k_val}') surf = ax.plot_trisurf(x_k, y_k, z_k, cmap='viridis') fig.colorbar(surf, shrink=0.5, aspect=9, ax=ax) plt.show()
方案2:插值生成规则网格后绘制曲面(更平滑,无剖分错误)
如果分组后仍然存在三角剖分错误,可以先对数据做二维插值生成规则网格再绘图,代码如下:
import numpy as np import matplotlib.pyplot as plt from scipy.interpolate import griddata data = np.genfromtxt("data.csv", delimiter=",", names=["x", "y","z","k"]) x = data['x'] y = data['y'] z = data['z'] k = data['k'] valid_mask = ~np.isnan(x) & ~np.isnan(y) & ~np.isnan(z) x, y, z, k = x[valid_mask], y[valid_mask], z[valid_mask], k[valid_mask] # 生成0-1区间的规则网格 xi = np.linspace(0, 1, 100) yi = np.linspace(0, 1, 100) xi, yi = np.meshgrid(xi, yi) fig = plt.figure(figsize=(12,6)) for idx, k_val in enumerate([0,1]): mask = k == k_val x_k, y_k, z_k = x[mask], y[mask], z[mask] # 插值得到网格对应的z值 zi = griddata((x_k, y_k), z_k, (xi, yi), method='cubic') ax = fig.add_subplot(1, 2, idx+1, projection='3d') ax.set_xlabel('X') ax.set_ylabel('Y') ax.set_zlabel('Optimal-Selection') ax.set_xlim(0,1) ax.set_ylim(0,1) ax.set_zlim(0,1) ax.set_title(f'k = {k_val}') surf = ax.plot_surface(xi, yi, zi, cmap='viridis') fig.colorbar(surf, shrink=0.5, aspect=9, ax=ax) plt.show()
内容的提问来源于stack exchange,提问作者ash goharam
相关产品推荐
相关产品推荐

