Python: trouve les lignes de contour de matplotlib.pyplot.contour()
j'essaie de trouver (mais pas de dessiner!) lignes de contour pour certaines données:
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)
je sais cn
contient les lignes de contour que je veux, mais je ne semble pas pouvoir obtenir
pour eux. J'ai essayé plusieurs choses:
print dir(cn)
pprint(cn.collections[0])
print dir(cn.collections[0])
pprint(cn.collections[0].figure)
print dir(cn.collections[0].figure)
en vain. Je sais cn
est un ContourSet
et cn.collections
est un tableau
LineCollection
s. Je pense que un LineCollection
est un tableau de segments de ligne, mais I
Je ne sais pas comment extraire ces segments.
mon objectif ultime est de créer un KML fichier de parcelles données sur un monde la carte, et le contour de ces données.
Toutefois, comme certains de mes points de données sont rapprochés, et d'autres sont loin, j'ai besoin des polygones réels (linestrings) qui composent les contours, pas seulement une image rastérifiée des contours.
je suis un peu surpris qhull
ne fait pas quelque chose comme ça.
à l'Aide de Mathematica ListContourPlot
et ensuite exporter comme SVG fonctionne, mais je
voulez utiliser quelque chose d'ouvert source.
Je ne peux pas utiliser L'algorithme bien connu de CONREC parce que mes données ne sont pas sur un mesh (il n'y a pas toujours plusieurs valeurs y pour une valeur x donnée, et inversement.)
la solution n'a pas besoin de python, mais doit être open source et exécutable sous Linux.
2 réponses
vous pouvez obtenir les sommets de retour en boucle sur les collections et les chemins et en utilisant le iter_segments()
méthode matplotlib.path.Path
.
Voici une fonction qui renvoie les sommets comme un ensemble de listes imbriquées de lignes de contour, de sections de contour et de tableaux de x, y vertices:
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
Edit:
il est également possible de calculer les contours sans tracer quoi que ce soit en utilisant les matplotlib._cntr
C module:
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()
il semble que les données de contour soient dans le .allsegs
l'attribut QuadContourSet
objet retourné par la plt.contour()
fonction.
.allseg
attribut est une liste de tous les niveaux (qui peuvent être spécifiés lors de l'appel plt.contour(X,Y,Z,V)
. Pour chaque niveau, vous obtenez une liste de tableaux 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')
Dans l'exemple ci-dessus, un seul niveau est donné, si len(C.allsegs)
=1. Vous obtenez:
tracé de contour
l'extrait courbe