Генерування GeoJSON з Python


16

Я хочу програмно створити файл GeoJSON, використовуючи полігони з форм-файлу, але додаючи атрибути з моєї власної програми.

Це легко зробити для файлу форми:

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

оскільки у мене є всі геометрії в словнику за допомогою геокодування (self.geomdict), я просто створюю функції, встановлюю поля та клоную геометрії з попередньо існуючого шару (завантаження коду цього шару опущено для простоти). Тепер мені потрібно лише генерувати GeoJSON за допомогою комбінації полів та геометрій, природно за допомогою OGR, щоб отримати решту файлів право (CRS тощо), як з вихідної карти)

Як експортувати колекцію функцій, згенеровану як вище?

Відповіді:


14

На щастя, OGR може зробити це для вас, як ogr.Featureі в ogr.Geometryоб'єктах є ExportToJson()методи. У своєму коді;

fe.ExportToJson()

А оскільки GeoJSON FeatureCollection об'єкти просто словники з typeз FeatureCollectionі в featuresоб'єкт , що містить список об'єктів Feature.

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

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

Об'єкт CRS у колекції функцій може бути одного з двох типів:

  • Іменований CRS (наприклад, OGC URN або код EPSG)
  • Об'єкт посилання з URI та типом типу "proj4"

Залежно від формату ваших даних, цілком ймовірно, що назву буде неприємно отримати від OGR. Замість цього, якщо ми запишемо проекцію у файл на диску, який ми можемо посилатись на URI. Ми можемо захопити проекцію з об'єкта шару (який має кілька функцій експорту)

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"
                                 }
                             }

Це хороше рішення, оскільки воно не додає додаткової залежності до мого проекту, як (приємне) рішення @sgillies
fccoelho

Я закінчив своє тестування цим рішенням, і це працювало чудово. Однак мені довелося обробляти вручну, коли функції мали символи unicode в іменах полів, оскільки ogr.py неправильно обробляв їх.
fccoelho

Я не знаю, чи змінився функціонал з тих пір, але fe.ExportToJson()повертає рядок, тому вам потрібно завершити роботу json.loads(...). Інакше це дуже корисно!
jon_two

35

Якщо у вас є середовище розробки GDAL / OGR (заголовки, libs), ви можете кардинально спростити код за допомогою Fiona . Щоб прочитати функції з файлу форми, додайте нові атрибути та запишіть їх, оскільки GeoJSON - це лише кілька рядків:

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 вбивці!
Чад Купер

1
Я б проголосував не раз, якби міг!
om_henners

2
Чи не існує способу включити визначення crs в GeoJSON?
fccoelho

2

Це найпростіший і найпростіший у Фіоні. ви можете встановити SRS для виведення 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)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.