Python:从matplotlib.pyplot.contour()中查找轮廓线

时间:2013-08-18 23:26:20

标签: python numpy matplotlib spatial contour

我正在尝试为某些数据找到(但不是绘制!)轮廓线:

from pprint import pprint 
import matplotlib.pyplot 
z = [[0.350087, 0.0590954, 0.002165], [0.144522, 0.885409, 0.378515], 
     [0.027956, 0.777996, 0.602663], [0.138367, 0.182499, 0.460879], 
     [0.357434, 0.297271, 0.587715]] 
cn = matplotlib.pyplot.contour(z) 

我知道cn包含我想要的等高线,但我似乎无法得到 给他们。我尝试了几件事:

print dir(cn) 
pprint(cn.collections[0]) 
print dir(cn.collections[0]) 
pprint(cn.collections[0].figure) 
print dir(cn.collections[0].figure) 

无济于事。我知道cnContourSetcn.collections是一个数组 LineCollection的。{我认为LineCollection是一个线段数组,但是我 无法弄清楚如何提取这些细分。

我的最终目标是创建一个用于绘制世界数据的KML文件 地图,以及该数据的轮廓。

但是,由于我的一些数据点和其他数据点很接近 很远,我需要组成的实际多边形(线串) 轮廓,而不仅仅是轮廓的光栅化图像。

我有些惊讶qhull没有这样的事情。

使用Mathematica的ListContourPlot,然后导出为SVG,但是我 想要使用开源的东西。

我无法使用众所周知的CONREC算法,因为我的数据不在 mesh(对于给定的x值,并不总是有多个y值,并且 反之亦然)。

解决方案不需要python,但必须是开源的 并且可以在Linux上运行。

4 个答案:

答案 0 :(得分:22)

您可以通过循环使用集合和路径并使用matplotlib.path.Pathiter_segments()方法来获取顶点。

这是一个函数,它将顶点作为一组嵌套的轮廓线,轮廓截面和x,y顶点数组返回:

import numpy as np

def get_contour_verts(cn):
    contours = []
    # for each contour line
    for cc in cn.collections:
        paths = []
        # for each separate section of the contour line
        for pp in cc.get_paths():
            xy = []
            # for each segment of that section
            for vv in pp.iter_segments():
                xy.append(vv[0])
            paths.append(np.vstack(xy))
        contours.append(paths)

    return contours

编辑:

也可以使用未记录的matplotlib._cntr C模块计算轮廓而无需绘制任何内容:

from matplotlib import pyplot as plt
from matplotlib import _cntr as cntr

z = np.array([[0.350087, 0.0590954, 0.002165],
              [0.144522,  0.885409, 0.378515],
              [0.027956,  0.777996, 0.602663],
              [0.138367,  0.182499, 0.460879], 
              [0.357434,  0.297271, 0.587715]])

x, y = np.mgrid[:z.shape[0], :z.shape[1]]
c = cntr.Cntr(x, y, z)

# trace a contour at z == 0.5
res = c.trace(0.5)

# result is a list of arrays of vertices and path codes
# (see docs for matplotlib.path.Path)
nseg = len(res) // 2
segments, codes = res[:nseg], res[nseg:]

fig, ax = plt.subplots(1, 1)
img = ax.imshow(z.T, origin='lower')
plt.colorbar(img)
ax.hold(True)
p = plt.Polygon(segments[0], fill=False, color='w')
ax.add_artist(p)
plt.show()

enter image description here

答案 1 :(得分:2)

轮廓数据似乎位于.allsegs函数返回的QuadContourSet对象的plt.contour()属性中。

.allseg属性是所有级别的列表(可以在调用plt.contour(X,Y,Z,V)时指定。对于每个级别,您将获得numpy nx2数组的列表。

plt.figure()
plt.contour(X, Y, Z, [0], colors='r')

plt.figure()
for ii, seg in enumerate(C.allsegs[0]):
    plt.plot(seg[:,0], seg[:,1], '.-', label=ii)
plt.legend(fontsize=9, loc='best')

在上面的示例中,只给出了一个级别,因此len(C.allsegs) = 1。你得到:

等高线图

提取的曲线

答案 2 :(得分:2)

我建议使用scikit-image find_contours

它返回给定级别的轮廓列表。

从v2.2开始,

matplotlib._cntr已从matplotlib中删除(请参见here)。

答案 3 :(得分:0)

所有路径的顶点都可以通过以下方式以float64的numpy数组形式返回:

cn.allsegs[i][j]  # for element j, in level i

更详细:

遍历集合并提取路径和顶点并不是最直接或最快的操作。返回的Contour对象实际上通过cs.allsegs拥有线段的属性,该属性返回嵌套的[level] [element] [vertex_coord]形状的列表:

num_levels = len(cn.allsegs)
num_element = len(cn.allsegs[0])  # in level 0
num_vertices = len(cn.allsegs[0][0])  # of element 0, in level 0
num_coord = len(cn.allsegs[0][0][0])  # of vertex 0, in element 0, in level 0

请参阅参考资料: https://matplotlib.org/3.1.1/api/contour_api.html