Plot Shapefile mit Matplotlib


13

Ich versuche, ein Shapefile zu lesen und es mit matplotlib zu zeichnen. Hier ist der 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()

Ich erhalte jedoch Linien, die meine Polygone verbinden. Wie kann ich die Polygone so zeichnen, dass sie der Weg in das Shapefile sind? Hier sehen Sie Screenshots des Diagramms und des Shapefiles, wenn es mit ArcGIS geöffnet wird.Mit Code generiert Aktuelle Datei


Nicht vertraut mit dem Shapefile-Reader, aber ich kann sagen, dass Sie nur alle Punkte in der Datei an eine große Liste anhängen, ohne jede Form in ihre Bestandteile zu zerlegen. Sie benötigen eine große Liste von Formen, an die Sie die einzelnen

Richtig. Müssen Sie einen Weg finden, um die Formen zu trennen. Aber das kann ich im Moment nicht.
statBeginner

@DanPatterson Können Sie angeben, wie mehrere Formen in derselben Figur gezeichnet werden sollen, nachdem ich die Formen getrennt habe? Wenn ich plt.plot (listx, listy) für jede Form verwende, wird jedes Mal eine neue Figur generiert, anstatt dieselbe Figur zu verwenden.
statBeginner

Antworten:


10

Ich überlasse es Ihnen, wie Sie die Formen sammeln, aber das ist das Prinzip

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

oh .. frage mich, wie ich das verpasst habe. Ich bekomme die Formen in verschiedenen Farben gedruckt.
Muss das

Wie kann man die verschiedenen Formen finden oder isolieren?
FaCoffee

15

Für zukünftige Referenzen ist hier die Lösung, zu der ich gekommen bin, nachdem ich die obigen Hinweise befolgt habe.

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

Die resultierende Figur wird sehr farbenfroh sein, aber dann müssen Sie nur die Handlungsschlüsselwörter anpassen.


6
Ich weiß, dass dies redundante Informationen sein könnten, aber für diejenigen, die noch nicht mit dem Thema vertraut sind, wäre es nützlich zu sagen, dass sie import shapefilesich auf das pyshpPaket beziehen
FaCoffee

Dies ist nicht in Ordnung, wenn Sie eine Reihe von Inseln haben, da diese Punkte durch Linien mit Punkten auf dem Festland verbunden werden und so etwas Ähnliches schaffen, wie es das OP veröffentlicht hat.
FaCoffee

1
@FaCoffee, du hast recht. Meine Antwort gis.stackexchange.com/a/309780/126618 sollte dies ansprechen.
Gus

7

Sie müssen matplotlib- Pfade und -Patches verwenden , und es gibt ein Python-Modul, mit dem Sie mithilfe dieser Descartes- Funktionen Polygone aus Shapefiles zeichnen können .

Da Pyshp (Shapefile) die Konvention geo_interface ( New geo_interface for PyShp ) hat, können Sie diese verwenden.

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

Das Ergebnis ist die GeoJSON-Darstellung der Geometrie, und Sie können die Lösung von So zeichnen Sie Geodaten mit 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()

Bildbeschreibung hier eingeben


Das ist sehr hilfreich, aber können Sie dies in einer for-Schleife tun, wenn Sie mehrere Polygone zeichnen müssen?
FaCoffee

Ja, ohne Problem
Gen

Mir ist aufgefallen, dass die descartesLösung nicht funktioniert, wenn Sie versuchen, zwei verschiedene Shapefiles auf zwei benachbarten Unterplots mit fig, ax = plt.subplots(1,2,figsize=(15, 8))und dann ax[0].add_patch(PolygonPatch(poly_geo, fc='#d3d3d3', ec='#000000', alpha=0, zorder=5))und zu zeichnen ax[1].add_patch(PolygonPatch(poly_geo, fc='#d3d3d3', ec='#000000', alpha=0, zorder=5)). Das Ergebnis ist ein leeres Bild. Irgendeine Idee?
FaCoffee

2

Dies kann entweder mit Geopandas oder mit pyshp erfolgen, wie in dieser Antwort erläutert . Geopanden verwenden matplotlib im Backend zum Plotten.


2

Zusätzlich zu ldocao Antwort und Beantwortung der Frage FaCoffee. Wenn Sie isolierte Inseln haben und diese Teil derselben Funktion sind, können Sie Folgendes versuchen:

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

Das macht es für mich arbeiten. Die Eigenschaft "Teile" einer Form gibt die Anfangsindizes der verschiedenen Geometrien innerhalb eines Features zurück.


0

Dennoch kann es in einer Shapefile-Form mehrere Teile geben. Dadurch wird jedes Teil innerhalb einer Form separat gezeichnet.

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]))
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.