Skip to content

Commit 984d821

Browse files
committed
feat: use filtering in street project
1 parent 80ecf28 commit 984d821

File tree

5 files changed

+124
-20
lines changed

5 files changed

+124
-20
lines changed

mapswipe_workers/mapswipe_workers/project_types/street/project.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,15 @@ def __init__(self, project_draft):
4646
self.tasks: Dict[str, List[StreetTask]] = {}
4747

4848
self.geometry = project_draft["geometry"]
49-
ImageMetadata = get_image_metadata(self.geometry)
49+
50+
# TODO: validate inputs
51+
ImageMetadata = get_image_metadata(
52+
self.geometry,
53+
is_pano=project_draft.get("isPano", None),
54+
start_time=project_draft.get("startTimestamp", None),
55+
end_time=project_draft.get("endTimestamp", None),
56+
organization_id=project_draft.get("organizationId", None),
57+
)
5058

5159

5260
self.imageIds = ImageMetadata["ids"]

mapswipe_workers/mapswipe_workers/utils/process_mapillary.py

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
from vt2geojson import tools as vt2geojson_tools
1818
from concurrent.futures import ThreadPoolExecutor, as_completed
1919
from mapswipe_workers.definitions import MAPILLARY_API_LINK, MAPILLARY_API_KEY
20+
from mapswipe_workers.definitions import logger
2021

2122

2223
def create_tiles(polygon, level):
@@ -128,6 +129,12 @@ def coordinate_download(
128129
failed_tiles = pd.DataFrame(failed_tiles, columns=tiles.columns).reset_index(
129130
drop=True
130131
)
132+
target_columns = [
133+
"id", "geometry", "captured_at", "is_pano", "compass_angle", "sequence", "organization_id"
134+
]
135+
for col in target_columns:
136+
if col not in downloaded_metadata.columns:
137+
downloaded_metadata[col] = None
131138

132139
return downloaded_metadata, failed_tiles
133140

@@ -157,11 +164,11 @@ def geojson_to_polygon(geojson_data):
157164

158165
def filter_by_timerange(df: pd.DataFrame, start_time: str, end_time: str = None):
159166
df["captured_at"] = pd.to_datetime(df["captured_at"], unit="ms")
160-
start_time = pd.Timestamp(start_time)
161-
167+
start_time = pd.to_datetime(start_time).tz_localize(None)
162168
if end_time is None:
163-
end_time = pd.Timestamp.now()
164-
169+
end_time = pd.Timestamp.now().tz_localize(None)
170+
else:
171+
end_time = pd.to_datetime(end_time).tz_localize(None)
165172
filtered_df = df[
166173
(df["captured_at"] >= start_time) & (df["captured_at"] <= end_time)
167174
]
@@ -177,12 +184,30 @@ def filter_results(
177184
):
178185
df = results_df.copy()
179186
if is_pano is not None:
187+
if df["is_pano"].isna().all():
188+
logger.exception(
189+
"No Mapillary Feature in the AoI has a 'is_pano' value."
190+
)
191+
return None
180192
df = df[df["is_pano"] == is_pano]
193+
181194
if organization_id is not None:
195+
if df["organization_id"].isna().all():
196+
logger.exception(
197+
"No Mapillary Feature in the AoI has an 'organization_id' value."
198+
)
199+
return None
182200
df = df[df["organization_id"] == organization_id]
201+
183202
if start_time is not None:
203+
if df["captured_at"].isna().all():
204+
logger.exception(
205+
"No Mapillary Feature in the AoI has a 'captured_at' value."
206+
)
207+
return None
184208
df = filter_by_timerange(df, start_time, end_time)
185209

210+
186211
return df
187212

188213

@@ -202,7 +227,10 @@ def get_image_metadata(
202227
downloaded_metadata = filter_results(
203228
downloaded_metadata, is_pano, organization_id, start_time, end_time
204229
)
205-
return {
206-
"ids": downloaded_metadata["id"].tolist(),
207-
"geometries": downloaded_metadata["geometry"].tolist(),
208-
}
230+
if downloaded_metadata.isna().all().all() == False:
231+
return {
232+
"ids": downloaded_metadata["id"].tolist(),
233+
"geometries": downloaded_metadata["geometry"].tolist(),
234+
}
235+
else:
236+
raise ValueError("No Mapillary Features in the AoI match the filter criteria.")

mapswipe_workers/tests/fixtures/projectDrafts/street.json

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,5 @@
4747
"verificationNumber": 3,
4848
"groupSize": 25,
4949
"isPano": false,
50-
"startTimestamp": "2019-07-01T00:00:00.000Z",
51-
"endTimestamp": null,
52-
"organisationId": "1"
50+
"startTimestamp": "2019-07-01T00:00:00.000Z"
5351
}

mapswipe_workers/tests/unittests/test_process_mapillary.py

Lines changed: 62 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,10 @@
1818
geojson_to_polygon,
1919
filter_by_timerange,
2020
filter_results,
21+
get_image_metadata,
2122
)
2223

2324

24-
# Assuming create_tiles, download_and_process_tile, and coordinate_download are imported
25-
26-
2725
class TestTileGroupingFunctions(unittest.TestCase):
2826
@classmethod
2927
def setUpClass(cls):
@@ -156,13 +154,11 @@ def test_geojson_to_polygon_contribution_geojson(self):
156154
)
157155
@patch("mapswipe_workers.utils.process_mapillary.requests.get")
158156
def test_download_and_process_tile_success(self, mock_get, mock_vt2geojson):
159-
# Mock the response from requests.get
160157
mock_response = MagicMock()
161158
mock_response.status_code = 200
162159
mock_response.content = b"mock vector tile data" # Example mock data
163160
mock_get.return_value = mock_response
164161

165-
# Mock the return value of vt_bytes_to_geojson
166162
mock_vt2geojson.return_value = {
167163
"features": [
168164
{
@@ -176,7 +172,6 @@ def test_download_and_process_tile_success(self, mock_get, mock_vt2geojson):
176172

177173
result, failed = download_and_process_tile(row)
178174

179-
# Assertions
180175
self.assertIsNone(failed)
181176
self.assertIsInstance(result, pd.DataFrame)
182177
self.assertEqual(len(result), 1)
@@ -269,6 +264,67 @@ def test_filter_time_range(self):
269264
)
270265
self.assertEqual(len(filtered_df), 3)
271266

267+
def test_filter_no_rows_after_filter(self):
268+
filtered_df = filter_results(self.fixture_df, is_pano="False")
269+
self.assertTrue(filtered_df.empty)
270+
271+
def test_filter_missing_columns(self):
272+
columns_to_check = ["is_pano", "organization_id", "captured_at"] # Add your column names here
273+
for column in columns_to_check:
274+
df_copy = self.fixture_df.copy()
275+
df_copy[column] = None
276+
if column == "captured_at":
277+
column = "start_time"
278+
279+
result = filter_results(df_copy, **{column: True})
280+
self.assertIsNone(result)
281+
282+
@patch("mapswipe_workers.utils.process_mapillary.coordinate_download")
283+
def test_get_image_metadata(self, mock_coordinate_download):
284+
mock_coordinate_download.return_value = (
285+
self.fixture_df,
286+
None,
287+
)
288+
result = get_image_metadata(self.fixture_data)
289+
self.assertIsInstance(result, dict)
290+
self.assertIn("ids", result)
291+
self.assertIn("geometries", result)
292+
293+
294+
@patch("mapswipe_workers.utils.process_mapillary.coordinate_download")
295+
def test_get_image_metadata_filtering(self, mock_coordinate_download):
296+
mock_coordinate_download.return_value = (
297+
self.fixture_df,
298+
None,
299+
)
300+
301+
params = {
302+
"is_pano": True,
303+
"start_time": "2016-01-20 00:00:00",
304+
"end_time": "2022-01-21 23:59:59",
305+
}
306+
307+
result = get_image_metadata(self.fixture_data, **params)
308+
self.assertIsInstance(result, dict)
309+
self.assertIn("ids", result)
310+
self.assertIn("geometries", result)
311+
312+
313+
@patch("mapswipe_workers.utils.process_mapillary.coordinate_download")
314+
def test_get_image_metadata_no_rows(self, mock_coordinate_download):
315+
mock_coordinate_download.return_value = (
316+
self.fixture_df,
317+
None,
318+
)
319+
320+
params = {
321+
"is_pano": True,
322+
"start_time": "1916-01-20 00:00:00",
323+
"end_time": "1922-01-21 23:59:59",
324+
}
325+
with self.assertRaises(ValueError):
326+
get_image_metadata(self.fixture_data, **params)
327+
272328

273329
if __name__ == "__main__":
274330
unittest.main()

mapswipe_workers/tests/unittests/test_project_type_street.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import os
33
import unittest
44
from unittest.mock import patch
5+
import pandas as pd
56

67
from mapswipe_workers.project_types import StreetProject
78
from tests import fixtures
@@ -16,7 +17,21 @@ def setUp(self) -> None:
1617
)
1718
)
1819
project_draft["projectDraftId"] = "foo"
19-
self.project = StreetProject(project_draft)
20+
21+
with patch(
22+
"mapswipe_workers.utils.process_mapillary.coordinate_download"
23+
) as mock_get:
24+
with open(
25+
os.path.join(
26+
os.path.dirname(os.path.abspath(__file__)),
27+
"..",
28+
"fixtures",
29+
"mapillary_response.csv",
30+
),
31+
"r",
32+
) as file:
33+
mock_get.return_value = (pd.read_csv(file), None)
34+
self.project = StreetProject(project_draft)
2035

2136
def test_init(self):
2237
self.assertEqual(self.project.geometry["type"], "FeatureCollection")
@@ -30,7 +45,6 @@ def test_create_tasks(self):
3045
self.project.create_groups()
3146
self.project.create_tasks()
3247
self.assertEqual(self.project.tasks["g0"][0].taskId, imageId)
33-
# self.assertEqual(self.project.groups["g0"].numberOfTasks, 1)
3448

3549

3650
if __name__ == "__main__":

0 commit comments

Comments
 (0)