**凹**非网格数据的 matplotlib 轮廓/轮廓 [英] matplotlib contour/contourf of **concave** non-gridded data

查看:32
本文介绍了**凹**非网格数据的 matplotlib 轮廓/轮廓的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想做一个 matplotlib contourcontourf 非网格 3D 数据 (x, y, z) 的图,它在 x 中以某种方式呈 C 形和 y(见草图)——因此围绕数据的封闭外壳的一部分在 x 和 y 中是凹的.

I'd like to do a matplotlib contour or contourf plot of non-gridded 3D data (x, y, z) which is somehow C-shaped in x and y (see sketch) -- therefore part of the enclosing hull around the data is concave in x and y.

通常我会先将非网格 3D 数据插值到

Usually I do plots of non-gridded 3D data by first interpolating it with

from matplotlib.mlab import griddata
griddata...

但这会在数据的凹部产生伪影,使得凹部被插值填充.

but this generates artifacts in the concave part of the data such that the concave part is filled by the interpolation.

是否可以进行插值或轮廓/轮廓图,以便尊重数据的凹面部分?

推荐答案

按条件屏蔽

下面是一个示例,说明如何使用带有掩码的 tricontourf 来获得没有数据外插值部分的凹面形状.它依赖于根据条件屏蔽数据的能力.

Masking by condition

Below is an example on how to use tricontourf with masking to obtain a concave shape without interpolated portions outside the data. It relies on the ability to mask the data depending on a condition.

import matplotlib.pyplot as plt
import matplotlib.tri as tri
import numpy as np

# create some data
rawx = np.random.rand(500)
rawy = np.random.rand(len(rawx))
cond01 = (rawx-1)**2 + rawy**2 <=1
cond02 = (rawx-0.7)**2 + rawy**2 >0.3
x = rawx[cond01 & cond02]
y = rawy[cond01 & cond02]
f = lambda x,y: np.sin(x*4)+np.cos(y)
z = f(x,y)
# now, x,y are points within a partially concave shape

triang0 = tri.Triangulation(x, y)
triang = tri.Triangulation(x, y)
x2 = x[triang.triangles].mean(axis=1) 
y2 = y[triang.triangles].mean(axis=1)
#note the very obscure mean command, which, if not present causes an error.
#now we need some masking condition.
# this is easy in this case where we generated the data according to the same condition
cond1 = (x2-1)**2 + y2**2 <=1
cond2 = (x2-0.7)**2 + (y2)**2 >0.3
mask = np.where(cond1 & cond2,0,1)
# apply masking
triang.set_mask(mask)


fig, (ax, ax2) = plt.subplots(ncols=2, figsize=(6,3))
ax.set_aspect("equal")
ax2.set_aspect("equal")

ax.tricontourf(triang0, z,  cmap="Oranges")
ax.scatter(x,y, s=3, color="k")

ax2.tricontourf(triang, z,  cmap="Oranges")
ax2.scatter(x,y, s=3, color="k")

ax.set_title("tricontourf without mask")
ax2.set_title("tricontourf with mask")
ax.set_xlim(0,1)
ax.set_ylim(0,1)
ax2.set_xlim(0,1)
ax2.set_ylim(0,1)

plt.show()

如果您无法访问确切条件,但有点之间的最大边长(距离),则以下将是一个解决方案.它会掩盖至少一侧比某个最大距离长的所有三角形.如果点密度相当高,这可以很好地应用.

If you do not have access to the exact condition, but have a maximum side-length (distance) between points, the following would be a solution. It would mask out all triangles for which at least one side is longer than some maximum distance. This can be well applied if the point density is rather high.

import matplotlib.pyplot as plt
import matplotlib.tri as tri
import numpy as np

# create some data
rawx = np.random.rand(500)
rawy = np.random.rand(len(rawx))
cond01 = (rawx-1)**2 + rawy**2 <=1
cond02 = (rawx-0.7)**2 + rawy**2 >0.3
x = rawx[cond01 & cond02]
y = rawy[cond01 & cond02]
f = lambda x,y: np.sin(x*4)+np.cos(y)
z = f(x,y)
# now, x,y are points within a partially concave shape

triang1 = tri.Triangulation(x, y)
triang2 = tri.Triangulation(x, y)
triang3 = tri.Triangulation(x, y)

def apply_mask(triang, alpha=0.4):
    # Mask triangles with sidelength bigger some alpha
    triangles = triang.triangles
    # Mask off unwanted triangles.
    xtri = x[triangles] - np.roll(x[triangles], 1, axis=1)
    ytri = y[triangles] - np.roll(y[triangles], 1, axis=1)
    maxi = np.max(np.sqrt(xtri**2 + ytri**2), axis=1)
    # apply masking
    triang.set_mask(maxi > alpha)

apply_mask(triang2, alpha=0.1)
apply_mask(triang3, alpha=0.3)

fig, (ax1, ax2, ax3) = plt.subplots(ncols=3, figsize=(9,3))

ax1.tricontourf(triang1, z,  cmap="Oranges")
ax1.scatter(x,y, s=3, color="k")

ax2.tricontourf(triang2, z,  cmap="Oranges")
ax2.scatter(x,y, s=3, color="k")

ax3.tricontourf(triang3, z,  cmap="Oranges")
ax3.scatter(x,y, s=3, color="k")

ax1.set_title("tricontourf without mask")
ax2.set_title("with mask (alpha=0.1)")
ax3.set_title("with mask (alpha=0.3)")

for ax in (ax1, ax2, ax3):
    ax.set(xlim=(0,1), ylim=(0,1), aspect="equal")

plt.show()

可以看出,在这里找到正确的参数(alpha)可能需要一些调整.

As can be seen, finding the correct parameter (alpha) here is may need some tweaking.

这篇关于**凹**非网格数据的 matplotlib 轮廓/轮廓的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆