59 votes

matplotlib - extraction de données à partir de lignes de contour

J'aimerais obtenir des données à partir d'un seul contour de données 2D uniformément espacées (données de type image).

Basé sur l'exemple trouvé dans une question similaire : Comment puis-je obtenir les valeurs (x,y) de la ligne qui est tracée par un tracé de contour (matplotlib) ?

>>> import matplotlib.pyplot as plt
>>> x = [1,2,3,4]
>>> y = [1,2,3,4]
>>> m = [[15,14,13,12],[14,12,10,8],[13,10,7,4],[12,8,4,0]]
>>> cs = plt.contour(x,y,m, [9.5])
>>> cs.collections[0].get_paths()

Le résultat de cet appel dans cs.collections[0].get_paths() est :

[Path([[ 4.          1.625     ]
 [ 3.25        2.        ]
 [ 3.          2.16666667]
 [ 2.16666667  3.        ]
 [ 2.          3.25      ]
 [ 1.625       4.        ]], None)]

Sur la base des graphiques, ce résultat est logique et semble être une collection de paires (y,x) pour la ligne de contour.

À part le fait de boucler manuellement sur cette valeur de retour, d'extraire les coordonnées et d'assembler des tableaux pour la ligne, existe-t-il de meilleures façons de récupérer des données à partir d'un fichier de type matplotlib.path objet ? Y a-t-il des pièges à éviter lors de l'extraction de données d'un objet de type matplotlib.path ?

Par ailleurs, existe-t-il des alternatives au sein de matplotlib ou mieux encore numpy / scipy pour faire une chose similaire ? L'idéal serait d'obtenir un vecteur haute résolution de paires (x,y) décrivant la ligne, qui pourrait être utilisé pour une analyse plus approfondie, car en général mes ensembles de données ne sont pas aussi petits ou simples que l'exemple ci-dessus.

62voto

UnbanRonMaimon Points 1684

Pour un chemin donné, vous pouvez obtenir les points comme ceci :

p = cs.collections[0].get_paths()[0]
v = p.vertices
x = v[:,0]
y = v[:,1]

0 votes

C'est vraiment utile, merci ! Connaissez-vous un moyen d'obtenir/interpoler des points équidistants sur la courbe de niveau ? (les points renvoyés de cette manière ne sont pas équidistants).

0 votes

La méthode recommandée pour le moment est d'utiliser cs.allsegs . C'est une liste qui contient un élément pour chaque niveau. Chaque élément est lui-même une liste contenant les polygones correspondant à ce niveau. Ainsi, si polys0 = cs.allsegs[0] est la liste des polygones pour le premier niveau, x00, y00 = polys0[0].T sont les x y y qui construiront le premier polygone de ce niveau.

10voto

user724375 Points 96

De : http://matplotlib.org/api/path_api.html#module-matplotlib.path

Les utilisateurs des objets Path ne doivent pas accéder aux tableaux de sommets et de codes. directement. Au lieu de cela, ils doivent utiliser iter_segments() pour obtenir les paires sommet/code. Ceci est important, car de nombreux objets Path, par souci d'optimisation, ne stockent pas du tout de codes, mais ont des codes de sommet. optimisation, ne stockent pas de codes du tout, mais en ont un par défaut fourni par iter_segments(). par défaut qui leur est fourni par iter_segments().

Sinon, je ne sais pas vraiment quelle est votre question. La fonction [Zip] est une fonction intégrée parfois utile pour travailler avec des coordonnées. 1

6voto

RCCG Points 51

Les sommets d'un chemin peuvent être retournés comme un tableau numpy de float64 simplement via :

cs.allsegs[i][j]  # for element j, in level i

donde cs est défini comme dans la question originale comme :

import matplotlib.pyplot as plt
x = [1, 2, 3, 4]
y = [1, 2, 3, 4]
m = [[15, 14, 13, 12], [14, 12, 10, 8], [13, 10, 7, 4], [12, 8, 4, 0]]
cs = plt.contour(x, y, m, [9.5])

Plus de détails :

Passer en revue les collections et extraire les chemins et les sommets n'est pas la chose la plus simple ou la plus rapide à faire. L'objet Contour renvoyé possède en fait des attributs pour les segments par l'intermédiaire de la fonction cs.allsegs qui renvoie une liste imbriquée de forme [level][element][vertex_coord] :

num_levels = len(cs.allsegs)
num_element = len(cs.allsegs[0])  # in level 0
num_vertices = len(cs.allsegs[0][0])  # of element 0, in level 0
num_coord = len(cs.allsegs[0][0][0])  # of vertex 0, in element 0, in level 0

Voir la référence : https://matplotlib.org/3.1.1/api/contour_api.html

4voto

grg rsr Points 390

Je suis confronté à un problème similaire, et je suis tombé sur cette discussion sur la liste matplotlib .

En fait, il est possible de supprimer le traçage et d'appeler directement les fonctions sous-jacentes, ce qui n'est pas très pratique, mais possible. La solution n'est pas non plus précise au pixel près, car il y a probablement une certaine interpolation dans le code sous-jacent.

import matplotlib.pyplot as plt
import matplotlib._cntr as cntr
import scipy as sp

data = sp.zeros((6,6))
data[2:4,2:4] = 1

plt.imshow(data,interpolation='none')
level=0.5
X,Y = sp.meshgrid(sp.arange(data.shape[0]),sp.arange(data.shape[1]))
c = cntr.Cntr(X, Y, data.T)
nlist = c.trace(level, level, 0)
segs = nlist[:len(nlist)//2]
for seg in segs:
    plt.plot(seg[:,0],seg[:,1],color='white')

plt.show()

2 votes

Notez que matplotlib._cntr ne fait plus partie de matplotlib . stackoverflow.com/questions/48349730/

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X