Geojson data. I must admit, it is one of the weirdest standard data formats that I have come across. But, they are out there and you adapt.
Begin with getting the keys of a nested dictionary.
def get_keys(data, num):
"""Return dictiony keys by level.
Parameters
----------
data : dictionary in geojson format
num : beginning index number
Useage
------
r = get_keys(data, 0)
"""
keys = []
if isinstance(data, dict):
num += 1
for key, value in data.items():
t = type(value).__name__
keys.append((num, key, t))
keys += get_keys(value, num)
elif isinstance(data, list):
for value in data[:1]:
keys += get_keys(value, num)
# num += 1
return keys
An example of a simple geojson with 3 shapes, a couple of them multipolygons and some attributes (which I don't actually carry about, but they were there).
In this example, I returned the level, name and data type. A quick modification to the above and you could return the values/items.
get_keys(vals, 0)
[(1, 'type', 'str'),
(1, 'crs', 'dict'),
(2, 'type', 'str'),
(2, 'properties', 'dict'),
(3, 'name', 'str'),
(1, 'features', 'list'),
(2, 'type', 'str'),
(2, 'id', 'int'),
(2, 'geometry', 'dict'),
(3, 'type', 'str'),
(3, 'coordinates', 'list'),
(2, 'properties', 'dict'),
(3, 'OBJECTID', 'int'),
(3, 'Parts', 'int'),
(3, 'Points', 'int'),
(3, 'Curves', 'int'),
(3, 'A0', 'str'),
(3, 'A1', 'str'),
(3, 'Longs_', 'int'),
(3, 'Area_perim', 'float'),
(3, 'srt_a0a1', 'int'),
(3, 'Int_nulls', 'int'),
(3, 'Float_nulls', 'NoneType'),
(3, 'Text_nulls', 'str'),
(3, 'OID_', 'int'),
(3, 'Dbls_', 'int'),
(3, 'Shape_Length', 'float'),
(3, 'Shape_Area', 'float')]
Not bad, but one of the 1's is out of the expected order, so on to the next incarnation...printing to show the nested levels of the keys.
prn_keys(vals, 0)
1 type str
1 crs dict
2 type str
2 properties dict
3 name str
1 features list
2 type str
2 id int
2 geometry dict
3 type str
3 coordinates list
2 properties dict
3 OBJECTID int
3 Parts int
3 Points int
3 Curves int
3 A0 str
3 A1 str
3 Longs_ int
3 Area_perim float
3 srt_a0a1 int
3 Int_nulls int
3 Float_nulls NoneType
3 Text_nulls str
3 OID_ int
3 Dbls_ int
3 Shape_Length float
3 Shape_Area float
You can use numpy to pull out information from the key data
kys = get_keys(vals, 0)
dt = np.dtype([('Level', 'i4'), ('Key_name', 'U15'), ('Type', 'U10')])
val_arr = np.asarray(kys, dtype=dt)
#
# -- do a little query, pull out the results, and show as a list
q = val_arr['Level'] == 1 # query, get all level 1 keys
result = val_arr[q]
result.tolist()
##
[(1, 'type', 'str'),
(1, 'crs', 'dict'),
(1, 'features', 'list')]
If you want to load a geojson and mess with the data structure yourself, here is a script
def load_geojson(pth, full=True, just_geometry=False):
"""Load a geojson file and convert to a Geo Array.
The geojson is from the ``Features to JSON`` tool listed in the references.
Parameters
----------
pth : file path
Full file path to the geojson file.
full : boolean
True to return a formatted geojson file.
geometry : boolean
True returns just the geometry of the file.
Returns
-------
data : dictionary
The full geojson dictionary of the geometry and its attributes. The
result is a nested dictionary::
>>> data
... {'type': # first feature
... 'crs': {'type': 'name', 'properties': {'name': 'EPSG:2951'}},
... 'features':
... [{'type': 'Feature',
... 'id': 1,
... 'geometry': {'type': 'MultiPolygon',
... 'coordinates': snip}, # coordinate values
... 'properties': snip }}, # attribute values from table
... {'type': # next feature
... ... repeat}
geometry : list
A list of lists representing the features, their parts (for multipart
features) and inner holes (for polygons).
Notes
-----
Using the Features to JSON tool in ArcGIS PRO, the .json option was used.
- Unchecked : The output will be created as Esri JSON (.json).
- Checked : The output will be created in the GeoJSON format (.geojson).
References
----------
`geojson specification in detail
<https://geojson.org/>`_.
`Wikipedia link
<https://en.wikipedia.org/wiki/GeoJSON>`_.
`Features to JSON
<https://pro.arcgis.com/en/pro-app/tool-reference/conversion/
features-to-json.htm>`_.
`JSON to Features
<https://pro.arcgis.com/en/pro-app/tool-reference/conversion/
json-to-features.htm>`_.
"""
# import json # required if run outside
with open(pth) as f:
data = json.load(f)
type_key = pth.split(".")[-1]
keys = list(data.keys())
if 'features' in keys:
shapes = data['features']
coord_key = ['rings', 'coordinates'][type_key == 'geojson']
coords = [s['geometry'][coord_key] for s in shapes] # 'rings'
if full and just_geometry:
print("\nReturning full geojson and just the geometry portion")
print("as a list")
return data, coords
if full:
return data
if just_geometry:
return coords
If you are interested in alternate geometry construct, see and example on my github site (geo arrays)
NumPy Geometry (npg geometry arrays)
Enjoy
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.