"""Utility functions to manage geospatial vector data in geojson format."""
# Author(s): Davide.De-Marchi@ec.europa.eu
# Copyright © European Union 2022-2023
#
# Licensed under the EUPL, Version 1.2 or as soon they will be approved by
# the European Commission subsequent versions of the EUPL (the "Licence");
#
# You may not use this work except in compliance with the Licence.
#
# You may obtain a copy of the Licence at:
# https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
# Unless required by applicable law or agreed to in writing, software
# distributed under the Licence is distributed on an "AS IS"
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
# express or implied.
#
# See the Licence for the specific language governing permissions and
# limitations under the Licence.import json
import json
# Given a geojson string, returns a json object after having tested that the input string contains a valid geojson
[docs]def geojsonJson(geojson):
"""
Given a geojson string, returns a json dictionary after having tested that the input string contains a valid geojson
Parameters
----------
geojson : str
String containing data in geojson format
Returns
-------
Json dictionary
Raises
------
Exception if the input string is not in geojson format
"""
j = json.loads(geojson)
if j.get('type', None) != 'FeatureCollection':
raise Exception('Sorry, input string does not look like GeoJSON')
if type(j.get('features', None)) != list:
raise Exception('Sorry, input string does not contains GeoJSON features')
return j
# Load a geojson from file, testing that it contains a valid geojson
# Returns a string
[docs]def geojsonLoadFile(filepath):
"""
Load a geojson content from file, testing that it contains valid geojson data
Parameters
----------
filepath : str
File path of the geojson file to load
Returns
-------
File content as a geojson string
Example
-------
Load a geojson from file, print the geojson string::
from vois import geojsonUtils
geojson = geojsonUtils.geojsonLoadFile('./data/example.geojson')
print(geojson)
.. figure:: figures/geojsonLoad.png
:scale: 100 %
:alt: Geojson example geojsonLoadFile
Read a geojson file and print its content
"""
with open(filepath,"r") as f:
geojson = f.read()
j = geojsonJson(geojson)
return json.dumps(j)
# Given a geojson string, returns the number of features
[docs]def geojsonCount(geojson):
"""
Given a geojson string, returns the number of features
Parameters
----------
geojson : str
String containing data in geojson format
Returns
-------
Integer corresponding to the number of features in the input geojson string
"""
j = geojsonJson(geojson)
return len(j['features'])
# Given a geojson string, returns the list of the attribute names of the features
[docs]def geojsonAttributes(geojson):
"""
Given a geojson string, returns the list of the attribute names of the features
Parameters
----------
geojson : str
String containing data in geojson format
Returns
-------
List of strings containing the names of the attributes of the features in the input geojson string
Example
-------
Load a geojson from file and print the names of its attributes::
from vois import geojsonUtils
geojson = geojsonUtils.geojsonLoadFile('./data/example.geojson')
print('Attributes = ', geojsonUtils.geojsonAttributes(geojson))
.. figure:: figures/geojsonAttributes.png
:scale: 100 %
:alt: Geojson example geojsonAttributes
Read a geojson file and print the names of its attributes
"""
j = geojsonJson(geojson)
features = j['features']
attributes = set()
for f in features:
attributes.update(f['properties'].keys())
return list(attributes)
# Given a geojson string, returns the list of values of the attribute attributeName for all the features
[docs]def geojsonAll(geojson, attributeName):
"""
Given a geojson string, returns the list of values of the attribute attributeName for all the features
Parameters
----------
geojson : str
String containing data in geojson format
attributeName : str
Name of one of the attributes
Returns
-------
List containing the values of the attribute for all the features of the input geojson dataset
Example
-------
Load a geojson from file and print all the values of one if its attributes::
from vois import geojsonUtils
geojson = geojsonUtils.geojsonLoadFile('./data/example.geojson')
print('Values = ', geojsonUtils.geojsonAll(geojson,'ha'))
.. figure:: figures/geojsonAll.png
:scale: 100 %
:alt: Geojson example geojsonAll
Read a geojson file and print the values of one of its attributes for all the features of the dataset
"""
j = geojsonJson(geojson)
features = j['features']
attributes = set()
values = [f['properties'][attributeName] if attributeName in f['properties'] else None for f in features]
return values
# Add a field to a geojson by joining a python dictionary through match with the field named keyname.
# If innerMode is True, the output geojson will only keep the joined features, otherwise all the original features are returned
# Returns the modified geojson
[docs]def geojsonJoin(geojson, keyname, addedfieldname, keytovaluedict, innerMode=False):
"""
Add a field to a geojson by joining a python dictionary through match with the field named keyname.
If innerMode is True, the output geojson will only keep the joined features, otherwise all the original features are returned
Parameters
----------
geojson : str
String containing data in geojson format
keyname : str
Name of the attribute of the input geojson to use as internal key for the join operation
addedfieldname : str
Name of the attribute to add to the input geojson as a result of the join operation
keytovaluedict : dict
Dictionary (key-value pairs) to use as joined values. The keys of the <keytovaluedict> are used as foreign keys to match the values of the <keyname> attribute of the input geojson. When a match is found, the attribute <addedfieldname> is added to the corresponding feature having the value read from the <keytovaluedict>
innerMode : bool, optional
If innerMode is True, the output geojson will only keep the successfully joined features, otherwise all the original features are returned
Returns
-------
a string containing the modified geojson after the join operation
Example
-------
Load a geojson from file, print some information on attributes and values of the features, then join the features with a dictionary::
from vois import geojsonUtils
# Load a geojson file
geojson = geojsonUtils.geojsonLoadFile('./data/example.geojson')
# Add a new field by joining with a dictionary (with innerMode flag set to True)
keytovalue = { 37661: 'aaa', 37662: 'bbb'}
geojsonnew = geojsonUtils.geojsonJoin(geojson,'id', 'value', keytovalue, innerMode=True)
# Print the 'value' attribute values for the joined geojson dataset
print('Joined values =', geojsonUtils.geojsonAll(geojsonnew,'value'))
.. figure:: figures/geojsonJoin.png
:scale: 100 %
:alt: Geojson example
Result of the Join operation
"""
j = geojsonJson(geojson)
# Feature collection to return
res = {
"type": "FeatureCollection",
"features": []
}
if 'crs' in j:
res['crs'] = j['crs']
for f in j['features']:
if 'properties' in f:
if keyname in f['properties']:
key = f['properties'][keyname]
if key in keytovaluedict:
value = keytovaluedict[key]
f['properties'][addedfieldname] = value
if innerMode:
res['features'].append(f)
if not innerMode:
res['features'].append(f)
return json.dumps(res)
# Filter a geojson by keeping only the features for which <fieldname> has value <fieldvalue> (fieldvalue can be also a list!)
# Returns the modified geojson
[docs]def geojsonFilter(geojson, fieldname, fieldvalue):
"""
Filter a geojson by keeping only the features for which <fieldname> has value <fieldvalue> (fieldvalue can be also a list)
Parameters
----------
geojson : str
String containing data in geojson format
fieldname : str
Name of one of the attributes of the input geojson
fieldvalue : single value or list of values
Comparison value. Only the input features having this value on the <fieldname> attribute are kept in the output geojson returned
Returns
-------
a string containing the modified geojson containing only the features that pass the filter operation
"""
j = geojsonJson(geojson)
# Feature collection to return
res = {
"type": "FeatureCollection",
"features": []
}
if 'crs' in j:
res['crs'] = j['crs']
for f in j['features']:
if 'properties' in f:
if fieldname in f['properties']:
fvalue = f['properties'][fieldname]
if (type(fieldvalue) is list and fvalue in fieldvalue) or (fvalue == fieldvalue):
res['features'].append(f)
return json.dumps(res)