Plot shapefile con matplotlib

13

Estoy tratando de leer un archivo de formas y trazarlo usando matplotlib. Aquí está el código:

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

Sin embargo, obtengo líneas que conectan mis polígonos. ¿Cómo puedo dibujar los polígonos para que sean la forma en el archivo de forma? Aquí hay capturas de pantalla de la trama y el archivo de forma cuando se abre con ArcGIS.Generado por código Archivo real

statBeginner
fuente
No estoy familiarizado con el lector de archivos de forma, sin embargo, puedo decir que solo está agregando todos los puntos del archivo a una lista grande sin separar cada forma en sus partes componentes. Necesita una gran lista de formas a las que
Correcto. Tiene que encontrar una manera de separar las formas. Pero eso es lo que no puedo hacer en este momento.
statBeginner
@DanPatterson ¿Puede especificar cómo trazar varias formas en la misma figura después de que logré separar las formas? Si uso plt.plot (listx, listy) para cada forma, sigue generando una nueva figura cada vez, en lugar de usar la misma figura.
statBeginner

Respuestas:

10

Te dejo a ti cómo recolectar las formas, pero este es el principio

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

fuente
oh ... me pregunto cómo me perdí eso. Sin embargo, tengo las formas impresas en diferentes colores. Tendrá que arreglar eso :)
statBeginner
¿Cómo obtener o aislar las diferentes formas?
FaCoffee
15

Para futuras referencias, aquí está la solución a la que he llegado después de seguir los consejos anteriores.

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

La figura resultante será muy colorida, pero entonces, solo necesita ajustar las palabras clave de la trama.

ldocao
fuente
66
Sé que esto podría ser información redundante, pero para aquellos que aún no están familiarizados con el tema, habría sido útil decir que se import shapefilerefiere al pyshppaquete: pypi.python.org/pypi/pyshp
FaCoffee
Esto no está bien cuando tienes un montón de islas, ya que estos puntos estarán conectados por líneas a puntos en el continente, creando algo similar a lo que publicó el OP.
FaCoffee
1
@FaCoffee, tienes razón. Mi respuesta gis.stackexchange.com/a/309780/126618 debería abordar esto.
Gus
7

Necesita usar rutas y parches matplotlib y hay un módulo de Python dedicado a trazar polígonos a partir de archivos de forma usando estas funciones Descartes .

Como Pyshp (shapefile) tiene la convención geo_interface ( Nueva geo_interface para PyShp ), puede usarla.

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)),)}

El resultado es la representación GeoJSON de la geometría y puede usar la solución de Cómo trazar geodatos usando 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()

ingrese la descripción de la imagen aquí

gene
fuente
Eso es realmente útil, pero ¿puedes hacer esto en un bucle for si tienes varios polígonos para trazar?
FaCoffee
Sí sin problema
gen
Noté que la descartessolución no funciona si intentas trazar dos archivos de forma diferentes en dos subtramas adyacentes usando fig, ax = plt.subplots(1,2,figsize=(15, 8))y luego ax[0].add_patch(PolygonPatch(poly_geo, fc='#d3d3d3', ec='#000000', alpha=0, zorder=5))y ax[1].add_patch(PolygonPatch(poly_geo, fc='#d3d3d3', ec='#000000', alpha=0, zorder=5)). El resultado es una imagen vacía. ¿Alguna idea?
FaCoffee
2

Se puede hacer usando geopandas o pyshp como se discutió en esta respuesta . Las geopandas usan matplotlib en su backend para trazar.

SRA_
fuente
2

Además de responder a ldocao, y responder a la pregunta de FaCoffee. Cuando tenga islas aisladas y formen parte de la misma característica, puede intentar lo siguiente:

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

Esto hace que funcione para mí. Las "partes" de propiedad de una forma devuelven los índices iniciales de diferentes geometrías dentro de una entidad.

felipesaam
fuente
0

Aún así, en una forma de archivo de forma, puede haber múltiples partes. Esto trazará cada parte dentro de una forma, por separado.

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
fuente