如何使用Matplotlib在Python中计算轮廓内的区域?

时间:2014-03-27 05:27:10

标签: python matplotlib area contour

我想找到一种方法让区域在特定的轮廓线内?我使用matplotlib.pyplot创建我的轮廓。
有没有人有这方面的经验?

非常感谢。

3 个答案:

答案 0 :(得分:8)

collections函数返回的轮廓集合的contour属性中,您可以获得描述每个轮廓的路径。路径' vertices属性然后包含轮廓的有序顶点。

使用顶点可以近似轮廓积分0.5 *(x * dy-y * dx),通过应用Green's theorem可以得到封闭区域的区域。

但是,轮廓必须完全包含在图中,否则轮廓会被分解为多个,不一定是连接的路径,并且方法会中断。

这里是用于计算半径函数所包围的面积的方法,即r =(x ^ 2 + y ^ 2)^ 0.5,对于r = 1.0,r = 2.0,r = 3.0。

import numpy as np
import matplotlib.pylab as plt

# Use Green's theorem to compute the area
# enclosed by the given contour.
def area(vs):
    a = 0
    x0,y0 = vs[0]
    for [x1,y1] in vs[1:]:
        dx = x1-x0
        dy = y1-y0
        a += 0.5*(y0*dx - x0*dy)
        x0 = x1
        y0 = y1
    return a

# Generate some test data.
delta = 0.01
x = np.arange(-3.1, 3.1, delta)
y = np.arange(-3.1, 3.1, delta)
X, Y = np.meshgrid(x, y)
r = np.sqrt(X**2 + Y**2)

# Plot the data
levels = [1.0,2.0,3.0]
cs = plt.contour(X,Y,r,levels=levels)
plt.clabel(cs, inline=1, fontsize=10)

# Get one of the contours from the plot.
for i in range(len(levels)):
    contour = cs.collections[i]
    vs = contour.get_paths()[0].vertices
    # Compute area enclosed by vertices.
    a = area(vs)
    print "r = " + str(levels[i]) + ": a =" + str(a)

plt.show()

输出:

r = 1.0: a = 2.83566351207
r = 2.0: a = 11.9922190971
r = 3.0: a = 27.3977413253

答案 1 :(得分:2)

@ spfrnd的矢量化版本计算区域的答案:

x=contour.vertices[:,0]
y=contour.vertices[:,1]
area=0.5*np.sum(y[:-1]*np.diff(x) - x[:-1]*np.diff(y))
area=np.abs(area)

请注意,您可能需要使用该区域的abs,因为如果沿着轮廓的点朝向相反方向,则结果将为负。

答案 2 :(得分:1)

很明显,@ spfrnd的答案中r = 1,2,3的结果与根据A(r)= pi r ^ 2的圆的确切区域相差甚远,即使对于相当密集的网格也是如此。上面的代码无法正常工作的原因是,由于

生成的clabel,返回的顶点不完整
plt.clabel(cs, inline=1, fontsize=10)

,因此,鞋带算法计算出错误的面积。

您可以通过在等高线图旁边绘制返回的顶点来轻松验证这一点(最好使用较大的增量,或者通过::运算符仅保留每N个点)

N = 10
vs = cs.collections[0].get_paths()[0].vertices                                   
plt.plot(vs[::N, 0], vs[::N, 1], marker="x", alpha=0.5)

有关可视化的信息,请参见this picture

删除clabel会得到非常准确的结果,即使对于相当粗糙的网格也是如此。在inline=False命令中设置clabel也可以完成这项工作。