You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

单等高线图中多函数求和绘图异常问题排查

问题分析与解决

问题现象

在等高线图中绘制三个仅坐标参数不同的同类型函数求和结果时,单独绘制每个函数均正常,但求和后绘图会裁剪掉非三个函数共有的点位,推测问题出在mask处理逻辑上。

原代码

import numpy as np
import matplotlib.pyplot as plt

xx = np.linspace(-200, 200, 200)
yy = np.linspace(-200, 200, 200)
X, Y = np.meshgrid(xx, yy)
        
r1 = np.sqrt(np.square(X) + np.square(Y))
r2 = np.sqrt(np.square(20 - X) + np.square(20 - Y))
r3 = np.sqrt(np.square(-40 - X) + np.square(40 - Y))

# 坐标1对应的函数
Z1 = 3 * (r1/100)**4 - 8 * (r1/100)**3 + 6 * (r1/100)**2
Z1 = np.ma.array(Z1, mask=r1>=100)

# 坐标2对应的函数
Z11 = 3 * (r2/100)**4 - 8 * (r2/100)**3 + 6 * (r2/100)**2
Z11 = np.ma.array(Z11, mask=r2>=100)

# 坐标3对应的函数
Z21 = 3 * (r3/100)**4 - 8 * (r3/100)**3 + 6 * (r3/100)**2
Z21 = np.ma.array(Z21, mask=r3>=100)

# 函数求和
Z01 = Z1 + Z11 + Z21

cs = plt.contour(X, Y, Z01, 20, cmap=plt.cm.YlGn_r, levels = 10, extend='max')
cs2 = plt.contourf(X, Y, Z01, 20,cmap=plt.cm.YlOrBr, levels = 10, extend='max')

plt.clabel(cs2)
plt.clabel(cs, fontsize=10, colors=plt.cm.Reds(cs.norm(cs.levels)))
plt.colorbar(cs2)
plt.grid(which='major')
plt.title('Contours Plot')
plt.xlabel('X (m)')
plt.ylabel('Y (m)')
plt.xlim([0, 200])
plt.ylim([0, 200])
plt.axis('scaled')

plt.tight_layout()
plt.show()

效果对比

  • 单函数等高线图:
    单函数等高线图
  • 求和后等高线图:
    求和后等高线图

问题原因

numpy.ma掩码数组的加法规则是:只要任一数组的某点位被掩码,求和结果的该点位就会被掩码。原代码中三个函数各自的掩码范围不同,求和后掩码是三个掩码的并集,导致只有三个函数都未被掩码的区域才会显示,非共有的点位被全部裁剪。

解决方案

方案1:将超出范围的函数值设为0后求和

去掉单个函数的掩码操作,直接将超出作用范围的函数值设为0,这样求和后能保留所有单个函数覆盖的区域:

import numpy as np
import matplotlib.pyplot as plt

xx = np.linspace(-200, 200, 200)
yy = np.linspace(-200, 200, 200)
X, Y = np.meshgrid(xx, yy)
        
r1 = np.sqrt(np.square(X) + np.square(Y))
r2 = np.sqrt(np.square(20 - X) + np.square(20 - Y))
r3 = np.sqrt(np.square(-40 - X) + np.square(40 - Y))

# 坐标1对应的函数:超出范围设为0
Z1 = 3 * (r1/100)**4 - 8 * (r1/100)**3 + 6 * (r1/100)**2
Z1[r1 >= 100] = 0

# 坐标2对应的函数:超出范围设为0
Z11 = 3 * (r2/100)**4 - 8 * (r2/100)**3 + 6 * (r2/100)**2
Z11[r2 >= 100] = 0

# 坐标3对应的函数:超出范围设为0
Z21 = 3 * (r3/100)**4 - 8 * (r3/100)**3 + 6 * (r3/100)**2
Z21[r3 >= 100] = 0

# 函数求和
Z01 = Z1 + Z11 + Z21

# 可选:仅掩码三个函数都超出范围的区域
mask = (r1 >= 100) & (r2 >= 100) & (r3 >= 100)
Z01 = np.ma.array(Z01, mask=mask)

cs = plt.contour(X, Y, Z01, 20, cmap=plt.cm.YlGn_r, levels = 10, extend='max')
cs2 = plt.contourf(X, Y, Z01, 20,cmap=plt.cm.YlOrBr, levels = 10, extend='max')

plt.clabel(cs, fontsize=10, colors=plt.cm.Reds(cs.norm(cs.levels)))
plt.colorbar(cs2)
plt.grid(which='major')
plt.title('Contours Plot')
plt.xlabel('X (m)')
plt.ylabel('Y (m)')
plt.xlim([0, 200])
plt.ylim([0, 200])
plt.axis('scaled')

plt.tight_layout()
plt.show()

方案2:保留掩码但替换掩码值为0后求和

如果坚持使用掩码数组,可通过np.ma.filled将掩码区域的值替换为0,再进行求和:

# 替换原求和步骤
Z01 = np.ma.filled(Z1, 0) + np.ma.filled(Z11, 0) + np.ma.filled(Z21, 0)
# 可选:掩码三个函数都超出范围的区域
mask = (r1 >=100) & (r2 >=100) & (r3 >=100)
Z01 = np.ma.array(Z01, mask=mask)

关键说明

  • 掩码数组的加法逻辑是导致问题的核心:只要任意一个数组元素被掩码,结果元素就会被掩码。
  • 将超出范围的函数值设为0,既符合“超出作用范围后函数无贡献”的物理意义,又能保留所有单个函数覆盖的区域,求和后可显示完整的等高线。

内容的提问来源于stack exchange,提问作者Vadym Honcharuk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 02:05:57