누군가 형상 데이터 구조를 형태에서 형태 파일로 작성하는 간단한 방법을 보여줄 수 있습니까? 특히 구멍과 선 스트링이있는 다각형에 관심이 있습니다. 또한 아크 피에서 멀리 떨어져있는 것이 좋습니다 (따라서 osgeo, pyshp 등이 모두 더 나을 것입니다).
누군가 형상 데이터 구조를 형태에서 형태 파일로 작성하는 간단한 방법을 보여줄 수 있습니까? 특히 구멍과 선 스트링이있는 다각형에 관심이 있습니다. 또한 아크 피에서 멀리 떨어져있는 것이 좋습니다 (따라서 osgeo, pyshp 등이 모두 더 나을 것입니다).
답변:
잘 알려진 바이너리 는 Shapely 및 GDAL / OGR을 포함한 많은 GIS 소프트웨어와 교환 할 수있는 좋은 바이너리 교환 형식입니다.
이것은 다음 과 같은 워크 플로 의 작은 예입니다 osgeo.ogr
.
from osgeo import ogr
from shapely.geometry import Polygon
# Here's an example Shapely geometry
poly = Polygon([(0, 0), (0, 1), (1, 1), (0, 0)])
# Now convert it to a shapefile with OGR
driver = ogr.GetDriverByName('Esri Shapefile')
ds = driver.CreateDataSource('my.shp')
layer = ds.CreateLayer('', None, ogr.wkbPolygon)
# Add one attribute
layer.CreateField(ogr.FieldDefn('id', ogr.OFTInteger))
defn = layer.GetLayerDefn()
## If there are multiple geometries, put the "for" loop here
# Create a new feature (attribute and geometry)
feat = ogr.Feature(defn)
feat.SetField('id', 123)
# Make a geometry, from Shapely object
geom = ogr.CreateGeometryFromWkb(poly.wkb)
feat.SetGeometry(geom)
layer.CreateFeature(feat)
feat = geom = None # destroy these
# Save and close everything
ds = layer = feat = geom = None
업데이트 : 포스터가 GDAL / OGR 답변을 수락했지만 다음은 Fiona에 해당합니다.
from shapely.geometry import mapping, Polygon
import fiona
# Here's an example Shapely geometry
poly = Polygon([(0, 0), (0, 1), (1, 1), (0, 0)])
# Define a polygon feature geometry with one attribute
schema = {
'geometry': 'Polygon',
'properties': {'id': 'int'},
}
# Write a new Shapefile
with fiona.open('my_shp2.shp', 'w', 'ESRI Shapefile', schema) as c:
## If there are multiple geometries, put the "for" loop here
c.write({
'geometry': mapping(poly),
'properties': {'id': 123},
})
(참고 Windows 사용자 : 변명의 여지가 없습니다 )
Fiona 가 Shapely와 잘 작동 하도록 설계했습니다 . 다음은 셰이프 파일 기능을 "정리"하기 위해 함께 사용하는 매우 간단한 예입니다.
import logging
import sys
from shapely.geometry import mapping, shape
import fiona
logging.basicConfig(stream=sys.stderr, level=logging.INFO)
with fiona.open('docs/data/test_uk.shp', 'r') as source:
# **source.meta is a shortcut to get the crs, driver, and schema
# keyword arguments from the source Collection.
with fiona.open(
'with-shapely.shp', 'w',
**source.meta) as sink:
for f in source:
try:
geom = shape(f['geometry'])
if not geom.is_valid:
clean = geom.buffer(0.0)
assert clean.is_valid
assert clean.geom_type == 'Polygon'
geom = clean
f['geometry'] = mapping(geom)
sink.write(f)
except Exception, e:
# Writing uncleanable features to a different shapefile
# is another option.
logging.exception("Error cleaning feature %s:", f['id'])
에서 https://github.com/Toblerity/Fiona/blob/master/examples/with-shapely.py .
PyShp를 사용하여 Shapely 도형을 작성할 수도 있습니다 (원래 포스터도 PyShp에 대해 요청한 이후).
한 가지 방법은 shapely geometry를 geojson으로 변환하고 (shapely.geometry.mapping 방법) 수정 된 PyShp 포크 를 사용하는 것입니다. 하여 shapefile에 쓸 때 geojson geometry 사전을 허용하는 Writer 메소드를 제공하는 것입니다.
기본 PyShp 버전을 사용하려는 경우 아래 변환 기능도 제공했습니다.
# THIS FUNCTION CONVERTS A GEOJSON GEOMETRY DICTIONARY TO A PYSHP SHAPE OBJECT
def shapely_to_pyshp(shapelygeom):
# first convert shapely to geojson
try:
shapelytogeojson = shapely.geometry.mapping
except:
import shapely.geometry
shapelytogeojson = shapely.geometry.mapping
geoj = shapelytogeojson(shapelygeom)
# create empty pyshp shape
record = shapefile._Shape()
# set shapetype
if geoj["type"] == "Null":
pyshptype = 0
elif geoj["type"] == "Point":
pyshptype = 1
elif geoj["type"] == "LineString":
pyshptype = 3
elif geoj["type"] == "Polygon":
pyshptype = 5
elif geoj["type"] == "MultiPoint":
pyshptype = 8
elif geoj["type"] == "MultiLineString":
pyshptype = 3
elif geoj["type"] == "MultiPolygon":
pyshptype = 5
record.shapeType = pyshptype
# set points and parts
if geoj["type"] == "Point":
record.points = geoj["coordinates"]
record.parts = [0]
elif geoj["type"] in ("MultiPoint","Linestring"):
record.points = geoj["coordinates"]
record.parts = [0]
elif geoj["type"] in ("Polygon"):
record.points = geoj["coordinates"][0]
record.parts = [0]
elif geoj["type"] in ("MultiPolygon","MultiLineString"):
index = 0
points = []
parts = []
for eachmulti in geoj["coordinates"]:
points.extend(eachmulti[0])
parts.append(index)
index += len(eachmulti[0])
record.points = points
record.parts = parts
return record
함수를 자신의 스크립트에 복사하여 붙여 넣기 만하면 모양이있는 도형을 pyshp 호환 모양으로 변환 할 수 있습니다. 이를 저장하기 위해 각 pyshp 모양을 shapefile.Writer 인스턴스의 ._shapes 목록에 추가하기 만하면됩니다 (예를 들어,이 게시물의 하단에있는 테스트 스크립트 참조).
그러나 내부 다각형 구멍이있는 경우이 함수는 처리하지 않으며 단순히 무시합니다. 해당 기능을 함수에 추가하는 것은 가능하지만 아직 귀찮게하지 않았습니다. 기능 개선을위한 제안이나 편집은 환영합니다 :)
완전한 독립형 테스트 스크립트는 다음과 같습니다.
### HOW TO SAVE SHAPEFILE FROM SHAPELY GEOMETRY USING PYSHP
# IMPORT STUFF
import shapefile
import shapely, shapely.geometry
# CREATE YOUR SHAPELY TEST INPUT
TEST_SHAPELYSHAPE = shapely.geometry.Polygon([(133,822),(422,644),(223,445),(921,154)])
#########################################################
################## END OF USER INPUT ####################
#########################################################
# DEFINE/COPY-PASTE THE SHAPELY-PYSHP CONVERSION FUNCTION
def shapely_to_pyshp(shapelygeom):
# first convert shapely to geojson
try:
shapelytogeojson = shapely.geometry.mapping
except:
import shapely.geometry
shapelytogeojson = shapely.geometry.mapping
geoj = shapelytogeojson(shapelygeom)
# create empty pyshp shape
record = shapefile._Shape()
# set shapetype
if geoj["type"] == "Null":
pyshptype = 0
elif geoj["type"] == "Point":
pyshptype = 1
elif geoj["type"] == "LineString":
pyshptype = 3
elif geoj["type"] == "Polygon":
pyshptype = 5
elif geoj["type"] == "MultiPoint":
pyshptype = 8
elif geoj["type"] == "MultiLineString":
pyshptype = 3
elif geoj["type"] == "MultiPolygon":
pyshptype = 5
record.shapeType = pyshptype
# set points and parts
if geoj["type"] == "Point":
record.points = geoj["coordinates"]
record.parts = [0]
elif geoj["type"] in ("MultiPoint","Linestring"):
record.points = geoj["coordinates"]
record.parts = [0]
elif geoj["type"] in ("Polygon"):
record.points = geoj["coordinates"][0]
record.parts = [0]
elif geoj["type"] in ("MultiPolygon","MultiLineString"):
index = 0
points = []
parts = []
for eachmulti in geoj["coordinates"]:
points.extend(eachmulti[0])
parts.append(index)
index += len(eachmulti[0])
record.points = points
record.parts = parts
return record
# WRITE TO SHAPEFILE USING PYSHP
shapewriter = shapefile.Writer()
shapewriter.field("field1")
# step1: convert shapely to pyshp using the function above
converted_shape = shapely_to_pyshp(TEST_SHAPELYSHAPE)
# step2: tell the writer to add the converted shape
shapewriter._shapes.append(converted_shape)
# add a list of attributes to go along with the shape
shapewriter.record(["empty record"])
# save it
shapewriter.save("test_shapelytopyshp.shp")
카림의 대답은 꽤 오래되었지만 나는 그의 코드를 사용하여 그에게 감사하고 싶었습니다. 코드를 사용하여 알아 낸 한 가지 사소한 점 : 모양 유형이 다각형 또는 다중 다각형 인 경우 여전히 여러 부분 (구멍이 있음)이있을 수 있습니다. 따라서 그의 코드의 일부는
elif geoj["type"] == "Polygon":
index = 0
points = []
parts = []
for eachmulti in geoj["coordinates"]:
points.extend(eachmulti)
parts.append(index)
index += len(eachmulti)
record.points = points
record.parts = parts
elif geoj["type"] in ("MultiPolygon", "MultiLineString"):
index = 0
points = []
parts = []
for polygon in geoj["coordinates"]:
for part in polygon:
points.extend(part)
parts.append(index)
index += len(part)
record.points = points
record.parts = parts