Tạo GeoJSON với Python


16

Tôi muốn lập trình tạo một tệp GeoJSON bằng cách sử dụng các đa giác từ một shapefile nhưng thêm các thuộc tính từ ứng dụng của riêng tôi.

Điều này được thực hiện dễ dàng cho một 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()

vì tôi có tất cả các hình học trên một từ điển bằng mã địa lý (self.geomdict) Tôi chỉ cần tạo các tính năng, đặt các trường và sao chép hình học từ lớp có sẵn (tải mã lớp mà bỏ qua cho đơn giản). Tất cả những gì tôi cần bây giờ là một cách để tạo GeoJSON từ sự kết hợp giữa các trường và hình học, một cách tự nhiên với sự trợ giúp của OGR để có được phần còn lại của tệp (CRS, v.v. như từ bản đồ nguồn)

Làm cách nào để xuất bộ sưu tập tính năng được tạo như trên?

Câu trả lời:


14

Hạnh phúc OGR có thể làm điều này cho bạn vì cả hai ogr.Featureogr.Geometrycác đối tượng đều có ExportToJson()phương thức. Trong mã của bạn;

fe.ExportToJson()

Và kể từ khi GeoJSON FeatureCollection đối tượng chỉ đơn giản là từ điển với một typesố FeatureCollectionvà một featuresđối tượng chứa một danh sách các đối tượng tính năng.

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

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

Đối tượng CRS trong bộ sưu tập tính năng có thể là một trong hai loại:

  • CRS có tên (ví dụ: OGC URN hoặc mã EPSG)
  • Một đối tượng liên kết với một URI và một loại như "proj4"

Tùy thuộc vào định dạng dữ liệu của bạn, rất có thể tên đó sẽ là một nỗi đau để lấy từ OGR. Thay vào đó, nếu chúng ta viết phép chiếu vào một tệp trên đĩa mà chúng ta có thể tham chiếu với URI. Chúng ta có thể lấy phép chiếu từ đối tượng lớp (có một số hàm Xuất)

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

Đây là một giải pháp tốt, vì nó không thêm phụ thuộc vào dự án của tôi như giải pháp (tốt đẹp) của @sgillies
fccoelho

Tôi đã hoàn thành thử nghiệm của mình với giải pháp này và nó hoạt động tốt. Tuy nhiên, tôi phải xử lý thủ công khi các tính năng có các ký tự unicode trong tên trường, vì ogr.py không xử lý chúng đúng cách.
fccoelho

Tôi không biết chức năng đã thay đổi kể từ khi, nhưng fe.ExportToJson()trả về một chuỗi, vì vậy bạn cần phải kết hợp với json.loads(...). Nếu không, điều này là siêu hữu ích!
jon_two

35

Nếu bạn đã có môi trường phát triển GDAL / OGR (tiêu đề, libs), bạn có thể đơn giản hóa hoàn toàn mã của mình bằng cách sử dụng Fiona . Để đọc các tính năng từ một shapefile, hãy thêm các thuộc tính mới và viết chúng ra vì GeoJSON chỉ là một số dòng:

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
Tài liệu Fiona là kẻ giết người!
Chad Cooper

1
Sẽ bỏ phiếu nhiều hơn một lần nếu tôi có thể!
om_henners

2
Không có cách nào để đưa định nghĩa crs vào GeoJSON?
fccoelho

2

Đây là cách đơn giản nhất và dễ nhất trong Fiona. bạn có thể đặt SRS cho đầu ra 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)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.