Rysuj plik kształtu za pomocą matplotlib

15

Próbuję odczytać plik kształtu i wykreślić go za pomocą matplotlib. Oto kod:

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

Jednak dostaję linie łączące moje wielokąty. Jak narysować wielokąty w taki sposób, aby stanowiły drogę w pliku kształtu? Oto zrzuty ekranu z fabuły i pliku kształtu, gdy jest on otwierany za pomocą ArcGIS.Wygenerowane przez kod Rzeczywisty plik

statBeginner
źródło
Nie jestem zaznajomiony z czytnikiem plików kształtów, ale mogę powiedzieć, że po prostu dodajesz wszystkie punkty w pliku do jednej dużej listy, nie dzieląc każdego kształtu na części składowe. Potrzebujesz dużej listy kształtów, do których
Dobrze. Muszę znaleźć sposób na rozdzielenie kształtów. Ale w tej chwili nie jestem w stanie tego zrobić.
statBeginner
@DanPatterson Czy możesz określić sposób kreślenia wielu kształtów na tej samej figurze po tym, jak uda mi się rozdzielić kształty? Jeśli użyję plt.plot (listx, listy) dla każdego kształtu, za każdym razem generuje nową figurę, zamiast używać tej samej figury.
statBeginner

Odpowiedzi:

10

Pozostawię wam, jak zbierać kształty, ale taka jest zasada

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

źródło
och ... zastanawiam się, jak mi tego brakowało. Dostaję kształty w różnych kolorach. Będę musiał to naprawić :)
statBeginner
jak uzyskać lub wyizolować różne kształty?
FaCoffee
15

Dla przyszłych odniesień oto rozwiązanie, do którego doszedłem po wykonaniu powyższych rad.

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

Wynikowa liczba będzie bardzo kolorowa, ale wtedy wystarczy dostosować słowa kluczowe fabuły.

ldocao
źródło
6
Wiem, że mogą to być zbędne informacje, ale dla osób, które nie są jeszcze zaznajomione z tematem, przydatne byłoby powiedzenie, że import shapefileodnosi się do pyshppakietu: pypi.python.org/pypi/pyshp
FaCoffee
Nie jest to dobre, gdy masz kilka wysp, ponieważ punkty te zostaną połączone liniami z punktami na kontynencie, tworząc coś podobnego do tego, co opublikował PO.
FaCoffee
1
@FaCoffee, masz rację. Moja odpowiedź gis.stackexchange.com/a/309780/126618 powinna rozwiązać ten problem.
Gus
9

Musisz użyć ścieżek i łatek matplotlib, a istnieje moduł Pythona dedykowany do drukowania wieloboków z plików kształtów za pomocą tych funkcji Kartezjusza .

Ponieważ Pyshp (shapefile) ma konwencję geo_interface ( Nowy interfejs geo dla PyShp ), możesz jej używać.

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

Wynikiem jest reprezentacja geometrii przez GeoJSON. Możesz użyć rozwiązania Jak narysować dane geograficzne za pomocą 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()

wprowadź opis zdjęcia tutaj

gen
źródło
To naprawdę pomocne, ale czy możesz to zrobić w pętli for, jeśli masz wiele wielokątów do wykreślenia?
FaCoffee
Tak bez problemu
gen
Zauważyłem, że descartesrozwiązanie nie działa, jeśli spróbujesz wykreślić dwa różne pliki kształtów na dwóch sąsiednich działkach za pomocą, fig, ax = plt.subplots(1,2,figsize=(15, 8))a następnie ax[0].add_patch(PolygonPatch(poly_geo, fc='#d3d3d3', ec='#000000', alpha=0, zorder=5))i ax[1].add_patch(PolygonPatch(poly_geo, fc='#d3d3d3', ec='#000000', alpha=0, zorder=5)). Rezultatem jest pusty obraz. Dowolny pomysł?
FaCoffee,
3

Oprócz odpowiedzi ldocao i odpowiedzi na pytanie FaCoffee. Gdy masz izolowane wyspy i są one częścią tej samej funkcji, możesz spróbować dalej:

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

To sprawia, że ​​działa dla mnie. „Części” kształtu właściwości zwracają indeksy początkowe różnych geometrii wewnątrz elementu.

felipesaam
źródło
2

Można to zrobić za pomocą geopandas lub pyshp, jak omówiono w tej odpowiedzi . Geopandy używają matplotlib na swoim zapleczu do kreślenia.

MS_
źródło
0

Jednak w jednym kształcie pliku kształtu może być wiele części. Spowoduje to wydrukowanie każdej części osobno w jednym kształcie.

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
źródło