शेपिली को शेपली ज्यामिति कैसे लिखें?


26

क्या कोई व्यक्ति ज्यामिति डेटा-संरचनाओं को आकार से आकार में लिखने के लिए एक सरल तरीका प्रदर्शित कर सकता है? मुझे विशेष रूप से छेद और लिनस्ट्रेस के साथ बहुभुज में दिलचस्पी है। यह चापलूसी से दूर रहने के लिए भी फायदेमंद होगा (इसलिए ओस्गो, pyshp, आदि सभी बेहतर होंगे)।

जवाबों:


44

अच्छी तरह से ज्ञात बाइनरी एक अच्छा द्विआधारी विनिमय प्रारूप है, जिसे शेपली और जीडीएएल / ओजीआर सहित जीआईएस सॉफ्टवेयर के बहुत से आदान-प्रदान किया जा सकता है।

यह वर्कफ़्लो का एक छोटा उदाहरण है 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 उत्तर को स्वीकार कर लिया है, यहाँ एक फियोना समकक्ष है:

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

(नोट विंडोज यूजर्स: आपके पास कोई बहाना नहीं है )


रुचि है कि आपने इस पद्धति को क्यों चुना, फिर फियोना पुस्तकालय।
नाथन डब्ल्यू

1
ठीक है, पोस्टर एक osgeo.ogr उदाहरण के लिए देख रहा था, और तुलना दिलचस्प है।
sgillies

@sgillies स्पष्ट तुलना जोड़ा गया
माइक टी

3
खैर, ईमानदार होना ज्यादातर व्यावहारिक था। मैंने अपने प्रश्न के उत्तर में कोड को प्रदर्शित करने के प्रयास की सराहना की और मैं पहले से ही ऑस्गेओ के बारे में विचार कर रहा था। मैंने तब से दोनों तरीकों की कोशिश की है और वे दोनों पर्याप्त उत्तर हैं। मैं उत्तरदाताओं द्वारा सटीक और तेज दोनों के प्रयास की सराहना करता हूं।
terra_matics

@ माइक टी। ओजग.ओगर दृष्टिकोण के बारे में, मैं इसे क्यूजीआईएस के लिए पायथन प्लगइन में उपयोग कर रहा हूं। लिखी जाने वाली शेपफाइल एक रेखा है (शेपली में लाइनस्ट्रिंग)। जहाँ आपने "पॉली" वेरिएबल को परिभाषित किया है, मैंने Qgs.Rectangle के निर्देशांक के साथ "लाइन" वेरिएबल को परिभाषित किया है। मैंने सटीक कोड का उपयोग किया है, कोई त्रुटि नहीं है, लेकिन यह एक सुविधा नहीं जोड़ता है, और मुझे बिना किसी विशेषता के एक आकृति प्रदान करता है।
अखिल

28

मैंने फिओना को शेपली के साथ अच्छा काम करने के लिए डिज़ाइन किया है । यहाँ उन्हें "साफ" आकार-प्रकार की विशेषताओं के साथ उपयोग करने का एक बहुत ही सरल उदाहरण दिया गया है:

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


6

आप Pyhhp का उपयोग करके Shapely geometries भी लिख सकते हैं (क्योंकि मूल पोस्टर ने PyShp के बारे में भी पूछा था)।

एक तरीका यह होगा कि आप अपने सुडौल ज्यामिति को जियोजोन में (सुडौल.ग्रोमेट्री मेपिंग विधि के साथ) परिवर्तित करें और फिर मेरे संशोधित पियूष का उपयोग करें जो एक राइटर विधि प्रदान करता है जो एक आकृति के लिए लिखते समय जियोजोन ज्यामिति शब्दकोशों को स्वीकार करता है।

यदि आप मुख्य 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 आकृति को आकार-प्रकार में जोड़ते हैं। उदाहरण की ._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")

5

करीम का जवाब बहुत पुराना है लेकिन मैंने उनके कोड का इस्तेमाल किया है और इसके लिए उन्हें धन्यवाद देना चाहता हूं। एक मामूली बात जो मुझे उनके कोड का उपयोग करके समझ में आई: यदि आकार का प्रकार बहुभुज या मल्टीपोलीगॉन है, तो इसमें अभी भी कई हिस्से (अंदर छेद) हो सकते हैं। इसलिए उसके कोड का हिस्सा बदल दिया जाना चाहिए

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
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.