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)
безрезультатно. Я знаю, что cn
- это ContourSet
, а cn.collections
- массив
от LineCollection
s. Я бы подумал, что LineCollection
- это массив сегментов линии, но я
не могут понять, как извлечь эти сегменты.
Моя конечная цель - создать файл KML, который отображает данные в мире
карту и контуры для этих данных.
Однако, поскольку некоторые мои данные находятся близко друг к другу, а другие
далеки, мне нужны фактические полигоны (linestrings), которые составляют
контуры, а не только растрированное изображение контуров.
Я несколько удивлен, что qhull
не делает ничего подобного.
Использование Mathematica ListContourPlot
, а затем экспорт в качестве SVG работает, но я
хотите использовать что-то с открытым исходным кодом.
Я не могу использовать известный алгоритм CONREC, потому что мои данные не находятся на
mesh (не всегда есть несколько значений y для заданного значения x и
наоборот).
Решение не требуется для python, но должно быть открытым исходным кодом
и запускается в Linux.
Ответы
Ответ 1
Вы можете вернуть вершины, перейдя по коллекциям и путям и используя метод 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._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]()
Ответ 2
Кажется, что данные контура находятся в атрибуте .allsegs
объекта QuadContourSet
, возвращаемого функцией plt.contour()
.
Атрибут .allseg
- это список всех уровней (которые могут быть указаны при вызове plt.contour(X,Y,Z,V)
). Для каждого уровня вы получаете список массивов nx2 numpy.
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. Вы получаете:
контурный график
![]()
извлеченные кривые
![]()