Plot shapefile dengan matplotlib

13

Saya mencoba membaca sebuah shapefile dan memplotnya menggunakan matplotlib. Ini kodenya:

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

Namun, saya mendapatkan garis yang menghubungkan poligon saya. Bagaimana saya bisa menggambar poligon sedemikian rupa sehingga ada jalan di shapefile. Berikut adalah screenshot dari plot dan shapefile ketika dibuka dengan ArcGIS.Dihasilkan oleh Kode File yang Sebenarnya

statBeginner
sumber
Tidak terbiasa dengan pembaca shapefile, namun saya dapat mengatakan bahwa Anda hanya menambahkan semua poin dalam file ke satu daftar besar tanpa memisahkan setiap bentuk menjadi bagian-bagian komponennya. Anda memerlukan daftar besar bentuk tempat Anda menambahkan setiap titik bentuk
Baik. Harus menemukan cara untuk memisahkan bentuk. Tapi itu yang tidak bisa saya lakukan saat ini.
statBeginner
@DanPatterson Bisakah Anda menentukan cara memplot banyak bentuk pada gambar yang sama setelah saya berhasil memisahkan bentuk? Jika saya menggunakan plt.plot (listx, listy) untuk setiap bentuk, ia terus menghasilkan angka baru setiap kali, alih-alih menggunakan angka yang sama.
statBeginner

Jawaban:

10

Saya akan menyerahkan kepada Anda cara mengumpulkan bentuk tetapi ini adalah prinsipnya

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

sumber
oh .. ingin tahu bagaimana saya melewatkan itu. saya mendapatkan bentuk dicetak dalam warna berbeda.
Harus
bagaimana cara mendapatkan atau mengisolasi bentuk yang berbeda?
FaCoffee
15

Untuk referensi di masa mendatang, inilah solusi yang saya gunakan setelah mengikuti saran di atas.

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

Angka yang dihasilkan akan sangat berwarna, tetapi kemudian, Anda hanya perlu menyesuaikan kata kunci plot.

ldocao
sumber
6
Saya tahu ini mungkin informasi yang berlebihan, tetapi bagi mereka yang belum akrab dengan subjek, akan berguna untuk mengatakan bahwa import shapefilemerujuk pada pyshppaket: pypi.python.org/pypi/pyshp
FaCoffee
Ini tidak ok ketika Anda memiliki banyak pulau, karena titik-titik ini akan dihubungkan oleh garis ke titik di daratan, menciptakan sesuatu yang mirip dengan apa yang diposting OP.
FaCoffee
1
@FaCoffee, Anda benar. Jawaban saya gis.stackexchange.com/a/309780/126618 harus mengatasi ini.
Gus
7

Anda perlu menggunakan jalur dan tambalan matplotlib dan ada modul Python yang didedikasikan untuk memplot poligon dari shapefile menggunakan fungsi-fungsi ini Descartes .

Karena Pyshp (shapefile) memiliki konvensi geo_interface ( geo_interface baru untuk PyShp ), Anda dapat menggunakannya.

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

Hasilnya adalah representasi GeoJSON dari geometri dan Anda dapat menggunakan solusi Cara memplot data geo menggunakan 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()

masukkan deskripsi gambar di sini

gen
sumber
Itu sangat membantu, tetapi bisakah Anda melakukan ini dalam for for loop jika Anda memiliki beberapa poligon untuk plot?
FaCoffee
Ya tanpa masalah
gen
Saya perhatikan bahwa descartessolusinya tidak berfungsi jika Anda mencoba dan memplot dua shapefile berbeda pada dua subplot yang berdekatan menggunakan fig, ax = plt.subplots(1,2,figsize=(15, 8))dan kemudian ax[0].add_patch(PolygonPatch(poly_geo, fc='#d3d3d3', ec='#000000', alpha=0, zorder=5))dan ax[1].add_patch(PolygonPatch(poly_geo, fc='#d3d3d3', ec='#000000', alpha=0, zorder=5)). Hasilnya adalah gambar kosong. Ada ide?
FaCoffee
2

Ini dapat dilakukan dengan menggunakan geopanda atau pyshp seperti yang dibahas dalam jawaban ini . Geopanda menggunakan matplotlib di bagian belakangnya untuk merencanakan.

NONA_
sumber
2

Selain jawaban ldocao, dan menanggapi pertanyaan FaCoffee. Ketika Anda memiliki pulau-pulau terpencil dan mereka adalah bagian dari fitur yang sama, Anda dapat mencoba berikutnya:

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

Ini membuatnya bekerja untuk saya. Propertie "bagian" dari suatu bentuk mengembalikan indeks awal geometri differents di dalam fitur.

Felipesaam
sumber
0

Namun, dalam satu bentuk shapefile, mungkin ada beberapa bagian. Ini akan memplot setiap bagian dalam satu bentuk, secara terpisah.

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
sumber