问题
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