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 LineCollections. 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.

16
demandé sur ali_m 2013-08-19 03:26:19

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

enter image description here

22
répondu ali_m 2015-04-24 21:12:27

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

2
répondu Dneis 2017-09-28 10:53:20