非均匀坐标下多元函数等高线绘制问题:网格创建与遮罩困惑
解决非均匀坐标下多元函数等高线绘制的遮罩问题
针对你遇到的问题,这里提供两种实用的解决方案,核心思路都是通过遮罩超出目标定义域的区域来得到符合预期的等高线图:
方法一:MeshGrid + 插值 + 遮罩(适用于常规contourf)
这种方法先生成覆盖坐标范围的网格,通过插值得到网格上的函数值,再将超出定义域的部分标记为无效值(np.nan),让contourf自动忽略这些区域。
代码示例
import numpy as np import matplotlib.pyplot as plt from scipy.spatial import Delaunay from scipy.interpolate import LinearNDInterpolator # 1. 模拟非均匀分布的原始坐标与函数值(替换成你的真实数据) np.random.seed(42) n = 500 x = np.random.uniform(-2, 2, n) y = np.random.uniform(-2, 2, n) # 模拟目标定义域:圆形区域内的点 mask_original = x**2 + y**2 <= 4 x = x[mask_original] y = y[mask_original] z = x**2 + y**2 # 你的多元函数值 # 2. 生成覆盖x、y范围的网格 xi, yi = np.meshgrid( np.linspace(x.min(), x.max(), 200), np.linspace(y.min(), y.max(), 200) ) # 3. 判断网格点是否在原始点的凸包内(适用于凸定义域) tri = Delaunay(np.column_stack((x, y))) # 找出所有在凸包内的网格点 mask_grid = tri.find_simplex(np.column_stack((xi.flatten(), yi.flatten()))) >= 0 mask_grid = mask_grid.reshape(xi.shape) # 4. 插值得到网格上的函数值 interp = LinearNDInterpolator(tri, z) zi = interp(xi, yi) # 5. 遮罩超出定义域的区域(设为nan,contourf会自动忽略) zi[~mask_grid] = np.nan # 6. 绘制等高线图 plt.figure(figsize=(8, 6)) contour = plt.contourf(xi, yi, zi, levels=20, cmap='viridis') plt.scatter(x, y, c='red', s=5, label='原始数据点') plt.colorbar(contour) plt.legend() plt.xlabel('x') plt.ylabel('y') plt.title('非均匀坐标下的等高线图(凸定义域)') plt.show()
非凸定义域的适配
如果你的目标定义域是非凸的(比如多边形挖洞),可以用matplotlib.path.Path自定义定义域边界,再判断网格点是否在定义域内:
from matplotlib.path import Path # 定义非凸定义域的路径(示例:大正方形挖去小正方形) vertices = np.array([ [-2,-2], [2,-2], [2,2], [-2,2], # 外边界 [-1,-1], [-1,1], [1,1], [1,-1] # 内边界(挖洞) ]) # 路径指令:MOVETO=起点,LINETO=连线,CLOSEPOLY=闭合 codes = [ Path.MOVETO, Path.LINETO, Path.LINETO, Path.LINETO, Path.CLOSEPOLY, Path.MOVETO, Path.LINETO, Path.LINETO, Path.LINETO, Path.CLOSEPOLY ] domain_path = Path(vertices, codes) # 判断所有网格点是否在定义域内 mask_grid = domain_path.contains_points(np.column_stack((xi.flatten(), yi.flatten()))) mask_grid = mask_grid.reshape(xi.shape) # 后续步骤同前:插值→遮罩→绘制 zi[~mask_grid] = np.nan
方法二:改进Tricontourf(直接筛选有效三角形)
如果你更倾向于用tricontourf,可以通过筛选重心在目标定义域内的三角形,避免绘制超出范围的区域:
import numpy as np import matplotlib.pyplot as plt from scipy.spatial import Delaunay from matplotlib.path import Path # 模拟数据同方法一 np.random.seed(42) n = 500 x = np.random.uniform(-2, 2, n) y = np.random.uniform(-2, 2, n) mask_original = x**2 + y**2 <= 4 x = x[mask_original] y = y[mask_original] z = x**2 + y**2 # 定义定义域路径(示例为圆形,可替换为你的自定义边界) theta = np.linspace(0, 2*np.pi, 100) circle_vertices = np.array([2*np.cos(theta), 2*np.sin(theta)]).T domain_path = Path(circle_vertices) # 生成三角剖分 tri = Delaunay(np.column_stack((x, y))) # 计算每个三角形的重心 triangle_centers = np.column_stack([ np.mean(x[tri.simplices], axis=1), np.mean(y[tri.simplices], axis=1) ]) # 筛选重心在定义域内的三角形 valid_triangles = tri.simplices[domain_path.contains_points(triangle_centers)] # 绘制tricontourf plt.figure(figsize=(8, 6)) plt.tricontourf(x, y, z, levels=20, cmap='viridis', triangles=valid_triangles) plt.scatter(x, y, c='red', s=5) plt.colorbar() plt.title('非均匀坐标下的tricontourf(遮罩无效三角形)') plt.show()
关键说明
- 凸定义域下,
Delaunay.find_simplex是判断点是否在定义域内的高效方法;非凸定义域则用Path.contains_points自定义边界。 - 将超出区域的函数值设为
np.nan后,contourf会自动跳过这些区域的绘制。 tricontourf的核心是筛选有效三角形,只绘制重心在目标定义域内的三角区域,避免延伸出范围。
内容的提问来源于stack exchange,提问作者Mohamed Obeid
相关产品推荐
相关产品推荐

