Шейп-файл участка с матплотлибом


13

Я пытаюсь прочитать шейп-файл и построить его с помощью matplotlib. Вот код:

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

Тем не менее, я получаю линии, соединяющие мои полигоны. Как нарисовать полигоны так, чтобы они находились в шейп-файле? Вот скриншоты графика и шейп-файла, когда он открывается в ArcGIS.Сгенерировано кодом Актуальный файл


Не знаком с программой чтения шейп-файлов, однако могу сказать, что вы просто добавляете все точки в файле в один большой список, не разделяя каждую фигуру на составные части. Вам нужен большой список фигур, к которым вы добавляете точки каждой фигуры

Правильно. Нужно найти способ разделить фигуры. Но это то, что я не могу сделать в данный момент.
statBeginner

@DanPatterson Можете ли вы указать, как построить несколько фигур на одной фигуре после того, как мне удастся разделить фигуры? Если я использую plt.plot (listx, listy) для каждой фигуры, он продолжает генерировать новую фигуру каждый раз вместо использования одной и той же фигуры.
statBeginner

Ответы:


10

Я оставлю это вам, как собирать фигуры, но это принцип

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

о ... интересно, как я это пропустил. хотя я получаю формы, напечатанные разными цветами.
Придется это

как получить или изолировать различные формы?
FaCoffee

15

Для будущих ссылок, вот решение, к которому я пришел после следования советам выше.

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

Получившаяся фигура будет очень красочной, но тогда вам просто нужно настроить сюжетные ключевые слова.


6
Я знаю, что это может быть избыточной информацией, но для тех, кто еще не знаком с предметом, было бы полезно сказать, что это import shapefileотносится к pyshpпакету: pypi.python.org/pypi/pyshp
FaCoffee

Это не нормально, когда у вас есть группа островов, так как эти точки будут соединены линиями с точками на материке, создавая нечто похожее на то, что опубликовал ОП.
FaCoffee

1
@FaCoffee, ты прав. Мой ответ gis.stackexchange.com/a/309780/126618 должен решить эту проблему.
Гас

7

Вам нужно использовать пути и патчи matplotlib, и есть модуль Python, предназначенный для построения полигонов из шейп-файлов с использованием этих функций Descartes .

Поскольку Pyshp (shapefile) имеет соглашение geo_interface ( New geo_interface для PyShp ), вы можете использовать его.

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

Результатом является GeoJSON-представление геометрии, и вы можете использовать решение Как построить геоданные, используя 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()

введите описание изображения здесь


Это действительно полезно, но можете ли вы сделать это в цикле for, если у вас есть несколько полигонов для построения?
FaCoffee

Да без проблем
ген

Я заметил, что descartesрешение не работает, если вы попытаетесь нанести два разных шейп-файла на два соседних участка, используя, fig, ax = plt.subplots(1,2,figsize=(15, 8))а затем ax[0].add_patch(PolygonPatch(poly_geo, fc='#d3d3d3', ec='#000000', alpha=0, zorder=5))и ax[1].add_patch(PolygonPatch(poly_geo, fc='#d3d3d3', ec='#000000', alpha=0, zorder=5)). Результатом является пустое изображение. Любая идея?
FaCoffee

2

Это можно сделать с помощью геопанд или pyshp, как описано в этом ответе . Геопанды используют matplotlib на своем бэкенде для построения графиков.


2

В дополнение к ldocao ответ и ответ на вопрос FaCoffee. Когда у вас есть изолированные острова, и они являются частью одной и той же функции, вы можете попробовать следующее:

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

Это заставляет меня работать. Свойство «части» фигуры возвращает начальные индексы различных геометрий внутри объекта.


0

Тем не менее, в одной форме шейп-файла может быть несколько частей. Это позволит построить каждую часть внутри одной фигуры отдельно.

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]))
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.