web-dev-qa-db-ja.com

Python:matplotlib.pyplot.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) 

無駄に。 cnContourSetであり、cn.collectionsLineCollectionsの配列です。 LineCollectionは線分の配列だと思いますが、それらのセグメントを抽出する方法がわかりません。

私の最終的な目標は、世界地図にデータをプロットするKMLファイルと、そのデータの等高線を作成することです。

ただし、一部のデータポイントは近くにあり、他のデータポイントは遠くにあるため、輪郭のラスタライズされた画像だけでなく、輪郭を構成する実際のポリゴン(ラインストリング)が必要です。

qhullがこのようなことをしないのには少し驚いています。

MathematicaのListContourPlotを使って、SVGとしてエクスポートするのはうまくいくが、私は何かオープンソースを使いたい。

データがメッシュ上にないため、よく知られているCONRECアルゴリズムを使用できません(特定のx値に対して常に複数のy値が存在するわけではなく、その逆も同様です)。

ソリューションはPythonである必要はありませんが、オープンソースでLinux上で実行可能である必要があります。

20
barrycarter

コレクションとパスをループし、 _matplotlib.path.Path_iter_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

24
ali_m

等高線データは、plt.contour()関数によって返されるQuadContourSetオブジェクトの_.allsegs_属性にあるようです。

_.allseg_属性は、すべてのレベルのリストです(plt.contour(X,Y,Z,V)を呼び出すときに指定できます。レベルごとに、numpynx2配列のリストを取得します。

_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')
_

上記の例では、1つのレベルのみが指定されているため、len(C.allsegs) = 1です。あなたが得る:

等高線図 

抽出された曲線 

2
Dneis

すべてのパスの頂点は、次の方法で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

0
RCCG