Câu trả lời:
Nhị phân nổi tiếng là một định dạng trao đổi nhị phân tốt có thể được trao đổi với nhiều phần mềm GIS, bao gồm Shapely và GDAL / OGR.
Đây là một ví dụ nhỏ về quy trình làm việc với 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
Cập nhật : Mặc dù người đăng đã chấp nhận câu trả lời GDAL / OGR, đây là tương đương với 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},
})
(Lưu ý người dùng Windows: bạn không có lý do )
Tôi đã thiết kế Fiona để hoạt động tốt với Shapely. Dưới đây là một ví dụ rất đơn giản về việc sử dụng chúng cùng nhau để "dọn dẹp" các tính năng shapefile:
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'])
Từ https://github.com/Toblerity/Fiona/blob/master/examples/with-shapely.py .
Bạn cũng có thể viết hình học Shapely bằng cách sử dụng PyShp (vì người đăng ban đầu cũng hỏi về PyShp).
Một cách là chuyển đổi hình dạng tạo hình của bạn thành Geojson (với phương thức shapely.geometry.micking) và sau đó sử dụng ngã ba PyShp đã sửa đổi của tôi , cung cấp phương thức Writer chấp nhận từ điển hình học Geojson khi viết vào shapefile.
Nếu bạn muốn dựa vào phiên bản PyShp chính, tôi cũng đã cung cấp chức năng chuyển đổi bên dưới:
# 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
Chỉ cần sao chép và dán chức năng vào tập lệnh của riêng bạn và gọi nó để chuyển đổi bất kỳ hình dạng hình dạng nào của bạn thành hình dạng tương thích pyshp. Để lưu chúng, sau đó bạn chỉ cần nối từng hình dạng pyshp kết quả vào danh sách ._shapes của shapefile.Writer (ví dụ: xem tập lệnh thử nghiệm ở cuối bài này).
Tuy nhiên, lưu ý: chức năng sẽ KHÔNG xử lý bất kỳ lỗ đa giác bên trong nào nếu có, nó chỉ đơn giản là bỏ qua chúng. Chắc chắn có thể thêm chức năng đó vào chức năng nhưng tôi đơn giản là chưa làm phiền. Đề xuất hoặc chỉnh sửa để cải thiện chức năng đều được chào đón :)
Đây là một kịch bản thử nghiệm độc lập đầy đủ:
### 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")
Câu trả lời của Karim khá cũ nhưng tôi đã sử dụng mã của anh ấy và muốn cảm ơn anh ấy vì điều đó. Một điều nhỏ tôi đã tìm ra bằng cách sử dụng mã của anh ấy: Nếu loại hình dạng là Đa giác hoặc Đa hình, nó vẫn có thể có nhiều phần (lỗ bên trong). Do đó, một phần mã của anh ta nên được đổi thành
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