Plot shapefile avec matplotlib

13

J'essaie de lire un fichier de formes et de le tracer en utilisant matplotlib. Voici le code:

import matplotlib.pyplot as plt
import shapefile   

shpFilePath = "D:\test.shp"  
listx=[]
listy=[]
test = shapefile.Reader(shpFilePath)
for sr in test.shapeRecords():
    for xNew,yNew in sr.shape.points:
        listx.append(xNew)
        listy.append(yNew)
plt.plot(listx,listy)
plt.show()

Cependant, je reçois des lignes reliant mes polygones. Comment puis-je dessiner les polygones de telle sorte qu'ils soient le chemin dans le fichier de formes. Voici des captures d'écran du tracé et du fichier de formes lorsqu'il est ouvert avec ArcGIS.Généré par code Fichier réel

statBeginner
la source
Je ne suis pas familier avec le lecteur de fichiers de formes, mais je peux dire que vous ajoutez simplement tous les points du fichier à une grande liste sans séparer chaque forme en ses composants. Vous avez besoin d'une grande liste de formes auxquelles vous ajoutez chaque point de forme
Droite. Je dois trouver un moyen de séparer les formes. Mais c'est ce que je ne peux pas faire pour le moment.
statBeginner
@DanPatterson Pouvez-vous spécifier comment tracer plusieurs formes dans la même figure après avoir réussi à séparer les formes? Si j'utilise plt.plot (listx, listy) pour chaque forme, il continue de générer une nouvelle figure à chaque fois, au lieu d'utiliser la même figure.
statBeginner

Réponses:

10

Je vous laisse le soin de collecter les formes mais c'est le principe

import numpy as np
from matplotlib import pyplot as p  #contains both numpy and pyplot
x1 = [-1,-1,10,10,-1]; y1 = [-1,10,10,-1,-1]
x2 = [21,21,29,29,21]; y2 = [21,29,29,21,21]
shapes = [[x1,y1],[x2,y2]]
for shape in shapes:
  x,y = shape
  p.plot(x,y)
p.show()

la source
oh .. je me demande comment j'ai raté ça. cependant, je fais imprimer les formes dans différentes couleurs. Devra résoudre ce problème :)
statBeginner
comment obtenir ou isoler les différentes formes?
FaCoffee
15

Pour les références futures, voici la solution à laquelle je suis parvenu après avoir suivi les conseils ci-dessus.

import shapefile as shp  # Requires the pyshp package
import matplotlib.pyplot as plt

sf = shp.Reader("test.shp")

plt.figure()
for shape in sf.shapeRecords():
    x = [i[0] for i in shape.shape.points[:]]
    y = [i[1] for i in shape.shape.points[:]]
    plt.plot(x,y)
plt.show()

Le chiffre résultant sera très coloré, mais ensuite, il vous suffit d'ajuster les mots clés du graphique.

ldocao
la source
6
Je sais que cela pourrait être une information redondante, mais pour ceux qui ne connaissent pas encore le sujet, il aurait été utile de dire que cela import shapefilefait référence au pyshppackage: pypi.python.org/pypi/pyshp
FaCoffee
Ce n'est pas correct lorsque vous avez un tas d'îles, car ces points seront connectés par des lignes à des points sur le continent, créant quelque chose de similaire à ce que l'OP a publié.
FaCoffee
1
@FaCoffee, vous avez raison. Ma réponse gis.stackexchange.com/a/309780/126618 devrait répondre à cela.
Gus
7

Vous devez utiliser des chemins et des correctifs matplotlib et il existe un module Python dédié au tracé de polygones à partir de fichiers de formes à l'aide de ces fonctions Descartes .

Comme Pyshp (shapefile) a la convention geo_interface ( New geo_interface for PyShp ), vous pouvez l'utiliser.

polys  = shapefile.Reader("polygon")
# first polygon
poly = polys.iterShapes().next().__geo_interface__
print poly
{'type': 'Polygon', 'coordinates': (((151116.87238259654, 135890.8706318218), (153492.19971554304, 134793.3055883224), (153934.50204650551, 133892.31935858406), (152623.97662143156, 131811.86024627919), (150903.91200102202, 130894.49244872745), (149347.66305874675, 132991.33312884573), (149151.08424498566, 134383.76639298678), (151116.87238259654, 135890.8706318218)),)}

Le résultat est la représentation GeoJSON de la géométrie et vous pouvez utiliser la solution Comment tracer des géo-données en utilisant matplotlib / python

import matplotlib.pyplot as plt 
from descartes import PolygonPatch
BLUE = '#6699cc'
fig = plt.figure() 
ax = fig.gca() 
ax.add_patch(PolygonPatch(poly, fc=BLUE, ec=BLUE, alpha=0.5, zorder=2 ))
ax.axis('scaled')
plt.show()

entrez la description de l'image ici

gène
la source
C'est vraiment utile, mais pouvez-vous le faire dans une boucle for si vous avez plusieurs polygones à tracer?
FaCoffee
Oui sans problème
gène
J'ai remarqué que la descartessolution ne fonctionne pas si vous essayez de tracer deux fichiers de formes différents sur deux sous-tracés adjacents à l'aide de fig, ax = plt.subplots(1,2,figsize=(15, 8))et puis ax[0].add_patch(PolygonPatch(poly_geo, fc='#d3d3d3', ec='#000000', alpha=0, zorder=5))et ax[1].add_patch(PolygonPatch(poly_geo, fc='#d3d3d3', ec='#000000', alpha=0, zorder=5)). Le résultat est une image vide. Une idée?
FaCoffee
2

Cela peut être fait en utilisant des géopandas ou pyshp comme discuté dans cette réponse . Les géopandas utilisent matplotlib à son backend pour le traçage.

MME_
la source
2

En plus de la réponse ldocao et de la réponse à la question FaCoffee. Lorsque vous avez des îles isolées et qu'elles font partie de la même fonctionnalité, vous pouvez essayer ensuite:

import shapefile as shp
import matplotlib.pyplot as plt

sf = shp.Reader("test.shp")

plt.figure()
for shape in sf.shapeRecords():
    for i in range(len(shape.shape.parts)):
        i_start = shape.shape.parts[i]
        if i==len(shape.shape.parts)-1:
            i_end = len(shape.shape.points)
        else:
            i_end = shape.shape.parts[i+1]
        x = [i[0] for i in shape.shape.points[i_start:i_end]]
        y = [i[1] for i in shape.shape.points[i_start:i_end]]
        plt.plot(x,y)
plt.show()

Cela fonctionne pour moi. La propriété "parties" d'une forme renvoie les index de départ des différentes géométries à l'intérieur d'une fonction.

Felipesaam
la source
0

Pourtant, dans une forme de fichier de formes, il peut y avoir plusieurs parties. Cela tracera chaque pièce dans une forme, séparément.

import matplotlib.pyplot as plt
import shapefile
import numpy as np

this_shapefile = shapefile.Reader(map_file_base) # whichever file
shape = this_shapefile.shape(i) # whichever shape
points = np.array(shape.points)

intervals = list(shape.parts) + [len(shape.points)]

ax = plt.gca()
ax.set_aspect(1)

for (i, j) in zip(intervals[:-1], intervals[1:]):
    ax.plot(*zip(*points[i:j]))
Gus
la source