使用Python生成GeoJSON


16

我想以编程方式使用shapefile中的多边形创建GeoJSON文件,但要从我自己的应用程序中添加属性。

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

由于我通过geocode(self.geomdict)将所有几何图形保存在字典中,因此我仅创建要素,设置字段并从预先存在的层克隆几何图形(为简化起见,省略了该层的代码加载)。我现在需要的是一种通过字段和几何的组合生成GeoJSON的方法,自然是借助OGR来正确获取文件的其余部分(如源地图中的CRS等)

如何导出如上生成的要素集合?

Answers:


14

OGR可以为您做到这一点,因为对象ogr.Featureogr.Geometry对象都有ExportToJson()方法。在您的代码中;

fe.ExportToJson()

而且由于geojson FeatureCollection对象只是带有和的字典typeFeatureCollectionfeatures对象包含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的(nice)解决方案那样给我的项目增加额外的依赖
fccoelho 2012年

我认为此解决方案可以完成我的测试,并且效果很好。但是,当功能部件在字段名称中包含unicode字符时,由于ogr.py无法正确处理它们,因此我必须手动处理。
fccoelho 2012年

我不知道此后功能是否发生了变化,但fe.ExportToJson()返回了一个字符串,因此您需要使用进行包装json.loads(...)。否则,这非常有帮助!
jon_two

35

如果您拥有GDAL / OGR开发环境(标头,库),则可以使用Fiona来从根本上简化代码。要从shapefile中读取要素,请添加新属性,并将其写出,因为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文档是杀手!!
乍得·库珀2012年

1
如果可以的话,我将投票一次以上!
om_henners 2012年

2
没有办法在GeoJSON中包含crs定义吗?
fccoelho 2012年

2

这是Fiona中最简单,最简单的一种。您可以为输出GeoJSON设置SRS。

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)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.