23

我正在尝试查找(但不绘制!)某些数据的等高线:

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) 

无济于事。我知道cn是一个ContourSet,并且cn.collections是一个 s 的数组LineCollection。我认为 aLineCollection是线段数组,但我不知道如何提取这些线段。

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

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

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

使用 Mathematica ListContourPlot,然后导出为 SVG 作品,但我想使用一些开源的东西。

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

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

4

4 回答 4

25

您可以通过遍历集合和路径并iter_segments()使用matplotlib.path.Path.

这是一个函数,它将顶点作为一组嵌套的轮廓线列表、轮廓部分和 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._cntrC 模块在不绘制任何内容的情况下计算轮廓:

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()

在此处输入图像描述

于 2013-08-19T08:57:59.717 回答
4

轮廓数据似乎在函数返回.allsegs的对象的属性中。QuadContourSetplt.contour()

.allseg属性是所有级别的列表(可以在调用时指定plt.contour(X,Y,Z,V)。对于每个级别,您都会获得一个n x 2 NumPy 数组的列表。

plt.figure()
C = 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。你得到:

等高线图

提取的曲线

于 2017-09-28T10:46:19.243 回答
2

我建议使用 scikit-image find_contours

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

matplotlib._cntr自 v2.2 以来已从 matplotlib 中删除(请参见此处)。

于 2019-10-23T12:13:43.387 回答
1

所有路径的顶点可以简单地通过以下方式返回为 float64 的 numpy 数组:

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

cn原始问题中的定义相同:

import matplotlib.pyplot as plt
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 = plt.contour(z) 

更详细:

遍历集合并提取路径和顶点并不是最直接或最快的事情。返回的 Contour 对象实际上具有线段的属性 via 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

于 2019-11-25T08:50:45.913 回答