Combine part of geojson object into another in Python

纵饮孤独 提交于 2019-12-31 04:30:15

问题


EDIT: I am trying to manipulate JSON files in Python. In my data some polygons have multiple related information: coordinates (LineString) and area percent and area (Text and Area in Point), I want to combine them to a single JSON object. As an example, the data from files are as follows:

data = {
        "type": "FeatureCollection",
        "name": "entities",
        "features": [{
                "type": "Feature",
                "properties": {
                    "Layer": "0",
                    "SubClasses": "AcDbEntity:AcDbBlockReference",
                    "EntityHandle": "2F1"
                },
                "geometry": {
                    "type": "LineString",
                    "coordinates": [
                        [61.971069681118479, 36.504485105673659],
                        [46.471068755199667, 36.504485105673659],
                        [46.471068755199667, 35.954489281866685],
                        [44.371068755199758, 35.954489281866685],
                        [44.371068755199758, 36.10448936390457],
                        [43.371069617387093, 36.104489150107824],
                        [43.371069617387093, 23.904496401184584],
                        [48.172716774891342, 23.904496401184584],
                        [48.171892994728751, 17.404489374370311],
                        [61.17106949647404, 17.404489281863786],
                        [61.17106949647404, 19.404489281863786],
                        [61.971069689453991, 19.404489282256687],
                        [61.971069681118479, 36.504485105673659]
                    ]
                }
            },
            {
                "type": "Feature",
                "properties": {
                    "Layer": "0",
                    "SubClasses": "AcDbEntity:AcDbMText",
                    "EntityHandle": "2F1",
                    "Text": "6%"
                },
                "geometry": {
                    "type": "Point",
                    "coordinates": [49.745686139884583, 28.11445704760262, 0.0]
                }
            },
            {
                "type": "Feature",
                "properties": {
                    "Layer": "0",
                    "SubClasses": "AcDbEntity:AcDbMText",
                    "EntityHandle": "2F1",
                    "Area": "100"
                },
                "geometry": {
                    "type": "Point",
                    "coordinates": [50.216857362443989, 63.981197759829229, 0.0]
                }
            },
            {
                "type": "Feature",
                "properties": {
                    "Layer": "0",
                    "SubClasses": "AcDbEntity:AcDbBlockReference",
                    "EntityHandle": "2F7"
                },
                "geometry": {
                    "type": "LineString",
                    "coordinates": [
                        [62.37106968111857, 36.504489398648715],
                        [62.371069689452725, 19.404489281863786],
                        [63.171069496474047, 19.404489281863786],
                        [63.171069496474047, 17.404489281863786],
                        [77.921070051947027, 17.404489281863786],
                        [77.921070051947027, 19.504489281855054],
                        [78.671070051947027, 19.504489281855054],
                        [78.671070051897914, 36.504485105717322],
                        [62.37106968111857, 36.504489398648715]
                    ]
                }
            },
            {
                "type": "Feature",
                "properties": {
                    "Layer": "0",
                    "SubClasses": "AcDbEntity:AcDbMText",
                    "EntityHandle": "2F7",
                    "Text": "5.8%"
                },
                "geometry": {
                    "type": "Point",
                    "coordinates": [67.27548061311245, 28.11445704760262, 0.0]
                }
            }
        ]
    }

I want to combine Point's Text and Area key and values to LineString based on EntityHandle's values, and also delete Point lines. The expected output is:

    {
        "type": "FeatureCollection",
        "name": "entities",
        "features": [{
                "type": "Feature",
                "properties": {
                    "Layer": "0",
                    "SubClasses": "AcDbEntity:AcDbBlockReference",
                    "EntityHandle": "2F1",
                    "Text": "6%",
                    "Area": "100"
                },
                "geometry": {
                    "type": "LineString",
                    "coordinates": [
                        [61.971069681118479, 36.504485105673659],
                        [46.471068755199667, 36.504485105673659],
                        [46.471068755199667, 35.954489281866685],
                        [44.371068755199758, 35.954489281866685],
                        [44.371068755199758, 36.10448936390457],
                        [43.371069617387093, 36.104489150107824],
                        [43.371069617387093, 23.904496401184584],
                        [48.172716774891342, 23.904496401184584],
                        [48.171892994728751, 17.404489374370311],
                        [61.17106949647404, 17.404489281863786],
                        [61.17106949647404, 19.404489281863786],
                        [61.971069689453991, 19.404489282256687],
                        [61.971069681118479, 36.504485105673659]
                    ]
                }
            },
            {
                "type": "Feature",
                "properties": {
                    "Layer": "0",
                    "SubClasses": "AcDbEntity:AcDbBlockReference",
                    "EntityHandle": "2F7",
                    "Text": "5.8%"
                },
                "geometry": {
                    "type": "LineString",
                    "coordinates": [
                        [62.37106968111857, 36.504489398648715],
                        [62.371069689452725, 19.404489281863786],
                        [63.171069496474047, 19.404489281863786],
                        [63.171069496474047, 17.404489281863786],
                        [77.921070051947027, 17.404489281863786],
                        [77.921070051947027, 19.504489281855054],
                        [78.671070051947027, 19.504489281855054],
                        [78.671070051897914, 36.504485105717322],
                        [62.37106968111857, 36.504489398648715]
                    ]
                }
            }
        ]
    }

Is it possible to get result above in Python? Thanks.

Updated solution, thanks to @dodopy:

import json
features = data["features"]
point_handle_text = {
    i["properties"]["EntityHandle"]: i["properties"]["Text"]
    for i in features
    if i["geometry"]["type"] == "Point"
}
point_handle_area = {
    i["properties"]["EntityHandle"]: i["properties"]["Area"]
    for i in features
    if i["geometry"]["type"] == "Point"
}
combine_features = []
for i in features:
    if i["geometry"]["type"] == "LineString":
        i["properties"]["Text"] = point_handle_text.get(i["properties"]["EntityHandle"])
        combine_features.append(i)
data["features"] = combine_features

combine_features = []
for i in features:
    if i["geometry"]["type"] == "LineString":
        i["properties"]["Area"] = point_handle_area.get(i["properties"]["EntityHandle"])
        combine_features.append(i)
data["features"] = combine_features

with open('test.geojson', 'w+') as f:
    json.dump(data, f, indent=2)

But I get an error:

Traceback (most recent call last):
  File "<ipython-input-131-d132c8854a9c>", line 6, in <module>
    for i in features
  File "<ipython-input-131-d132c8854a9c>", line 7, in <dictcomp>
    if i["geometry"]["type"] == "Point"
KeyError: 'Text'

回答1:


example like this:

import json
data = json.loads(json_data)
features = data["features"]
point_handle_text = {
    i["properties"]["EntityHandle"]: i["properties"]["Text"]
    for i in features
    if i["geometry"]["type"] == "Point"
}
combine_features = []
for i in features:
    if i["geometry"]["type"] == "LineString":
        i["properties"]["Text"] = point_handle_text.get(i["properties"]["EntityHandle"])
        combine_features.append(i)
data["features"] = combine_features
json_data = json.dumps(data)



回答2:


Yes, it is possible to get your result in python. It just requires storing the json data into a data structure we can work with in python and then writing an algorithm to combine features with the same entity type. I wrote up a script to do just that, along with comments. The program extracts the text property from the Point feature and places it into the properties of the LineString feature. Then, we essentially discard Point. BTW, your 'before' json data has a trailing comma that shouldn't be there. Using Python 3.7.0:

import json
import collections


def main():
    with open('before_data.json') as f:
        before_data = json.load(f)  # makes a python dict from the json file and stores in before
        features = before_data['features']  # list of features
        # loop through features, construct dictionary of entity handle mapped to point texts
        point_entities = collections.defaultdict()  # to avoid 'if key not in' pattern
        for feature in features:
            entity_handle = feature['properties']['EntityHandle']
            # only append points
            if feature['geometry']['type'] == 'Point':
                point_entities[entity_handle] = feature['properties']['Text']
        merged_features = []
        for feature in features:
            if feature['geometry']['type'] == 'LineString':
                entity_handle = feature['properties']['EntityHandle']
                text_percent = point_entities[entity_handle]
                feature['properties']['Text'] = text_percent
                merged_features.append(feature)
        # print(json.dumps(before_data, indent=4))
        result = before_data
        result['features'] = merged_features
    # compare with your expected output
    with open('after_data.json') as f:
        after_data = json.load(f)
        print(result == after_data)  # returns True
    # finally, write your result to a file
    with open('result.json', 'w') as output_file:
        json.dump(result, output_file)


if __name__ == '__main__':
    main()


来源:https://stackoverflow.com/questions/55411549/combine-part-of-geojson-object-into-another-in-python

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!