Menghasilkan GeoJSON dengan Python


16

Saya ingin membuat file GeoJSON secara terprogram menggunakan poligon dari shapefile tetapi menambahkan atribut dari aplikasi saya sendiri.

Ini mudah dilakukan untuk shapefile:

def create_data_dayer(self,varlist, data):
    """
    Creates a new shape to contain data about nodes.
    varlist is the list of fields names associated with
    the nodes.
    data is a list of lists whose first element is the geocode
    and the remaining elements are values of the fields, in the
    same order as they appear in varlist.
    """
    if os.path.exists(os.path.join(self.outdir,'Data.shp')):
        os.remove(os.path.join(self.outdir,'Data.shp'))
        os.remove(os.path.join(self.outdir,'Data.shx'))
        os.remove(os.path.join(self.outdir,'Data.dbf'))
    # Creates a new shape file to hold the data
    if not self.datasource:
        dsd = self.driver.CreateDataSource(os.path.join(self.outdir,'Data.shp'))
        self.datasource = dsd
        dl = dsd.CreateLayer("sim_results",geom_type=ogr.wkbPolygon)
    #Create the fields
    fi1 = ogr.FieldDefn("geocode",field_type=ogr.OFTInteger)
    dl.CreateField(fi1)
    for v in varlist:
        #print "creating data fields"
        fi = ogr.FieldDefn(v,field_type=ogr.OFTString)
        fi.SetPrecision(12)
        dl.CreateField(fi)

    #Add the features (points)
    for n,l in enumerate(data):
        #Iterate over the lines of the data matrix.
        gc = l[0]
        try:
            geom = self.geomdict[gc]
            if geom.GetGeometryType() != 3: continue
            #print geom.GetGeometryCount()
            fe = ogr.Feature(dl.GetLayerDefn())
            fe.SetField('geocode',gc)
            for v,d in zip (varlist,l[1:]):
                #print v,d
                fe.SetField(v,str(d))
            #Add the geometry
            #print "cloning geometry"
            clone = geom.Clone()
            #print geom
            #print "setting geometry"
            fe.SetGeometry(clone)
            #print "creating geom"
            dl.CreateFeature(fe)
        except: #Geocode not in polygon dictionary
            pass
        dl.SyncToDisk()

karena saya memiliki semua geometri pada kamus dengan geocode (self.geomdict) Saya cukup membuat fitur, mengatur bidang dan mengkloning geometri dari lapisan yang sudah ada sebelumnya (memuat kode yang lapisannya dihilangkan untuk kesederhanaan). Yang saya butuhkan sekarang adalah cara untuk menghasilkan GeoJSON dari kombinasi bidang dan geometri, secara alami dengan bantuan OGR untuk mendapatkan sisa file yang benar (CRS, dll. Seperti dari peta sumber)

Bagaimana cara mengekspor koleksi fitur yang dihasilkan seperti di atas?

Jawaban:


14

Untungnya OGR dapat melakukan ini untuk Anda karena keduanya ogr.Featuredan ogr.Geometryobjek memiliki ExportToJson()metode. Dalam kode Anda;

fe.ExportToJson()

Dan karena GeoJSON FeatureCollection benda hanya kamus dengan typedari FeatureCollectiondan featuresobjek yang berisi daftar objek Fitur.

feature_collection = {"type": "FeatureCollection",
                      "features": []
                      }

feature_collection["features"].append(fe.ExportToJson())

Objek CRS dalam kumpulan fitur dapat menjadi salah satu dari dua jenis:

  • Yang bernama CRS (misalnya OGC URN atau kode EPSG)
  • Objek tautan dengan URI dan jenis seperti "proj4"

Bergantung pada format data Anda, kemungkinan besar nama itu akan sulit didapat dari OGR. Alih-alih jika kita menulis proyeksi ke file pada disk yang dapat kita rujuk dengan URI. Kita dapat mengambil proyeksi dari objek layer (yang memiliki beberapa fungsi Ekspor)

spatial_reference = dl.GetSpatialRef()

with open("data.crs", "wb") as f:
    f.write(spatial_reference.ExportToProj4())

feature_collection["crs"] = {"type": "link",
                             "properties": {
                                 "href": "data.crs",
                                 "type": "proj4"
                                 }
                             }

Ini adalah solusi yang baik, karena tidak menambah ketergantungan ekstra pada proyek saya seperti solusi (bagus) dari @sgillies
fccoelho

Saya baru saja menyelesaikan pengujian saya dengan solusi ini dan itu bekerja dengan baik. Namun saya harus menangani secara manual ketika fitur memiliki karakter unicode dalam nama bidang, karena ogr.py tidak menanganinya dengan benar.
fccoelho

Saya tidak tahu apakah fungsionalitas telah berubah sejak itu, tetapi fe.ExportToJson()mengembalikan sebuah string, jadi Anda harus membungkusnya dengan json.loads(...). Kalau tidak, ini sangat membantu!
jon_two

35

Jika Anda memiliki lingkungan dev GDAL / OGR (header, libs), Anda dapat secara radikal menyederhanakan kode Anda dengan menggunakan Fiona . Untuk membaca fitur dari sebuah shapefile, menambahkan atribut baru, dan menuliskannya karena GeoJSON hanyalah beberapa baris:

import fiona
import json

features = []
crs = None
with fiona.collection("docs/data/test_uk.shp", "r") as source:
    for feat in source:
        feat['properties'].update(...) # with your attributes
        features.append(feat)
    crs = " ".join("+%s=%s" % (k,v) for k,v in source.crs.items())

my_layer = {
    "type": "FeatureCollection",
    "features": features,
    "crs": {
        "type": "link", 
        "properties": {"href": "my_layer.crs", "type": "proj4"} }}

with open("my_layer.json", "w") as f:
    f.write(json.dumps(my_layer))
with open("my_layer.crs", "w") as f:
    f.write(crs)

4
Fiona docs adalah pembunuh!
Chad Cooper

1
Akan memilih lebih dari sekali jika saya bisa!
om_henners

2
Apakah tidak ada cara untuk memasukkan definisi crs di GeoJSON?
fccoelho

2

Ini adalah yang paling sederhana dan termudah di Fiona. Anda dapat mengatur SRS untuk keluaran GeoJSON.

import fiona
from fiona.crs import from_epsg

source= fiona.open('shp/second_shp.shp', 'r', encoding = 'utf-8')

with fiona.open('tool_shp_geojson/geojson_fiona.json','w',  driver ="GeoJSON", schema=source.schema, encoding = 'utf-8', crs=fiona.crs.from_epsg(4326)) as geojson:
     geojson.write(feat)
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.