Skip to content

Commit bcf2ad7

Browse files
authored
feat: allow tag dict column
closes #130
1 parent 28a1f35 commit bcf2ad7

File tree

4 files changed

+153
-3
lines changed

4 files changed

+153
-3
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88
- accept shapely Polygon and MultiPolygon for `bpolys` input parameter
99
- if a request fails a bash script containing the respective `curl` command is logged (if possible). This allows for easier debugging and sharing of failed requests.
1010

11+
### Changed
12+
13+
- breaking: geodataframes now contain a `@other_tags` colum containing all OSM tags. This behaviour can be adapted using the `explode_tags` parameter that allows to specify tags that should be in a separate column or to disable the feature completely. The latter will result in a potentially wide but sparse data frame.
14+
1115
### Removed
1216

1317
- support for python < 3.10

ohsome/response.py

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
"""Class for ohsome API response"""
55

66
import json
7+
from typing import Optional
78

89
import geopandas as gpd
910
import pandas as pd
@@ -22,17 +23,22 @@ def __init__(self, response=None, url=None, params=None):
2223
self.parameters = params
2324
self.data = response.json()
2425

25-
def as_dataframe(self, multi_index=True):
26+
def as_dataframe(
27+
self, multi_index: Optional[bool] = True, explode_tags: Optional[tuple] = ()
28+
):
2629
"""
2730
Converts the ohsome response to a pandas.DataFrame or a geopandas.GeoDataFrame if the
2831
response contains geometries
2932
:param multi_index: If true returns the dataframe with a multi index
33+
:param explode_tags: By default, tags of extracted features are stored in a single dict-column. You can specify
34+
a tuple of tags that should be popped from this column. To disable it completely, pass None. Yet, be aware that
35+
you may get a large but sparse data frame.
3036
:return: pandas.DataFrame or geopandas.GeoDataFrame
3137
"""
3238
if "features" not in self.data.keys():
3339
return self._as_dataframe(multi_index)
3440
else:
35-
return self._as_geodataframe(multi_index)
41+
return self._as_geodataframe(multi_index, explode_tags)
3642

3743
def _as_dataframe(self, multi_index=True):
3844
"""
@@ -67,7 +73,9 @@ def _as_dataframe(self, multi_index=True):
6773

6874
return result_df.sort_index()
6975

70-
def _as_geodataframe(self, multi_index=True):
76+
def _as_geodataframe(
77+
self, multi_index: Optional[bool] = True, explode_tags: Optional[tuple] = ()
78+
):
7179
"""
7280
Converts the ohsome response to a geopandas.GeoDataFrame
7381
:param multi_index: If true returns the dataframe with a multi index
@@ -78,7 +86,25 @@ def _as_geodataframe(self, multi_index=True):
7886
return gpd.GeoDataFrame(crs="epsg:4326", columns=["@osmId", "geometry"])
7987

8088
try:
89+
if explode_tags is not None:
90+
for feature in self.data["features"]:
91+
properties = feature["properties"]
92+
tags = {}
93+
new_properties = {}
94+
for k in properties.keys():
95+
if (
96+
(k.startswith("@"))
97+
or (k == "timestamp")
98+
or (k in explode_tags)
99+
):
100+
new_properties[k] = properties.get(k)
101+
else:
102+
tags[k] = properties.get(k)
103+
new_properties["@other_tags"] = tags
104+
feature["properties"] = new_properties
105+
81106
features = gpd.GeoDataFrame().from_features(self.data, crs="epsg:4326")
107+
82108
except TypeError:
83109
raise TypeError(
84110
"This result type cannot be converted to a GeoPandas GeoDataFrame object."
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
interactions:
2+
- request:
3+
body: bboxes=8.7137%2C49.4096%2C8.717%2C49.4119&time=2016-01-01&filter=name%3DKrautturm+and+type%3Away&properties=tags%2Cmetadata
4+
headers:
5+
Accept:
6+
- '*/*'
7+
Accept-Encoding:
8+
- gzip, deflate
9+
Connection:
10+
- keep-alive
11+
Content-Length:
12+
- '123'
13+
Content-Type:
14+
- application/x-www-form-urlencoded
15+
user-agent:
16+
- ohsome-py/0.2.0
17+
method: POST
18+
uri: https://api.ohsome.org/v1/elements/geometry
19+
response:
20+
body:
21+
string: "{\n \"attribution\" : {\n \"url\" : \"https://ohsome.org/copyrights\",\n
22+
\ \"text\" : \"\xA9 OpenStreetMap contributors\"\n },\n \"apiVersion\"
23+
: \"1.10.1\",\n \"type\" : \"FeatureCollection\",\n \"features\" : [{\n
24+
\ \"type\" : \"Feature\",\n \"geometry\" : {\n \"type\" : \"Polygon\",\n
25+
\ \"coordinates\" : [\n [\n [\n 8.7160632,\n
26+
\ 49.4102899\n ],\n [\n 8.7160749,\n
27+
\ 49.4103121\n ],\n [\n 8.7160827,\n
28+
\ 49.4103235\n ],\n [\n 8.7160963,\n
29+
\ 49.4103374\n ],\n [\n 8.716121,\n
30+
\ 49.4103549\n ],\n [\n 8.7161392,\n
31+
\ 49.4103691\n ],\n [\n 8.7161626,\n
32+
\ 49.4103819\n ],\n [\n 8.716186,\n
33+
\ 49.4103894\n ],\n [\n 8.716225,\n
34+
\ 49.4103952\n ],\n [\n 8.7162679,\n
35+
\ 49.4103926\n ],\n [\n 8.7162893,\n
36+
\ 49.4103882\n ],\n [\n 8.7163176,\n
37+
\ 49.410378\n ],\n [\n 8.7163507,\n
38+
\ 49.4103615\n ],\n [\n 8.7163829,\n
39+
\ 49.4103317\n ],\n [\n 8.7163975,\n
40+
\ 49.4103057\n ],\n [\n 8.7164024,\n
41+
\ 49.4102791\n ],\n [\n 8.7164004,\n
42+
\ 49.4102506\n ],\n [\n 8.7163868,\n
43+
\ 49.4102277\n ],\n [\n 8.7162815,\n
44+
\ 49.4102258\n ],\n [\n 8.7162659,\n
45+
\ 49.4102189\n ],\n [\n 8.7162503,\n
46+
\ 49.4102144\n ],\n [\n 8.7162289,\n
47+
\ 49.4102106\n ],\n [\n 8.7162113,\n
48+
\ 49.4102093\n ],\n [\n 8.7161987,\n
49+
\ 49.4101992\n ],\n [\n 8.7161665,\n
50+
\ 49.4101992\n ],\n [\n 8.7161519,\n
51+
\ 49.4101954\n ],\n [\n 8.7161343,\n
52+
\ 49.4101846\n ],\n [\n 8.7161119,\n
53+
\ 49.4101967\n ],\n [\n 8.7160934,\n
54+
\ 49.4102119\n ],\n [\n 8.7160807,\n
55+
\ 49.4102277\n ],\n [\n 8.7160719,\n
56+
\ 49.4102449\n ],\n [\n 8.7160671,\n
57+
\ 49.4102594\n ],\n [\n 8.7160641,\n
58+
\ 49.4102753\n ],\n [\n 8.7160632,\n
59+
\ 49.4102899\n ]\n ]\n ]\n },\n \"properties\"
60+
: {\n \"@changesetId\" : 30687511,\n \"@lastEdit\" : \"2015-05-01T10:33:22Z\",\n
61+
\ \"@osmId\" : \"way/24885641\",\n \"@osmType\" : \"way\",\n \"@snapshotTimestamp\"
62+
: \"2016-01-01T00:00:00Z\",\n \"@version\" : 4,\n \"building\" :
63+
\"yes\",\n \"name\" : \"Krautturm\"\n }\n }]\n}\n"
64+
headers:
65+
Access-Control-Allow-Credentials:
66+
- 'true'
67+
Access-Control-Allow-Headers:
68+
- Origin,Accept,X-Requested-With,Content-Type,Access-Control-Request-Method,Access-Control-Request-Headers,Authorization
69+
Access-Control-Allow-Methods:
70+
- POST, GET
71+
Access-Control-Allow-Origin:
72+
- '*'
73+
Access-Control-Max-Age:
74+
- '3600'
75+
Connection:
76+
- Keep-Alive
77+
Content-Encoding:
78+
- gzip
79+
Content-Type:
80+
- application/geo+json;charset=utf-8
81+
Content-disposition:
82+
- attachment;filename=ohsome.geojson
83+
Date:
84+
- Fri, 17 Nov 2023 14:22:26 GMT
85+
Keep-Alive:
86+
- timeout=5, max=100
87+
Server:
88+
- Apache
89+
Strict-Transport-Security:
90+
- max-age=63072000; includeSubdomains;
91+
Transfer-Encoding:
92+
- chunked
93+
vary:
94+
- accept-encoding
95+
status:
96+
code: 200
97+
message: ''
98+
version: 1

ohsome/test/test_response.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,28 @@ def test_elements_geometry(base_client):
265265
assert len(result) == 1
266266

267267

268+
@pytest.mark.vcr
269+
def test_extra_tags_argument(base_client):
270+
"""
271+
Tests whether the result of elements.geometry is converted to a geopandas.GeoDataFrame
272+
:return:
273+
"""
274+
bboxes = "8.7137,49.4096,8.717,49.4119"
275+
time = "2016-01-01"
276+
flter = "name=Krautturm and type:way"
277+
278+
response = base_client.elements.geometry.post(
279+
bboxes=bboxes, time=time, filter=flter, properties="tags,metadata"
280+
)
281+
result = response.as_dataframe()
282+
283+
assert "@other_tags" in result.columns
284+
assert "@version" in result.columns
285+
286+
assert result["@other_tags"].to_list() == [{"building": "yes", "name": "Krautturm"}]
287+
assert result["@version"].to_list() == [4]
288+
289+
268290
@pytest.mark.vcr
269291
def test_elementsFullHistory_geometry(base_client):
270292
"""

0 commit comments

Comments
 (0)