Python中如何基于不同尺寸网格点绘制3D表面图?
解决合并矩形网格点的3D表面图颜色映射问题
首先,你遇到的颜色映射失效问题,核心原因是两个独立的plot_surface调用会各自计算自己的颜色范围——也就是说,第一个表面用的是自身Z值的 min/max 来映射颜色,第二个表面也是如此,导致原本数值高的蓝色区域(应该显示红色)因为自身范围小而被映射成了蓝色。
方法一:统一颜色范围(快速修复)
最简单的解决方式是,先计算所有Z值的全局最小值和最大值,然后在两个plot_surface中统一指定vmin和vmax参数,让它们共享同一个颜色映射范围:
import matplotlib.pyplot as plt import numpy as np from matplotlib import cm # 假设你已经有了gridValue、x1/x2、y1/y2这些数据 fig = plt.figure() ax = fig.add_subplot(111, projection='3d') x1 = np.arange(0,2,1) x2 = np.arange(0,10,1) y1 = np.arange(0,5,1) y2 = np.arange(5,12,1) Y1, X1 = np.meshgrid(x1, y1) Y2, X2 = np.meshgrid(x2, y2) gridValue1 = gridValue[:10] gridValue2 = gridValue[10:] Z1 = gridValue1.reshape(X1.shape) Z2 = gridValue2.reshape(X2.shape) # 计算全局的Z值范围 global_min = min(Z1.min(), Z2.min()) global_max = max(Z1.max(), Z2.max()) # 绘制两个表面时统一指定vmin和vmax cset1 = ax.plot_surface(X1, Y1, Z1, cmap=cm.coolwarm, linewidth=0, antialiased=False, vmin=global_min, vmax=global_max) cset2 = ax.plot_surface(X2, Y2, Z2, cmap=cm.coolwarm, linewidth=0, antialiased=False, vmin=global_min, vmax=global_max) # 添加颜色条(注意只需要一个,因为颜色范围统一了) fig.colorbar(cset1, shrink=0.5, aspect=5) ax.set_xlabel('X') ax.set_ylabel('Y') ax.set_zlabel('σ ') plt.show()
这样两个表面就会使用同一个颜色映射规则,数值高的区域会正确显示为红色,低的显示为蓝色。
方法二:构造完整网格(更优雅的方式)
如果你不想分开绘制,还可以先构造一个完整的大网格,把没有数据的区域设为NaN,然后一次性绘制,这样天然就会有统一的颜色映射:
import matplotlib.pyplot as plt import numpy as np from matplotlib import cm # 构造完整的X、Y网格 x_full = np.arange(0,10,1) y_full = np.arange(0,12,1) X_full, Y_full = np.meshgrid(x_full, y_full) # 初始化Z_full为NaN Z_full = np.full(X_full.shape, np.nan) # 填充第一个矩形区域(y从0到4,x从0到1) Z_full[0:5, 0:2] = gridValue[:10].reshape(5,2) # 填充第二个矩形区域(y从5到11,x从0到9) Z_full[5:12, 0:10] = gridValue[10:].reshape(7,10) fig = plt.figure() ax = fig.add_subplot(111, projection='3d') # 一次性绘制完整表面,NaN区域会自动被忽略 cset = ax.plot_surface(X_full, Y_full, Z_full, cmap=cm.coolwarm, linewidth=0, antialiased=False) fig.colorbar(cset, shrink=0.5, aspect=5) ax.set_xlabel('X') ax.set_ylabel('Y') ax.set_zlabel('σ ') plt.show()
这种方法更接近你最开始尝试的完整网格绘制思路,而且不需要分开处理两个表面,颜色映射自然是统一的,也避免了reshape错误(因为我们是按实际数据位置填充到完整网格的对应区域)。
补充说明
- 你最开始遇到的
ValueError: cannot reshape array of size 80 into shape (12,10),是因为完整网格(12,10)需要120个点,但你只有80个有效数据点,直接reshape肯定不行——上面的方法二通过填充NaN解决了这个问题。 clabel方法通常是给等高线图(contour)用的,plot_surface并不支持clabel,所以你之前的ax.clabel(cset1)其实不会生效,建议去掉这两行代码。
内容的提问来源于stack exchange,提问作者santobedi
相关产品推荐
相关产品推荐

