diff --git a/CHANGELOG.md b/CHANGELOG.md
index ea5d0364f..343695f47 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,13 @@
# Changelog
+## Current Main
+
+### New Features
+
+- building-comparison: support comparison with multiple datasets ([#768])
+
+[#768]: https://github.com/GIScience/ohsome-quality-api/pull/768
+
## Release 1.2.0
### New Features
diff --git a/ohsome_quality_api/definitions.py b/ohsome_quality_api/definitions.py
index 58d32a2cf..59e78d528 100644
--- a/ohsome_quality_api/definitions.py
+++ b/ohsome_quality_api/definitions.py
@@ -22,6 +22,7 @@
"VNL": "Earth Observation Group Nighttime Light Data",
"EUBUCCO": "European building stock characteristics in a common and open "
+ "database",
+ "Microsoft Buildings": "Microsoft Building Footprints (ODbL)",
}
)
@@ -106,6 +107,6 @@ def get_project_keys() -> Iterable[str]:
def get_attribution(data_keys: list) -> str:
"""Return attribution text. Individual attributions are separated by semicolons."""
- assert set(data_keys) <= {"OSM", "GHSL", "VNL", "EUBUCCO"}
+ assert set(data_keys) <= {"OSM", "GHSL", "VNL", "EUBUCCO", "Microsoft Buildings"}
filtered = dict(filter(lambda d: d[0] in data_keys, ATTRIBUTION_TEXTS.items()))
return "; ".join([str(v) for v in filtered.values()])
diff --git a/ohsome_quality_api/geodatabase/client.py b/ohsome_quality_api/geodatabase/client.py
index db936c1dc..ac08362a0 100644
--- a/ohsome_quality_api/geodatabase/client.py
+++ b/ohsome_quality_api/geodatabase/client.py
@@ -19,7 +19,7 @@
import asyncpg
import geojson
from asyncpg import Record
-from geojson import Feature, FeatureCollection
+from geojson import Feature, FeatureCollection, MultiPolygon
from ohsome_quality_api.config import get_config_value
@@ -69,50 +69,44 @@ async def get_shdi(bpoly: Feature | FeatureCollection) -> list[Record]:
return await conn.fetch(query, geom)
-async def get_building_area(bpoly: Feature) -> list[Record]:
- """Get area of building footprints for a bounding polygon."""
- file_path = os.path.join(WORKING_DIR, "select_building_area.sql")
+# TODO: Check calls of the function
+async def get_reference_coverage(table_name: str) -> Feature:
+ """Get reference coverage for a bounding polygon."""
+ file_path = os.path.join(WORKING_DIR, "select_coverage.sql")
with open(file_path, "r") as file:
query = file.read()
- geom = str(bpoly.geometry)
async with get_connection() as conn:
- return await conn.fetch(query, geom)
+ result = await conn.fetch(query.format(table_name=table_name))
+ return Feature(geometry=geojson.loads(result[0]["geom"]))
-async def get_eubucco_coverage(inverse: bool) -> list[Record]:
- file_path = os.path.join(WORKING_DIR, "select_eubucco_coverage.sql")
- with open(file_path, "r") as file:
- query = file.read()
- if inverse:
- table_name = "eubucco_v0_1_coverage_inversed"
- else:
- table_name = "eubucco_v0_1_coverage_simple"
- query = query.format(table_name=table_name)
- async with get_connection() as conn:
- return await conn.fetch(query)
-
-
-async def get_eubucco_coverage_intersection_area(bpoly: Feature) -> list[Record]:
+async def get_intersection_area(bpoly: Feature, table_name: str) -> float:
"""Get ratio of AOI area to intersection area of AOI and coverage geometry.
The result is the ratio of area within coverage (between 0-1) or an empty list if
AOI lies outside of coverage geometry.
"""
- file_path = os.path.join(WORKING_DIR, "select_check_eubucco_coverage.sql")
+ file_path = os.path.join(WORKING_DIR, "select_intersection.sql")
with open(file_path, "r") as file:
query = file.read()
geom = str(bpoly.geometry)
async with get_connection() as conn:
- return await conn.fetch(query, geom)
+ result = await conn.fetch(query.format(table_name=table_name), geom)
+ if result:
+ return result[0]["area_ratio"]
+ else:
+ return 0.0
-async def get_eubucco_coverage_intersection(bpoly: Feature) -> Feature:
+async def get_intersection_geom(bpoly: Feature, table_name: str) -> Feature:
"""Get intersection geometry of AoI and coverage geometry."""
- file_path = os.path.join(WORKING_DIR, "get_coverage_intersection.sql")
+ file_path = os.path.join(WORKING_DIR, "select_intersection.sql")
with open(file_path, "r") as file:
query = file.read()
geom = str(bpoly.geometry)
async with get_connection() as conn:
- result = await conn.fetch(query, geom)
- bpoly["geometry"] = geojson.loads(result[0]["geom"])
- return bpoly
+ result = await conn.fetch(query.format(table_name=table_name), geom)
+ if result:
+ return Feature(geometry=geojson.loads(result[0]["geom"]))
+ else:
+ return Feature(geometry=MultiPolygon(coordinates=[]))
diff --git a/ohsome_quality_api/geodatabase/get_coverage_intersection.sql b/ohsome_quality_api/geodatabase/get_coverage_intersection.sql
deleted file mode 100644
index d2f49edac..000000000
--- a/ohsome_quality_api/geodatabase/get_coverage_intersection.sql
+++ /dev/null
@@ -1,11 +0,0 @@
-WITH bpoly AS (
- SELECT
- ST_Setsrid (ST_GeomFromGeoJSON ($1), 4326) AS geom
-)
-SELECT
- ST_AsGeoJSON (ST_Intersection (bpoly.geom, coverage.geom)) AS geom
-FROM
- bpoly,
- eubucco_v0_1_coverage_simple coverage
-WHERE
- ST_Intersects (bpoly.geom, coverage.geom)
diff --git a/ohsome_quality_api/geodatabase/select_building_area.sql b/ohsome_quality_api/geodatabase/select_building_area.sql
index eb7c26d3e..a4b34bb73 100644
--- a/ohsome_quality_api/geodatabase/select_building_area.sql
+++ b/ohsome_quality_api/geodatabase/select_building_area.sql
@@ -3,9 +3,8 @@ WITH bpoly AS (
ST_Setsrid (ST_GeomFromGeoJSON (%s), 4326) AS geom
)
SELECT
- SUM(eubucco.area) as area
-FROM
- eubucco,
+ SUM({table_name}.area) as area
+FROM {table_name},
bpoly
WHERE
- ST_Intersects (eubucco.centroid, bpoly.geom);
+ ST_Intersects ({table_name}.centroid, bpoly.geom);
diff --git a/ohsome_quality_api/geodatabase/select_eubucco_coverage.sql b/ohsome_quality_api/geodatabase/select_coverage.sql
similarity index 100%
rename from ohsome_quality_api/geodatabase/select_eubucco_coverage.sql
rename to ohsome_quality_api/geodatabase/select_coverage.sql
diff --git a/ohsome_quality_api/geodatabase/select_check_eubucco_coverage.sql b/ohsome_quality_api/geodatabase/select_intersection.sql
similarity index 70%
rename from ohsome_quality_api/geodatabase/select_check_eubucco_coverage.sql
rename to ohsome_quality_api/geodatabase/select_intersection.sql
index 8e37f0447..cca64f558 100644
--- a/ohsome_quality_api/geodatabase/select_check_eubucco_coverage.sql
+++ b/ohsome_quality_api/geodatabase/select_intersection.sql
@@ -4,9 +4,10 @@ WITH bpoly AS (
)
SELECT
-- ratio of area within coverage (empty if outside, between 0-1 if intersection)
- ST_Area (ST_Intersection (bpoly.geom, coverage.geom)) / ST_Area (bpoly.geom) as area_ratio
+ ST_Area (ST_Intersection (bpoly.geom, coverage.geom)) / ST_Area (bpoly.geom) as area_ratio,
+ ST_AsGeoJSON (ST_Intersection (bpoly.geom, coverage.geom)) AS geom
FROM
bpoly,
- eubucco_v0_1_coverage_simple coverage
+ {table_name} coverage
WHERE
ST_Intersects (bpoly.geom, coverage.geom)
diff --git a/ohsome_quality_api/indicators/base.py b/ohsome_quality_api/indicators/base.py
index 3416198d8..ee0b02f82 100644
--- a/ohsome_quality_api/indicators/base.py
+++ b/ohsome_quality_api/indicators/base.py
@@ -2,7 +2,7 @@
from abc import ABCMeta, abstractmethod
import plotly.graph_objects as go
-from geojson import Feature, MultiPolygon, Polygon
+from geojson import Feature, Polygon
from ohsome_quality_api.definitions import get_attribution, get_metadata
from ohsome_quality_api.indicators.models import IndicatorMetadata, Result
@@ -102,22 +102,26 @@ def attribution(cls) -> str:
return get_attribution(["OSM"])
@classmethod
- async def coverage(cls, inverse=False) -> Polygon | MultiPolygon:
- """Return coverage geometry. Default is global coverage."""
+ async def coverage(cls, inverse=False) -> list[Feature]:
+ """Return coverage geometries. Default is global coverage."""
if inverse is False:
- return Polygon(
- coordinates=[
- [
- (-180, 90),
- (-180, -90),
- (180, -90),
- (180, 90),
- (-180, 90),
- ]
- ]
- )
+ return [
+ Feature(
+ geometry=Polygon(
+ coordinates=[
+ [
+ (-180, 90),
+ (-180, -90),
+ (180, -90),
+ (180, 90),
+ (-180, 90),
+ ]
+ ]
+ )
+ )
+ ]
else:
- return Polygon(coordinates=[])
+ return [Feature(Polygon(coordinates=[]))]
@abstractmethod
async def preprocess(self) -> None:
diff --git a/ohsome_quality_api/indicators/building_comparison/datasets.yaml b/ohsome_quality_api/indicators/building_comparison/datasets.yaml
new file mode 100644
index 000000000..d39c57acd
--- /dev/null
+++ b/ohsome_quality_api/indicators/building_comparison/datasets.yaml
@@ -0,0 +1,23 @@
+EUBUCCO:
+ name: EUBUCCO
+ link: https://docs.eubucco.com/
+ date: Nov 3, 2022
+ description: >-
+ EUBUCCO is a dataset of building footprints for Europe.
+ It is derived from administrative datasets.
+ color: PURPLE
+ coverage:
+ simple: eubucco_v0_1_coverage_simple
+ inversed: eubucco_v0_1_coverage_inversed
+
+Microsoft Buildings:
+ name: Microsoft Building Footprints
+ link: https://planetarycomputer.microsoft.com/dataset/ms-buildings
+ date: July 5, 2022
+ description: >-
+ Microsoft Building Footprints is a dataset of building footprints for the world.
+ It is derived from satellite imagery.
+ color: ORANGE
+ coverage:
+ simple: microsoft_buildings_coverage_simple
+ inversed: microsoft_buildings_coverage_inversed
diff --git a/ohsome_quality_api/indicators/building_comparison/indicator.py b/ohsome_quality_api/indicators/building_comparison/indicator.py
index 30a6295fd..f08cc2e01 100644
--- a/ohsome_quality_api/indicators/building_comparison/indicator.py
+++ b/ohsome_quality_api/indicators/building_comparison/indicator.py
@@ -1,5 +1,6 @@
import logging
import os
+from functools import cache
from string import Template
import geojson
@@ -8,7 +9,7 @@
import yaml
from async_lru import alru_cache
from dateutil import parser
-from geojson import Feature, MultiPolygon, Polygon
+from geojson import Feature
from numpy import mean
from ohsome_quality_api.config import get_config_value
@@ -29,173 +30,261 @@ def __init__(
topic=topic,
feature=feature,
)
- self.area_osm: float | None = None
- self.area_references: dict = {}
# The result is the ratio of area within coverage (between 0-1) or an empty list
- self.coverage: dict = {}
-
+ #
# TODO: Evaluate thresholds
self.th_high = 0.85 # Above or equal to this value label should be green
self.th_low = 0.50 # Above or equal to this value label should be yellow
self.above_one_th = 1.30
+ self.data_ref: dict[str, dict] = {}
+ self.area_osm: dict[str, float | None] = {}
+ self.area_ref: dict[str, float | None] = {}
+ self.area_cov: dict[str, float | None] = {}
+ self.ratio: dict[str, float | None] = {}
+ # self.data_ref: list = load_reference_datasets() # reference datasets
+ for key, val in load_datasets_metadata().items():
+ self.data_ref[key] = val
+ self.area_osm[key] = None # osm building area
+ self.area_ref[key] = None # reference building area [sqkm]
+ self.area_cov[key] = None # covered area [%]
+ self.ratio[key] = None
+
@classmethod
- async def coverage(cls, inverse=False) -> Polygon | MultiPolygon:
- result = await db_client.get_eubucco_coverage(inverse)
- return geojson.loads(result[0]["geom"])
+ async def coverage(cls, inverse=False) -> list[Feature]:
+ # TODO: could also return a Feature Collection
+ features = []
+ datasets = load_datasets_metadata()
+ for val in datasets.values():
+ if inverse:
+ table = val["coverage"]["inversed"]
+ else:
+ table = val["coverage"]["simple"]
+ feature_str = await db_client.get_reference_coverage(table)
+ geojson_dict = geojson.loads(feature_str)
+ feature = Feature(geometry=geojson_dict, properties={})
+ feature.properties.update({"refernce_dataset": val["name"]})
+ features.append(feature)
+ return features
@classmethod
def attribution(cls) -> str:
- return get_attribution(["OSM", "EUBUCCO"])
+ return get_attribution(["OSM", "EUBUCCO", "Microsoft Buildings"])
async def preprocess(self) -> None:
- result = await db_client.get_eubucco_coverage_intersection_area(self.feature)
- if result:
- self.coverage["EUBUCCO"] = result[0]["area_ratio"]
- else:
- self.coverage["EUBUCCO"] = None
- return
+ for key, val in self.data_ref.items():
+ # get coverage [%]
+ self.area_cov[key] = await db_client.get_intersection_area(
+ self.feature,
+ val["coverage"]["simple"],
+ )
- edge_case = self.check_major_edge_cases()
- if edge_case:
- self.result.description = edge_case
- return
+ if self.check_major_edge_cases(key):
+ continue
- self.feature = await db_client.get_eubucco_coverage_intersection(self.feature)
- db_query_result = await get_eubucco_building_area(geojson.dumps(self.feature))
- self.area_references["EUBUCCO"] = db_query_result / (1000 * 1000)
- osm_query_result = await ohsome_client.query(
- self.topic,
- self.feature,
- )
- raw = osm_query_result["result"][0]["value"] or 0 # if None
- self.area_osm = raw / (1000 * 1000)
- self.result.timestamp_osm = parser.isoparse(
- osm_query_result["result"][0]["timestamp"]
- )
+ # clip input geom with coverage of reference dataset
+ feature = await db_client.get_intersection_geom(
+ self.feature,
+ val["coverage"]["simple"],
+ )
+
+ # get reference building area
+ result = await get_reference_building_area(feature, key)
+ self.area_ref[key] = result / (1000 * 1000)
+
+ # get osm building area
+ result = await ohsome_client.query(self.topic, feature)
+ value = result["result"][0]["value"] or 0.0 # if None
+ self.area_osm[key] = value / (1000 * 1000)
+ timestamp = result["result"][0]["timestamp"]
+ self.result.timestamp_osm = parser.isoparse(timestamp)
def calculate(self) -> None:
# TODO: put checks into check_corner_cases. Let result be undefined.
- if self.result.label == "undefined" and self.check_major_edge_cases():
+ edge_cases = [self.check_major_edge_cases(k) for k in self.data_ref.keys()]
+ if all(edge_cases):
+ self.result.description += (
+ " None of the reference datasets covers the area-of-interest."
+ )
return
- if self.check_minor_edge_cases():
- self.result.description = self.check_minor_edge_cases()
- else:
- self.result.description = ""
+ self.result.description = "".join(edge_cases)
- if all(v == 0 for v in self.area_references.values()):
- self.result.description += "Warning: No reference data in this area. "
- pass
- else:
- self.result.value = float(
- mean(
- [self.area_osm / v for v in self.area_references.values() if v != 0]
- )
+ for key in self.data_ref.keys():
+ # if None in (self.ratio[key], self.area_cov[key], self.data_ref[key]):
+ if self.check_major_edge_cases(key):
+ continue
+
+ self.result.description += self.check_minor_edge_cases(key)
+ # TODO: check for None explicitly?
+ # TODO: add warning for user, that no buildings are present?
+ try:
+ self.ratio[key] = self.area_osm[key] / self.area_ref[key]
+ except ZeroDivisionError:
+ self.ratio[key] = 0.0
+
+ template = Template(self.metadata.result_description)
+ self.result.description += template.substitute(
+ ratio=round(self.ratio[key] * 100, 2),
+ coverage=round(self.area_cov[key] * 100, 2),
+ dataset=self.data_ref[key]["name"],
)
- if self.result.value is None:
- return
- elif self.above_one_th >= self.result.value >= self.th_high:
- self.result.class_ = 5
- elif self.th_high > self.result.value >= self.th_low:
- self.result.class_ = 3
- elif self.th_low > self.result.value >= 0:
- self.result.class_ = 1
- elif self.result.value > self.above_one_th:
- # TODO: move this to edge_case functions
+ ratios = [v for v in self.ratio.values() if v is not None]
+ ratios = [v for v in ratios if v <= self.above_one_th]
+ if ratios:
+ self.result.value = float(mean(ratios))
+ else:
self.result.description += (
- "Warning: Because of a big difference between OSM and the reference "
- + "data no quality estimation has been made. "
- + "It could be that the reference data is outdated. "
+ "Warning: OSM has substantivly more buildings mapped than the Reference"
+ + " datasets. No quality estimation has been made."
)
- template = Template(self.metadata.result_description)
- self.result.description += template.substitute(
- ratio=round(self.result.value * 100, 2),
- coverage=round(self.coverage["EUBUCCO"] * 100, 2),
- )
+ if self.result.value is not None:
+ if self.above_one_th >= self.result.value >= self.th_high:
+ self.result.class_ = 5
+ elif self.th_high > self.result.value >= self.th_low:
+ self.result.class_ = 3
+ elif self.th_low > self.result.value >= 0:
+ self.result.class_ = 1
+
label_description = self.metadata.label_description[self.result.label]
self.result.description += "\n" + label_description
def create_figure(self) -> None:
- if self.result.label == "undefined" and self.check_major_edge_cases():
+ edge_cases = [self.check_major_edge_cases(k) for k in self.data_ref.keys()]
+ if self.result.label == "undefined" and all(edge_cases):
logging.info(
- "Result is undefined and major edge case is present. "
- + "Skipping figure creation."
+ "Result is undefined and major edge case is present."
+ " Skipping figure creation."
)
return
- fig = pgo.Figure()
- fig.add_trace(
- pgo.Bar(
- name="OSM",
- x=["OSM" + f" ({self.result.timestamp_osm:%b %d, %Y})"],
- y=[round(self.area_osm, 2)],
- marker_color=Color.GREEN.value,
- )
- )
- for name, area in self.area_references.items():
- fig.add_trace(
+
+ ref_data = []
+ ref_x = []
+ ref_y = []
+ osm_x = []
+ osm_y = []
+ ref_hover = []
+ osm_hover = []
+ ref_color = []
+ osm_area = []
+ ref_area = []
+ for key, dataset in self.data_ref.items():
+ if None in (self.area_ref[key], self.area_osm[key]):
+ continue
+ ref_x.append(dataset["name"])
+ ref_y.append(round(self.area_ref[key], 2))
+ ref_data.append(dataset)
+ osm_x.append(dataset["name"])
+ osm_y.append(round(self.area_osm[key], 2))
+ ref_hover.append(f"{dataset['name']} ({dataset['date']})")
+ osm_hover.append(f"OSM ({self.result.timestamp_osm:%b %d, %Y})")
+ ref_color.append(Color[dataset["color"]].value)
+ osm_area.append(round(self.area_osm[key], 2))
+ ref_area.append(round(self.area_ref[key], 2))
+
+ fig = pgo.Figure(
+ data=[
pgo.Bar(
- name=name,
- x=[
- f"{name} ({load_source_data(name)['date']})"
- if load_source_data(name)["date"] is not None
- else name
- ],
- y=[round(area, 2)],
- marker_color=Color.PURPLE.value,
- )
+ name="OSM building area"
+ + " ("
+ + "km², ".join(map(str, osm_area))
+ + "km²)",
+ x=osm_x,
+ y=osm_y,
+ marker_color=Color.GREY.value,
+ hovertext=osm_hover,
+ hoverinfo="text",
+ ),
+ pgo.Bar(
+ name=ref_x[0] + f" ({ref_area[0]} km²)",
+ x=ref_x,
+ y=ref_y,
+ marker_color=ref_color,
+ hovertext=ref_hover,
+ hoverinfo="text",
+ legendgroup="Reference",
+ ),
+ ]
+ )
+
+ # Put every reference dataset to legend by adding transparent shapes
+ for i, dataset in enumerate(list(self.data_ref.values())[1:]):
+ fig.add_shape(
+ name=dataset["name"] + f" ({ref_area[i+1]} km²)",
+ legendgroup="Reference",
+ showlegend=True,
+ type="rect",
+ layer="below",
+ line=dict(width=0),
+ fillcolor=Color[dataset["color"]].value,
+ x0=0,
+ y0=0,
+ x1=0,
+ y1=0,
)
- fig.update_layout(title_text=("Building Comparison"), showlegend=True)
- fig.update_yaxes(title_text="Building Area [km²]")
- fig.update_xaxes(
- title_text="Reference Datasets ("
- + get_sources(self.area_references.keys())
- + ")"
- )
+ layout = {
+ "title_text": "Building Comparison",
+ "showlegend": True,
+ "barmode": "group",
+ "yaxis_title": "Building Area [km²]",
+ "xaxis_title": f"Reference Datasets ({self.format_sources()})",
+ }
+ fig.update_layout(**layout)
+
raw = fig.to_dict()
raw["layout"].pop("template") # remove boilerplate
self.result.figure = raw
- def check_major_edge_cases(self) -> str:
+ def check_major_edge_cases(self, dataset: str) -> str:
"""If edge case is present return description if not return empty string."""
- coverage = self.coverage["EUBUCCO"]
+ coverage = self.area_cov[dataset]
if coverage is None or coverage == 0.00:
- return "Reference dataset does not cover area-of-interest."
+ return f"Reference dataset {dataset} does not cover area-of-interest. "
elif coverage < 0.10:
return (
"Only {:.2f}% of the area-of-interest is covered ".format(
coverage * 100
)
- + "by the reference dataset (EUBUCCO). "
- + "No quality estimation is possible."
+ + f"by the reference dataset ({dataset}). "
+ + f"No quality estimation with reference {dataset} is possible."
)
else:
return ""
- def check_minor_edge_cases(self) -> str:
+ def check_minor_edge_cases(self, dataset: str) -> str:
"""If edge case is present return description if not return empty string."""
- coverage = self.coverage["EUBUCCO"]
+ coverage = self.area_cov[dataset]
if coverage < 0.95:
return (
- "Warning: Reference data does not cover the whole input geometry. "
- + "Input geometry is clipped to the coverage. Result is only calculated"
+ f"Warning: Reference data {dataset} does "
+ f"not cover the whole input geometry. "
+ + "Input geometry is clipped to the coverage."
+ " Result is only calculated"
" for the intersection area. "
)
else:
return ""
+ def format_sources(self):
+ sources = []
+ for dataset in self.data_ref.values():
+ if dataset["link"] is not None:
+ sources.append(f"" f"{dataset['name']}")
+ else:
+ sources.append(f"{dataset}")
+ result = ", ".join(sources)
+ return result
+
@alru_cache
-async def get_eubucco_building_area(bpoly: str) -> float:
+async def get_reference_building_area(feature: Feature, table_name: str) -> float:
"""Get the building area for a AoI from the EUBUCCO dataset."""
# TODO: https://github.com/GIScience/ohsome-quality-api/issues/746
- bpoly = geojson.loads(bpoly)
file_path = os.path.join(db_client.WORKING_DIR, "select_building_area.sql")
with open(file_path, "r") as file:
query = file.read()
- geom = str(bpoly.geometry)
dns = "postgres://{user}:{password}@{host}:{port}/{database}".format(
host=get_config_value("postgres_host"),
port=get_config_value("postgres_port"),
@@ -203,31 +292,17 @@ async def get_eubucco_building_area(bpoly: str) -> float:
user=get_config_value("postgres_user"),
password=get_config_value("postgres_password"),
)
+ table_name = table_name.replace(" ", "_")
+ geom = geojson.dumps(feature.geometry)
async with await psycopg.AsyncConnection.connect(dns) as con:
async with con.cursor() as cur:
- await cur.execute(query, (geom,))
+ await cur.execute(query.format(table_name=table_name), (geom,))
res = await cur.fetchone()
return res[0] or 0.0
-def get_sources(reference_datasets):
- sources = ""
- for dataset in reference_datasets:
- source_metadata = load_source_data(dataset)
- if source_metadata["link"] is not None:
- sources += f"{dataset}"
- else:
- sources += f"{dataset}"
- return sources
-
-
-def load_source_data(reference_dataset) -> dict:
- file_path = os.path.join(os.path.dirname(__file__), "sources.yaml")
-
+@cache
+def load_datasets_metadata() -> dict:
+ file_path = os.path.join(os.path.dirname(__file__), "datasets.yaml")
with open(file_path, "r") as f:
- raw = yaml.safe_load(f)
-
- link = raw.get(reference_dataset, {}).get("link")
- date = raw.get(reference_dataset, {}).get("date")
-
- return {"link": link, "date": date}
+ return yaml.safe_load(f)
diff --git a/ohsome_quality_api/indicators/building_comparison/metadata.yaml b/ohsome_quality_api/indicators/building_comparison/metadata.yaml
index 4ca475214..0b2a03de1 100644
--- a/ohsome_quality_api/indicators/building_comparison/metadata.yaml
+++ b/ohsome_quality_api/indicators/building_comparison/metadata.yaml
@@ -18,5 +18,5 @@ building-comparison:
undefined: >-
Comparison could not be made.
result_description: >-
- $coverage% of the area-of-interest is covered by the reference dataset.
- The building area of OSM is $ratio% of that of the reference data.
+ $coverage% of the area-of-interest is covered by the reference dataset $dataset.
+ The building area of OSM is $ratio% of that reference data.
diff --git a/ohsome_quality_api/indicators/building_comparison/sources.yaml b/ohsome_quality_api/indicators/building_comparison/sources.yaml
deleted file mode 100644
index 7d7c873b4..000000000
--- a/ohsome_quality_api/indicators/building_comparison/sources.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-# set source link and publishing date of compare datasets
-EUBUCCO:
- link: https://docs.eubucco.com
- date: Nov 3, 2022
\ No newline at end of file
diff --git a/ohsome_quality_api/indicators/definitions.py b/ohsome_quality_api/indicators/definitions.py
index 7b5679805..3856f81a7 100644
--- a/ohsome_quality_api/indicators/definitions.py
+++ b/ohsome_quality_api/indicators/definitions.py
@@ -1,6 +1,6 @@
from enum import Enum
-from geojson import Feature, FeatureCollection
+from geojson import FeatureCollection
from ohsome_quality_api.definitions import load_metadata
from ohsome_quality_api.indicators.models import IndicatorMetadata
@@ -29,9 +29,8 @@ def get_valid_indicators(topic_key: str) -> tuple:
async def get_coverage(indicator_key: str, inverse: bool = False) -> FeatureCollection:
indicator_class = get_class_from_key(class_type="indicator", key=indicator_key)
- geometry = await indicator_class.coverage(inverse)
- feature = Feature(geometry=geometry, properties={})
- return FeatureCollection(features=[feature])
+ features = await indicator_class.coverage(inverse)
+ return FeatureCollection(features=features)
IndicatorEnum = Enum("IndicatorEnum", {name: name for name in get_indicator_keys()})
diff --git a/pyproject.toml b/pyproject.toml
index 849e7d8ac..63835bc4c 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -81,3 +81,4 @@ select = [
[tool.pytest.ini_options]
testpaths = ["tests"]
+filterwarnings = ["ignore::DeprecationWarning"]
diff --git a/tests/integrationtests/fixtures/vcr_cassettes/indicators/test_building_comparison.yaml b/tests/integrationtests/fixtures/vcr_cassettes/indicators/test_building_comparison.yaml
index a7a18e284..57d264a6e 100644
--- a/tests/integrationtests/fixtures/vcr_cassettes/indicators/test_building_comparison.yaml
+++ b/tests/integrationtests/fixtures/vcr_cassettes/indicators/test_building_comparison.yaml
@@ -1,61 +1,4 @@
interactions:
-- request:
- body: filter=building%3D%2A+and+building%21%3Dno+and+geometry%3Apolygon&bpolys=%7B%22type%22%3A+%22FeatureCollection%22%2C+%22features%22%3A+%5B%7B%22type%22%3A+%22Feature%22%2C+%22geometry%22%3A+%7B%22type%22%3A+%22Polygon%22%2C+%22coordinates%22%3A+%5B%5B%5B8.573179%2C+49.4236%5D%2C+%5B8.573244%2C+49.423266%5D%2C+%5B8.573517%2C+49.421746%5D%2C+%5B8.573602%2C+49.421029%5D%2C+%5B8.57363%2C+49.420766%5D%2C+%5B8.573618%2C+49.420478%5D%2C+%5B8.573575%2C+49.420208%5D%2C+%5B8.573487%2C+49.419852%5D%2C+%5B8.573253%2C+49.419103%5D%2C+%5B8.57328%2C+49.418634%5D%2C+%5B8.573262%2C+49.41846%5D%2C+%5B8.573244%2C+49.418239%5D%2C+%5B8.573233%2C+49.418026%5D%2C+%5B8.573211%2C+49.417562%5D%2C+%5B8.573206%2C+49.417217%5D%2C+%5B8.573223%2C+49.416902%5D%2C+%5B8.573288%2C+49.416518%5D%2C+%5B8.57343%2C+49.415763%5D%2C+%5B8.573622%2C+49.415734%5D%2C+%5B8.57398%2C+49.414723%5D%2C+%5B8.574098%2C+49.414422%5D%2C+%5B8.574905%2C+49.412659%5D%2C+%5B8.575126%2C+49.41262%5D%2C+%5B8.575952%2C+49.412479%5D%2C+%5B8.576355%2C+49.412403%5D%2C+%5B8.576806%2C+49.412309%5D%2C+%5B8.577418%2C+49.412162%5D%2C+%5B8.578871%2C+49.411816%5D%2C+%5B8.580327%2C+49.411477%5D%2C+%5B8.580548%2C+49.411425%5D%2C+%5B8.581021%2C+49.411314%5D%2C+%5B8.581467%2C+49.411198%5D%2C+%5B8.582126%2C+49.411021%5D%2C+%5B8.58281%2C+49.410831%5D%2C+%5B8.583621%2C+49.410604%5D%2C+%5B8.584256%2C+49.41041%5D%2C+%5B8.584461%2C+49.410598%5D%2C+%5B8.584601%2C+49.41074%5D%2C+%5B8.58466%2C+49.410809%5D%2C+%5B8.584729%2C+49.410896%5D%2C+%5B8.584841%2C+49.411043%5D%2C+%5B8.584893%2C+49.411041%5D%2C+%5B8.590664%2C+49.410551%5D%2C+%5B8.592504%2C+49.410392%5D%2C+%5B8.59249%2C+49.410325%5D%2C+%5B8.592557%2C+49.410316%5D%2C+%5B8.592992%2C+49.410285%5D%2C+%5B8.594295%2C+49.410194%5D%2C+%5B8.595027%2C+49.410131%5D%2C+%5B8.595718%2C+49.41008%5D%2C+%5B8.596457%2C+49.410013%5D%2C+%5B8.597109%2C+49.409948%5D%2C+%5B8.597817%2C+49.409869%5D%2C+%5B8.598479%2C+49.409799%5D%2C+%5B8.59864%2C+49.409784%5D%2C+%5B8.600522%2C+49.409526%5D%2C+%5B8.603393%2C+49.409127%5D%2C+%5B8.60354%2C+49.409104%5D%2C+%5B8.603638%2C+49.409079%5D%2C+%5B8.6052%2C+49.408456%5D%2C+%5B8.608794%2C+49.407045%5D%2C+%5B8.610673%2C+49.405949%5D%2C+%5B8.611461%2C+49.405467%5D%2C+%5B8.612437%2C+49.406203%5D%2C+%5B8.616606%2C+49.407383%5D%2C+%5B8.622553%2C+49.409046%5D%2C+%5B8.622627%2C+49.40901%5D%2C+%5B8.622648%2C+49.408953%5D%2C+%5B8.62272%2C+49.408975%5D%2C+%5B8.622722%2C+49.408976%5D%2C+%5B8.622791%2C+49.409015%5D%2C+%5B8.622851%2C+49.409049%5D%2C+%5B8.623189%2C+49.409236%5D%2C+%5B8.624498%2C+49.409957%5D%2C+%5B8.62459%2C+49.410009%5D%2C+%5B8.625101%2C+49.410294%5D%2C+%5B8.625378%2C+49.410448%5D%2C+%5B8.625911%2C+49.410745%5D%2C+%5B8.626324%2C+49.410975%5D%2C+%5B8.626979%2C+49.411341%5D%2C+%5B8.628263%2C+49.412032%5D%2C+%5B8.62859%2C+49.412213%5D%2C+%5B8.629072%2C+49.412486%5D%2C+%5B8.630034%2C+49.413176%5D%2C+%5B8.630959%2C+49.413833%5D%2C+%5B8.632078%2C+49.414583%5D%2C+%5B8.632707%2C+49.415007%5D%2C+%5B8.632748%2C+49.415035%5D%2C+%5B8.632938%2C+49.414961%5D%2C+%5B8.633025%2C+49.414928%5D%2C+%5B8.633075%2C+49.414807%5D%2C+%5B8.63406%2C+49.412449%5D%2C+%5B8.634446%2C+49.411487%5D%2C+%5B8.634737%2C+49.410763%5D%2C+%5B8.635407%2C+49.409092%5D%2C+%5B8.635873%2C+49.407932%5D%2C+%5B8.636033%2C+49.40753%5D%2C+%5B8.636136%2C+49.407242%5D%2C+%5B8.636215%2C+49.406957%5D%2C+%5B8.636379%2C+49.406391%5D%2C+%5B8.636465%2C+49.406041%5D%2C+%5B8.636591%2C+49.405566%5D%2C+%5B8.636667%2C+49.405073%5D%2C+%5B8.636706%2C+49.404806%5D%2C+%5B8.636743%2C+49.404552%5D%2C+%5B8.636827%2C+49.403969%5D%2C+%5B8.6369%2C+49.403462%5D%2C+%5B8.636926%2C+49.403268%5D%2C+%5B8.637017%2C+49.402596%5D%2C+%5B8.637222%2C+49.401141%5D%2C+%5B8.63755%2C+49.3988%5D%2C+%5B8.638008%2C+49.395648%5D%2C+%5B8.638186%2C+49.393813%5D%2C+%5B8.638295%2C+49.39272%5D%2C+%5B8.638521%2C+49.392746%5D%2C+%5B8.640722%2C+49.393021%5D%2C+%5B8.64343%2C+49.393381%5D%2C+%5B8.643512%2C+49.393194%5D%2C+%5B8.643527%2C+49.39316%5D%2C+%5B8.645535%2C+49.390884%5D%2C+%5B8.64636%2C+49.389866%5D%2C+%5B8.6475%2C+49.388537%5D%2C+%5B8.645357%2C+49.388044%5D%2C+%5B8.643807%2C+49.387609%5D%2C+%5B8.642091%2C+49.387149%5D%2C+%5B8.641038%2C+49.386841%5D%2C+%5B8.639916%2C+49.386498%5D%2C+%5B8.639667%2C+49.386434%5D%2C+%5B8.639387%2C+49.386413%5D%2C+%5B8.638662%2C+49.386411%5D%2C+%5B8.638086%2C+49.386573%5D%2C+%5B8.636604%2C+49.38704%5D%2C+%5B8.634926%2C+49.387313%5D%2C+%5B8.633683%2C+49.387185%5D%2C+%5B8.633598%2C+49.387174%5D%2C+%5B8.633542%2C+49.386897%5D%2C+%5B8.633434%2C+49.386227%5D%2C+%5B8.633401%2C+49.385899%5D%2C+%5B8.633366%2C+49.385891%5D%2C+%5B8.630199%2C+49.385201%5D%2C+%5B8.629858%2C+49.385107%5D%2C+%5B8.629436%2C+49.384945%5D%2C+%5B8.628851%2C+49.384706%5D%2C+%5B8.628366%2C+49.384445%5D%2C+%5B8.627801%2C+49.38413%5D%2C+%5B8.627122%2C+49.383729%5D%2C+%5B8.62646%2C+49.38335%5D%2C+%5B8.625986%2C+49.383068%5D%2C+%5B8.625383%2C+49.382699%5D%2C+%5B8.624878%2C+49.382387%5D%2C+%5B8.624241%2C+49.38199%5D%2C+%5B8.623785%2C+49.381668%5D%2C+%5B8.624382%2C+49.38067%5D%2C+%5B8.621112%2C+49.380011%5D%2C+%5B8.620378%2C+49.379843%5D%2C+%5B8.617932%2C+49.379283%5D%2C+%5B8.616155%2C+49.379158%5D%2C+%5B8.615294%2C+49.378918%5D%2C+%5B8.614545%2C+49.378758%5D%2C+%5B8.613751%2C+49.378528%5D%2C+%5B8.612581%2C+49.378202%5D%2C+%5B8.610866%2C+49.378017%5D%2C+%5B8.610186%2C+49.377919%5D%2C+%5B8.609757%2C+49.37785%5D%2C+%5B8.609403%2C+49.377756%5D%2C+%5B8.609066%2C+49.377649%5D%2C+%5B8.608678%2C+49.377505%5D%2C+%5B8.607916%2C+49.37721%5D%2C+%5B8.607342%2C+49.376972%5D%2C+%5B8.606882%2C+49.376751%5D%2C+%5B8.60681%2C+49.376163%5D%2C+%5B8.607222%2C+49.374986%5D%2C+%5B8.607484%2C+49.37429%5D%2C+%5B8.607333%2C+49.373851%5D%2C+%5B8.606536%2C+49.371886%5D%2C+%5B8.605798%2C+49.370097%5D%2C+%5B8.605168%2C+49.370272%5D%2C+%5B8.60321%2C+49.368377%5D%2C+%5B8.601004%2C+49.366203%5D%2C+%5B8.604393%2C+49.365577%5D%2C+%5B8.604307%2C+49.365419%5D%2C+%5B8.605479%2C+49.365214%5D%2C+%5B8.605885%2C+49.365159%5D%2C+%5B8.607155%2C+49.365004%5D%2C+%5B8.607562%2C+49.364962%5D%2C+%5B8.607787%2C+49.364932%5D%2C+%5B8.608004%2C+49.364857%5D%2C+%5B8.60823%2C+49.364779%5D%2C+%5B8.608521%2C+49.364676%5D%2C+%5B8.608763%2C+49.364589%5D%2C+%5B8.608975%2C+49.364526%5D%2C+%5B8.60924%2C+49.364461%5D%2C+%5B8.609518%2C+49.364418%5D%2C+%5B8.609797%2C+49.364361%5D%2C+%5B8.610128%2C+49.3643%5D%2C+%5B8.610354%2C+49.364251%5D%2C+%5B8.610605%2C+49.364179%5D%2C+%5B8.610995%2C+49.364053%5D%2C+%5B8.611555%2C+49.363849%5D%2C+%5B8.612129%2C+49.363662%5D%2C+%5B8.613637%2C+49.363103%5D%2C+%5B8.615444%2C+49.362414%5D%2C+%5B8.61635%2C+49.362058%5D%2C+%5B8.617043%2C+49.361767%5D%2C+%5B8.617591%2C+49.361529%5D%2C+%5B8.618237%2C+49.361201%5D%2C+%5B8.618957%2C+49.360849%5D%2C+%5B8.619443%2C+49.360653%5D%2C+%5B8.619975%2C+49.360461%5D%2C+%5B8.620625%2C+49.360206%5D%2C+%5B8.621086%2C+49.360044%5D%2C+%5B8.621364%2C+49.359916%5D%2C+%5B8.621823%2C+49.359713%5D%2C+%5B8.622089%2C+49.35959%5D%2C+%5B8.622436%2C+49.35947%5D%2C+%5B8.623627%2C+49.359191%5D%2C+%5B8.624466%2C+49.359063%5D%2C+%5B8.623282%2C+49.35746%5D%2C+%5B8.623019%2C+49.357581%5D%2C+%5B8.621335%2C+49.355497%5D%2C+%5B8.620215%2C+49.354073%5D%2C+%5B8.620484%2C+49.354038%5D%2C+%5B8.620686%2C+49.354007%5D%2C+%5B8.621085%2C+49.353877%5D%2C+%5B8.623323%2C+49.35288%5D%2C+%5B8.625019%2C+49.352119%5D%2C+%5B8.62524%2C+49.35203%5D%2C+%5B8.625625%2C+49.352003%5D%2C+%5B8.627988%2C+49.352082%5D%2C+%5B8.628566%2C+49.352102%5D%2C+%5B8.629102%2C+49.352103%5D%2C+%5B8.629641%2C+49.352094%5D%2C+%5B8.630762%2C+49.352065%5D%2C+%5B8.630787%2C+49.352734%5D%2C+%5B8.631513%2C+49.352774%5D%2C+%5B8.631909%2C+49.352796%5D%2C+%5B8.632002%2C+49.352809%5D%2C+%5B8.632227%2C+49.352816%5D%2C+%5B8.632605%2C+49.35284%5D%2C+%5B8.632903%2C+49.352846%5D%2C+%5B8.633112%2C+49.352836%5D%2C+%5B8.633234%2C+49.352838%5D%2C+%5B8.633289%2C+49.353939%5D%2C+%5B8.633355%2C+49.355012%5D%2C+%5B8.633367%2C+49.355489%5D%2C+%5B8.63355%2C+49.355781%5D%2C+%5B8.633757%2C+49.3561%5D%2C+%5B8.633974%2C+49.356482%5D%2C+%5B8.634167%2C+49.356808%5D%2C+%5B8.634287%2C+49.357126%5D%2C+%5B8.634421%2C+49.357445%5D%2C+%5B8.634503%2C+49.357686%5D%2C+%5B8.634859%2C+49.358095%5D%2C+%5B8.635396%2C+49.358765%5D%2C+%5B8.636103%2C+49.359671%5D%2C+%5B8.636657%2C+49.360357%5D%2C+%5B8.636737%2C+49.360538%5D%2C+%5B8.636888%2C+49.361037%5D%2C+%5B8.637136%2C+49.36199%5D%2C+%5B8.637264%2C+49.362635%5D%2C+%5B8.637304%2C+49.362804%5D%2C+%5B8.637443%2C+49.363191%5D%2C+%5B8.637664%2C+49.36361%5D%2C+%5B8.637986%2C+49.364357%5D%2C+%5B8.638362%2C+49.365323%5D%2C+%5B8.638797%2C+49.36638%5D%2C+%5B8.639105%2C+49.3671%5D%2C+%5B8.639672%2C+49.368535%5D%2C+%5B8.640274%2C+49.369977%5D%2C+%5B8.64095%2C+49.36962%5D%2C+%5B8.642835%2C+49.368655%5D%2C+%5B8.644035%2C+49.369071%5D%2C+%5B8.644716%2C+49.369324%5D%2C+%5B8.644987%2C+49.369459%5D%2C+%5B8.645246%2C+49.369621%5D%2C+%5B8.645609%2C+49.369857%5D%2C+%5B8.645945%2C+49.370086%5D%2C+%5B8.646206%2C+49.370303%5D%2C+%5B8.646365%2C+49.370464%5D%2C+%5B8.647363%2C+49.369711%5D%2C+%5B8.647775%2C+49.369395%5D%2C+%5B8.64813%2C+49.369156%5D%2C+%5B8.648616%2C+49.368856%5D%2C+%5B8.649147%2C+49.368515%5D%2C+%5B8.649775%2C+49.368118%5D%2C+%5B8.650491%2C+49.367685%5D%2C+%5B8.650841%2C+49.367478%5D%2C+%5B8.650529%2C+49.366984%5D%2C+%5B8.650281%2C+49.366573%5D%2C+%5B8.650115%2C+49.36627%5D%2C+%5B8.649942%2C+49.365978%5D%2C+%5B8.651691%2C+49.364976%5D%2C+%5B8.651847%2C+49.365094%5D%2C+%5B8.652197%2C+49.364902%5D%2C+%5B8.652915%2C+49.364549%5D%2C+%5B8.653519%2C+49.364273%5D%2C+%5B8.654112%2C+49.36402%5D%2C+%5B8.654768%2C+49.363737%5D%2C+%5B8.655407%2C+49.363473%5D%2C+%5B8.656377%2C+49.363115%5D%2C+%5B8.657142%2C+49.362813%5D%2C+%5B8.657764%2C+49.363277%5D%2C+%5B8.658185%2C+49.363054%5D%2C+%5B8.658651%2C+49.362837%5D%2C+%5B8.659164%2C+49.362571%5D%2C+%5B8.658051%2C+49.361776%5D%2C+%5B8.657009%2C+49.360179%5D%2C+%5B8.656454%2C+49.35929%5D%2C+%5B8.655814%2C+49.358138%5D%2C+%5B8.655354%2C+49.357298%5D%2C+%5B8.654879%2C+49.356558%5D%2C+%5B8.654787%2C+49.35643%5D%2C+%5B8.654561%2C+49.356112%5D%2C+%5B8.653362%2C+49.356263%5D%2C+%5B8.652987%2C+49.35577%5D%2C+%5B8.652544%2C+49.355287%5D%2C+%5B8.652104%2C+49.35458%5D%2C+%5B8.651277%2C+49.353254%5D%2C+%5B8.651454%2C+49.353204%5D%2C+%5B8.651636%2C+49.353188%5D%2C+%5B8.65183%2C+49.353191%5D%2C+%5B8.652046%2C+49.353203%5D%2C+%5B8.652348%2C+49.353246%5D%2C+%5B8.652615%2C+49.353273%5D%2C+%5B8.652844%2C+49.353279%5D%2C+%5B8.653124%2C+49.353277%5D%2C+%5B8.653474%2C+49.353258%5D%2C+%5B8.653742%2C+49.353245%5D%2C+%5B8.654053%2C+49.353215%5D%2C+%5B8.654541%2C+49.353146%5D%2C+%5B8.655319%2C+49.353021%5D%2C+%5B8.656788%2C+49.352777%5D%2C+%5B8.657594%2C+49.352635%5D%2C+%5B8.657702%2C+49.352622%5D%2C+%5B8.657803%2C+49.352609%5D%2C+%5B8.658004%2C+49.352578%5D%2C+%5B8.658147%2C+49.352565%5D%2C+%5B8.657938%2C+49.35276%5D%2C+%5B8.657306%2C+49.353303%5D%2C+%5B8.657404%2C+49.353355%5D%2C+%5B8.656818%2C+49.353732%5D%2C+%5B8.656362%2C+49.354017%5D%2C+%5B8.656689%2C+49.35436%5D%2C+%5B8.657243%2C+49.355195%5D%2C+%5B8.658874%2C+49.354938%5D%2C+%5B8.660099%2C+49.354864%5D%2C+%5B8.660662%2C+49.354831%5D%2C+%5B8.660554%2C+49.35385%5D%2C+%5B8.661186%2C+49.353988%5D%2C+%5B8.661529%2C+49.354066%5D%2C+%5B8.662499%2C+49.354314%5D%2C+%5B8.663203%2C+49.354396%5D%2C+%5B8.663578%2C+49.353585%5D%2C+%5B8.664184%2C+49.353663%5D%2C+%5B8.665018%2C+49.353769%5D%2C+%5B8.664862%2C+49.354592%5D%2C+%5B8.664516%2C+49.356424%5D%2C+%5B8.664343%2C+49.35714%5D%2C+%5B8.664257%2C+49.357496%5D%2C+%5B8.664523%2C+49.357548%5D%2C+%5B8.664876%2C+49.357593%5D%2C+%5B8.667029%2C+49.35798%5D%2C+%5B8.66801%2C+49.358065%5D%2C+%5B8.668543%2C+49.358111%5D%2C+%5B8.668764%2C+49.358127%5D%2C+%5B8.669807%2C+49.358003%5D%2C+%5B8.671465%2C+49.357805%5D%2C+%5B8.67168%2C+49.357818%5D%2C+%5B8.671905%2C+49.359187%5D%2C+%5B8.672189%2C+49.360595%5D%2C+%5B8.672443%2C+49.361521%5D%2C+%5B8.6742%2C+49.361218%5D%2C+%5B8.675834%2C+49.360668%5D%2C+%5B8.675955%2C+49.360221%5D%2C+%5B8.677248%2C+49.360356%5D%2C+%5B8.678227%2C+49.360428%5D%2C+%5B8.67875%2C+49.360442%5D%2C+%5B8.679817%2C+49.360427%5D%2C+%5B8.679921%2C+49.360425%5D%2C+%5B8.682084%2C+49.360389%5D%2C+%5B8.682014%2C+49.359907%5D%2C+%5B8.684247%2C+49.359817%5D%2C+%5B8.684378%2C+49.359781%5D%2C+%5B8.68706%2C+49.359824%5D%2C+%5B8.687067%2C+49.35976%5D%2C+%5B8.687186%2C+49.359138%5D%2C+%5B8.687237%2C+49.35886%5D%2C+%5B8.689029%2C+49.3589%5D%2C+%5B8.689213%2C+49.358942%5D%2C+%5B8.690288%2C+49.358929%5D%2C+%5B8.690684%2C+49.358899%5D%2C+%5B8.691469%2C+49.358787%5D%2C+%5B8.691399%2C+49.358492%5D%2C+%5B8.692384%2C+49.358415%5D%2C+%5B8.692438%2C+49.358513%5D%2C+%5B8.692875%2C+49.358386%5D%2C+%5B8.692904%2C+49.358507%5D%2C+%5B8.693627%2C+49.358371%5D%2C+%5B8.693654%2C+49.35848%5D%2C+%5B8.694136%2C+49.358357%5D%2C+%5B8.694369%2C+49.358679%5D%2C+%5B8.69466%2C+49.358603%5D%2C+%5B8.694621%2C+49.358537%5D%2C+%5B8.694444%2C+49.358239%5D%2C+%5B8.6964%2C+49.357749%5D%2C+%5B8.696686%2C+49.357789%5D%2C+%5B8.696953%2C+49.358039%5D%2C+%5B8.698234%2C+49.357421%5D%2C+%5B8.699042%2C+49.357005%5D%2C+%5B8.699133%2C+49.357005%5D%2C+%5B8.699224%2C+49.357003%5D%2C+%5B8.699468%2C+49.356867%5D%2C+%5B8.70005%2C+49.356571%5D%2C+%5B8.700092%2C+49.35655%5D%2C+%5B8.700541%2C+49.356327%5D%2C+%5B8.701206%2C+49.356063%5D%2C+%5B8.701769%2C+49.355846%5D%2C+%5B8.701847%2C+49.355815%5D%2C+%5B8.70249%2C+49.355716%5D%2C+%5B8.703321%2C+49.355722%5D%2C+%5B8.703979%2C+49.355745%5D%2C+%5B8.704667%2C+49.355786%5D%2C+%5B8.705234%2C+49.355848%5D%2C+%5B8.705404%2C+49.355871%5D%2C+%5B8.705776%2C+49.35592%5D%2C+%5B8.706353%2C+49.356042%5D%2C+%5B8.706882%2C+49.356123%5D%2C+%5B8.708303%2C+49.356341%5D%2C+%5B8.70964%2C+49.35658%5D%2C+%5B8.71027%2C+49.355542%5D%2C+%5B8.710889%2C+49.35511%5D%2C+%5B8.711249%2C+49.35521%5D%2C+%5B8.7114%2C+49.35534%5D%2C+%5B8.711683%2C+49.355525%5D%2C+%5B8.711946%2C+49.355618%5D%2C+%5B8.712513%2C+49.355659%5D%2C+%5B8.71339%2C+49.355695%5D%2C+%5B8.71423%2C+49.355746%5D%2C+%5B8.715084%2C+49.355951%5D%2C+%5B8.715987%2C+49.35624%5D%2C+%5B8.716396%2C+49.356342%5D%2C+%5B8.718652%2C+49.356379%5D%2C+%5B8.71896%2C+49.356351%5D%2C+%5B8.719342%2C+49.356762%5D%2C+%5B8.719472%2C+49.357065%5D%2C+%5B8.71971%2C+49.357302%5D%2C+%5B8.720122%2C+49.357284%5D%2C+%5B8.721267%2C+49.357192%5D%2C+%5B8.721461%2C+49.357173%5D%2C+%5B8.722389%2C+49.357253%5D%2C+%5B8.723668%2C+49.357439%5D%2C+%5B8.724196%2C+49.357602%5D%2C+%5B8.724937%2C+49.357921%5D%2C+%5B8.72524%2C+49.358308%5D%2C+%5B8.725498%2C+49.358663%5D%2C+%5B8.725599%2C+49.358803%5D%2C+%5B8.726016%2C+49.359476%5D%2C+%5B8.726055%2C+49.360045%5D%2C+%5B8.726094%2C+49.360374%5D%2C+%5B8.727113%2C+49.361989%5D%2C+%5B8.727202%2C+49.362889%5D%2C+%5B8.727423%2C+49.364132%5D%2C+%5B8.727717%2C+49.365509%5D%2C+%5B8.728446%2C+49.366441%5D%2C+%5B8.728671%2C+49.366705%5D%2C+%5B8.728942%2C+49.366897%5D%2C+%5B8.730404%2C+49.367933%5D%2C+%5B8.729929%2C+49.368208%5D%2C+%5B8.728541%2C+49.368817%5D%2C+%5B8.72836%2C+49.368682%5D%2C+%5B8.726259%2C+49.369455%5D%2C+%5B8.725357%2C+49.370066%5D%2C+%5B8.725576%2C+49.37022%5D%2C+%5B8.725009%2C+49.371211%5D%2C+%5B8.724729%2C+49.37225%5D%2C+%5B8.724401%2C+49.373496%5D%2C+%5B8.724479%2C+49.373747%5D%2C+%5B8.724841%2C+49.373956%5D%2C+%5B8.727404%2C+49.375554%5D%2C+%5B8.72822%2C+49.374821%5D%2C+%5B8.729138%2C+49.374009%5D%2C+%5B8.730155%2C+49.373179%5D%2C+%5B8.730385%2C+49.373252%5D%2C+%5B8.730507%2C+49.373311%5D%2C+%5B8.731437%2C+49.372716%5D%2C+%5B8.732328%2C+49.372224%5D%2C+%5B8.733929%2C+49.372675%5D%2C+%5B8.735724%2C+49.372956%5D%2C+%5B8.736319%2C+49.373324%5D%2C+%5B8.737564%2C+49.374161%5D%2C+%5B8.738416%2C+49.374491%5D%2C+%5B8.740049%2C+49.374553%5D%2C+%5B8.740729%2C+49.374442%5D%2C+%5B8.741468%2C+49.373924%5D%2C+%5B8.742963%2C+49.373108%5D%2C+%5B8.744141%2C+49.372795%5D%2C+%5B8.745571%2C+49.37295%5D%2C+%5B8.746882%2C+49.373148%5D%2C+%5B8.747531%2C+49.373299%5D%2C+%5B8.747803%2C+49.373403%5D%2C+%5B8.74801%2C+49.373481%5D%2C+%5B8.749031%2C+49.373788%5D%2C+%5B8.749349%2C+49.373809%5D%2C+%5B8.749506%2C+49.373874%5D%2C+%5B8.749682%2C+49.374157%5D%2C+%5B8.749784%2C+49.374269%5D%2C+%5B8.749979%2C+49.37486%5D%2C+%5B8.750254%2C+49.375234%5D%2C+%5B8.750486%2C+49.375439%5D%2C+%5B8.751287%2C+49.375853%5D%2C+%5B8.751986%2C+49.376167%5D%2C+%5B8.752481%2C+49.376371%5D%2C+%5B8.75318%2C+49.376893%5D%2C+%5B8.753542%2C+49.377091%5D%2C+%5B8.754226%2C+49.377357%5D%2C+%5B8.754767%2C+49.377572%5D%2C+%5B8.754718%2C+49.377723%5D%2C+%5B8.754876%2C+49.377766%5D%2C+%5B8.75543%2C+49.377841%5D%2C+%5B8.756198%2C+49.37791%5D%2C+%5B8.756906%2C+49.377922%5D%2C+%5B8.75795%2C+49.377906%5D%2C+%5B8.758486%2C+49.377899%5D%2C+%5B8.758903%2C+49.377943%5D%2C+%5B8.759138%2C+49.377807%5D%2C+%5B8.759187%2C+49.377808%5D%2C+%5B8.759786%2C+49.377905%5D%2C+%5B8.760544%2C+49.378024%5D%2C+%5B8.762615%2C+49.378444%5D%2C+%5B8.763084%2C+49.378532%5D%2C+%5B8.763661%2C+49.378542%5D%2C+%5B8.76537%2C+49.378518%5D%2C+%5B8.766125%2C+49.378539%5D%2C+%5B8.766754%2C+49.378608%5D%2C+%5B8.76849%2C+49.379027%5D%2C+%5B8.76883%2C+49.379193%5D%2C+%5B8.768381%2C+49.379612%5D%2C+%5B8.767516%2C+49.380685%5D%2C+%5B8.766845%2C+49.381341%5D%2C+%5B8.766279%2C+49.382016%5D%2C+%5B8.765944%2C+49.3827%5D%2C+%5B8.76528%2C+49.383389%5D%2C+%5B8.764256%2C+49.384184%5D%2C+%5B8.763735%2C+49.384783%5D%2C+%5B8.76338%2C+49.385218%5D%2C+%5B8.763158%2C+49.385451%5D%2C+%5B8.762978%2C+49.385762%5D%2C+%5B8.762909%2C+49.385993%5D%2C+%5B8.762887%2C+49.386438%5D%2C+%5B8.762991%2C+49.386902%5D%2C+%5B8.762978%2C+49.387249%5D%2C+%5B8.762899%2C+49.387516%5D%2C+%5B8.763192%2C+49.387952%5D%2C+%5B8.764231%2C+49.387498%5D%2C+%5B8.766654%2C+49.387178%5D%2C+%5B8.767235%2C+49.387062%5D%2C+%5B8.767759%2C+49.386865%5D%2C+%5B8.768178%2C+49.386789%5D%2C+%5B8.768518%2C+49.386845%5D%2C+%5B8.768945%2C+49.386974%5D%2C+%5B8.76931%2C+49.387141%5D%2C+%5B8.769787%2C+49.387254%5D%2C+%5B8.770146%2C+49.387651%5D%2C+%5B8.771331%2C+49.388121%5D%2C+%5B8.771843%2C+49.388408%5D%2C+%5B8.772677%2C+49.388667%5D%2C+%5B8.772941%2C+49.388877%5D%2C+%5B8.773016%2C+49.389213%5D%2C+%5B8.773661%2C+49.389392%5D%2C+%5B8.773463%2C+49.389673%5D%2C+%5B8.773409%2C+49.390055%5D%2C+%5B8.77366%2C+49.390523%5D%2C+%5B8.773878%2C+49.390825%5D%2C+%5B8.774229%2C+49.390979%5D%2C+%5B8.774594%2C+49.391209%5D%2C+%5B8.775114%2C+49.391654%5D%2C+%5B8.775375%2C+49.392035%5D%2C+%5B8.775841%2C+49.392457%5D%2C+%5B8.775179%2C+49.393053%5D%2C+%5B8.776011%2C+49.393547%5D%2C+%5B8.776472%2C+49.394054%5D%2C+%5B8.776103%2C+49.394241%5D%2C+%5B8.775839%2C+49.394462%5D%2C+%5B8.775613%2C+49.394778%5D%2C+%5B8.775432%2C+49.39513%5D%2C+%5B8.775357%2C+49.395498%5D%2C+%5B8.775351%2C+49.39589%5D%2C+%5B8.775405%2C+49.396353%5D%2C+%5B8.77561%2C+49.396942%5D%2C+%5B8.775853%2C+49.397499%5D%2C+%5B8.77627%2C+49.398226%5D%2C+%5B8.776723%2C+49.39895%5D%2C+%5B8.777297%2C+49.399896%5D%2C+%5B8.777925%2C+49.401157%5D%2C+%5B8.778345%2C+49.40224%5D%2C+%5B8.779285%2C+49.402018%5D%2C+%5B8.78048%2C+49.4018%5D%2C+%5B8.781842%2C+49.401604%5D%2C+%5B8.783078%2C+49.401452%5D%2C+%5B8.783982%2C+49.401369%5D%2C+%5B8.784682%2C+49.401329%5D%2C+%5B8.785426%2C+49.40138%5D%2C+%5B8.78645%2C+49.401532%5D%2C+%5B8.787479%2C+49.40178%5D%2C+%5B8.789244%2C+49.402355%5D%2C+%5B8.790122%2C+49.40271%5D%2C+%5B8.7907%2C+49.403068%5D%2C+%5B8.791436%2C+49.403734%5D%2C+%5B8.792046%2C+49.404237%5D%2C+%5B8.792756%2C+49.404675%5D%2C+%5B8.793315%2C+49.405004%5D%2C+%5B8.793591%2C+49.405187%5D%2C+%5B8.793708%2C+49.405634%5D%2C+%5B8.793657%2C+49.406063%5D%2C+%5B8.793701%2C+49.40635%5D%2C+%5B8.793964%2C+49.406931%5D%2C+%5B8.79405%2C+49.40719%5D%2C+%5B8.793454%2C+49.408909%5D%2C+%5B8.79312%2C+49.409948%5D%2C+%5B8.793072%2C+49.410423%5D%2C+%5B8.792942%2C+49.411043%5D%2C+%5B8.792821%2C+49.411647%5D%2C+%5B8.792762%2C+49.411853%5D%2C+%5B8.792359%2C+49.412349%5D%2C+%5B8.790377%2C+49.414782%5D%2C+%5B8.790199%2C+49.414964%5D%2C+%5B8.790132%2C+49.415286%5D%2C+%5B8.789943%2C+49.416379%5D%2C+%5B8.78948%2C+49.417608%5D%2C+%5B8.789429%2C+49.418818%5D%2C+%5B8.789394%2C+49.419256%5D%2C+%5B8.789554%2C+49.419831%5D%2C+%5B8.789819%2C+49.420577%5D%2C+%5B8.789964%2C+49.421041%5D%2C+%5B8.790162%2C+49.421213%5D%2C+%5B8.791171%2C+49.42288%5D%2C+%5B8.791273%2C+49.423259%5D%2C+%5B8.790903%2C+49.424051%5D%2C+%5B8.789978%2C+49.425944%5D%2C+%5B8.789643%2C+49.42708%5D%2C+%5B8.78907%2C+49.430067%5D%2C+%5B8.78834%2C+49.431146%5D%2C+%5B8.786537%2C+49.432578%5D%2C+%5B8.779296%2C+49.432764%5D%2C+%5B8.777773%2C+49.432907%5D%2C+%5B8.777268%2C+49.433012%5D%2C+%5B8.776973%2C+49.433155%5D%2C+%5B8.776765%2C+49.433357%5D%2C+%5B8.775986%2C+49.434071%5D%2C+%5B8.774992%2C+49.43454%5D%2C+%5B8.774022%2C+49.434993%5D%2C+%5B8.773641%2C+49.435318%5D%2C+%5B8.773252%2C+49.435419%5D%2C+%5B8.772923%2C+49.435463%5D%2C+%5B8.77217%2C+49.435536%5D%2C+%5B8.77045%2C+49.435737%5D%2C+%5B8.769482%2C+49.436046%5D%2C+%5B8.766398%2C+49.437365%5D%2C+%5B8.766515%2C+49.440274%5D%2C+%5B8.766223%2C+49.440275%5D%2C+%5B8.76637%2C+49.441863%5D%2C+%5B8.766334%2C+49.443584%5D%2C+%5B8.764728%2C+49.446047%5D%2C+%5B8.761766%2C+49.448135%5D%2C+%5B8.761703%2C+49.450618%5D%2C+%5B8.761818%2C+49.450806%5D%2C+%5B8.762051%2C+49.450947%5D%2C+%5B8.763169%2C+49.451433%5D%2C+%5B8.764276%2C+49.451893%5D%2C+%5B8.765277%2C+49.452469%5D%2C+%5B8.766319%2C+49.453103%5D%2C+%5B8.767107%2C+49.453699%5D%2C+%5B8.767706%2C+49.454192%5D%2C+%5B8.765332%2C+49.455547%5D%2C+%5B8.763575%2C+49.456368%5D%2C+%5B8.76329%2C+49.456467%5D%2C+%5B8.762939%2C+49.456488%5D%2C+%5B8.76055%2C+49.456573%5D%2C+%5B8.758634%2C+49.456662%5D%2C+%5B8.757555%2C+49.456702%5D%2C+%5B8.757041%2C+49.457473%5D%2C+%5B8.756618%2C+49.457934%5D%2C+%5B8.756062%2C+49.458405%5D%2C+%5B8.755408%2C+49.458854%5D%2C+%5B8.754686%2C+49.459468%5D%2C+%5B8.754705%2C+49.459642%5D%2C+%5B8.753986%2C+49.459693%5D%2C+%5B8.753099%2C+49.459548%5D%2C+%5B8.75158%2C+49.459204%5D%2C+%5B8.750438%2C+49.458958%5D%2C+%5B8.750091%2C+49.459072%5D%2C+%5B8.748992%2C+49.459252%5D%2C+%5B8.747833%2C+49.459441%5D%2C+%5B8.746352%2C+49.459567%5D%2C+%5B8.74547%2C+49.459614%5D%2C+%5B8.745235%2C+49.459571%5D%2C+%5B8.744884%2C+49.459434%5D%2C+%5B8.744315%2C+49.459159%5D%2C+%5B8.743336%2C+49.458648%5D%2C+%5B8.74322%2C+49.458497%5D%2C+%5B8.74324%2C+49.458378%5D%2C+%5B8.743121%2C+49.458305%5D%2C+%5B8.742643%2C+49.45808%5D%2C+%5B8.741969%2C+49.45777%5D%2C+%5B8.741674%2C+49.457558%5D%2C+%5B8.741746%2C+49.457041%5D%2C+%5B8.741807%2C+49.456563%5D%2C+%5B8.741842%2C+49.456478%5D%2C+%5B8.742048%2C+49.4564%5D%2C+%5B8.74257%2C+49.456328%5D%2C+%5B8.74305%2C+49.456335%5D%2C+%5B8.743558%2C+49.456352%5D%2C+%5B8.744051%2C+49.456283%5D%2C+%5B8.744436%2C+49.456168%5D%2C+%5B8.744628%2C+49.456101%5D%2C+%5B8.744776%2C+49.456069%5D%2C+%5B8.744954%2C+49.456089%5D%2C+%5B8.745101%2C+49.456082%5D%2C+%5B8.745388%2C+49.455974%5D%2C+%5B8.745895%2C+49.455754%5D%2C+%5B8.746052%2C+49.455642%5D%2C+%5B8.746083%2C+49.455363%5D%2C+%5B8.746078%2C+49.455054%5D%2C+%5B8.746063%2C+49.454896%5D%2C+%5B8.745975%2C+49.454771%5D%2C+%5B8.745912%2C+49.454691%5D%2C+%5B8.745943%2C+49.454522%5D%2C+%5B8.746025%2C+49.45416%5D%2C+%5B8.746118%2C+49.453701%5D%2C+%5B8.746201%2C+49.453499%5D%2C+%5B8.746235%2C+49.453234%5D%2C+%5B8.745966%2C+49.452626%5D%2C+%5B8.745586%2C+49.451991%5D%2C+%5B8.744871%2C+49.451023%5D%2C+%5B8.744719%2C+49.450685%5D%2C+%5B8.744556%2C+49.450429%5D%2C+%5B8.744724%2C+49.450278%5D%2C+%5B8.74472%2C+49.450033%5D%2C+%5B8.744778%2C+49.449761%5D%2C+%5B8.745026%2C+49.449477%5D%2C+%5B8.745437%2C+49.449085%5D%2C+%5B8.745681%2C+49.448824%5D%2C+%5B8.745748%2C+49.448674%5D%2C+%5B8.745808%2C+49.448379%5D%2C+%5B8.745854%2C+49.448142%5D%2C+%5B8.745742%2C+49.447418%5D%2C+%5B8.7457%2C+49.446891%5D%2C+%5B8.739206%2C+49.446386%5D%2C+%5B8.739212%2C+49.44694%5D%2C+%5B8.738431%2C+49.448017%5D%2C+%5B8.738008%2C+49.448423%5D%2C+%5B8.737318%2C+49.44906%5D%2C+%5B8.737083%2C+49.449171%5D%2C+%5B8.736852%2C+49.449237%5D%2C+%5B8.736541%2C+49.449242%5D%2C+%5B8.735799%2C+49.449127%5D%2C+%5B8.735152%2C+49.448956%5D%2C+%5B8.734623%2C+49.44883%5D%2C+%5B8.732748%2C+49.448569%5D%2C+%5B8.730015%2C+49.448373%5D%2C+%5B8.726439%2C+49.448213%5D%2C+%5B8.725438%2C+49.448206%5D%2C+%5B8.724195%2C+49.448452%5D%2C+%5B8.723635%2C+49.448579%5D%2C+%5B8.722897%2C+49.448821%5D%2C+%5B8.722459%2C+49.449016%5D%2C+%5B8.722077%2C+49.449185%5D%2C+%5B8.721853%2C+49.449345%5D%2C+%5B8.721696%2C+49.449503%5D%2C+%5B8.721441%2C+49.449815%5D%2C+%5B8.721023%2C+49.450238%5D%2C+%5B8.720491%2C+49.450545%5D%2C+%5B8.720086%2C+49.450745%5D%2C+%5B8.719614%2C+49.451065%5D%2C+%5B8.718989%2C+49.451482%5D%2C+%5B8.718324%2C+49.451829%5D%2C+%5B8.717828%2C+49.452039%5D%2C+%5B8.717415%2C+49.452118%5D%2C+%5B8.716995%2C+49.452187%5D%2C+%5B8.716368%2C+49.452291%5D%2C+%5B8.715647%2C+49.452383%5D%2C+%5B8.715174%2C+49.45242%5D%2C+%5B8.714813%2C+49.452338%5D%2C+%5B8.714396%2C+49.452172%5D%2C+%5B8.714027%2C+49.451964%5D%2C+%5B8.713729%2C+49.451763%5D%2C+%5B8.713448%2C+49.451547%5D%2C+%5B8.71308%2C+49.451414%5D%2C+%5B8.712981%2C+49.451337%5D%2C+%5B8.712907%2C+49.451188%5D%2C+%5B8.712618%2C+49.450635%5D%2C+%5B8.712221%2C+49.450263%5D%2C+%5B8.712063%2C+49.450181%5D%2C+%5B8.711923%2C+49.450062%5D%2C+%5B8.711712%2C+49.449848%5D%2C+%5B8.711383%2C+49.449483%5D%2C+%5B8.710697%2C+49.449013%5D%2C+%5B8.709519%2C+49.447725%5D%2C+%5B8.709467%2C+49.447501%5D%2C+%5B8.709412%2C+49.446647%5D%2C+%5B8.709325%2C+49.446198%5D%2C+%5B8.708958%2C+49.446156%5D%2C+%5B8.708062%2C+49.445948%5D%2C+%5B8.707527%2C+49.44589%5D%2C+%5B8.706733%2C+49.445857%5D%2C+%5B8.706043%2C+49.445872%5D%2C+%5B8.705379%2C+49.445924%5D%2C+%5B8.704486%2C+49.446022%5D%2C+%5B8.703989%2C+49.446%5D%2C+%5B8.703226%2C+49.44592%5D%2C+%5B8.702235%2C+49.445819%5D%2C+%5B8.700441%2C+49.445474%5D%2C+%5B8.698009%2C+49.445025%5D%2C+%5B8.696864%2C+49.444866%5D%2C+%5B8.696436%2C+49.444666%5D%2C+%5B8.695967%2C+49.444555%5D%2C+%5B8.695515%2C+49.444586%5D%2C+%5B8.693686%2C+49.444206%5D%2C+%5B8.692734%2C+49.444117%5D%2C+%5B8.692166%2C+49.444018%5D%2C+%5B8.691707%2C+49.443845%5D%2C+%5B8.691244%2C+49.44365%5D%2C+%5B8.690496%2C+49.443236%5D%2C+%5B8.68937%2C+49.443263%5D%2C+%5B8.687857%2C+49.443212%5D%2C+%5B8.687569%2C+49.443035%5D%2C+%5B8.687363%2C+49.443008%5D%2C+%5B8.686799%2C+49.443048%5D%2C+%5B8.686065%2C+49.443213%5D%2C+%5B8.685572%2C+49.443319%5D%2C+%5B8.685446%2C+49.443329%5D%2C+%5B8.68496%2C+49.443355%5D%2C+%5B8.684607%2C+49.44354%5D%2C+%5B8.6843%2C+49.443671%5D%2C+%5B8.683887%2C+49.443768%5D%2C+%5B8.683496%2C+49.443878%5D%2C+%5B8.682964%2C+49.444%5D%2C+%5B8.682677%2C+49.443971%5D%2C+%5B8.682335%2C+49.443862%5D%2C+%5B8.682116%2C+49.443773%5D%2C+%5B8.681657%2C+49.443692%5D%2C+%5B8.681244%2C+49.443675%5D%2C+%5B8.680796%2C+49.443534%5D%2C+%5B8.680393%2C+49.443483%5D%2C+%5B8.67967%2C+49.443133%5D%2C+%5B8.679113%2C+49.44302%5D%2C+%5B8.679192%2C+49.442698%5D%2C+%5B8.678359%2C+49.442592%5D%2C+%5B8.678334%2C+49.442624%5D%2C+%5B8.677207%2C+49.442494%5D%2C+%5B8.677012%2C+49.442391%5D%2C+%5B8.676933%2C+49.442349%5D%2C+%5B8.676097%2C+49.442199%5D%2C+%5B8.675185%2C+49.442035%5D%2C+%5B8.674777%2C+49.441968%5D%2C+%5B8.673293%2C+49.441504%5D%2C+%5B8.672861%2C+49.441253%5D%2C+%5B8.67274%2C+49.441326%5D%2C+%5B8.672341%2C+49.441125%5D%2C+%5B8.671575%2C+49.440834%5D%2C+%5B8.670761%2C+49.441343%5D%2C+%5B8.67033%2C+49.441494%5D%2C+%5B8.669915%2C+49.441467%5D%2C+%5B8.668932%2C+49.441262%5D%2C+%5B8.667104%2C+49.440835%5D%2C+%5B8.666264%2C+49.440772%5D%2C+%5B8.665848%2C+49.44064%5D%2C+%5B8.665677%2C+49.440536%5D%2C+%5B8.665516%2C+49.440349%5D%2C+%5B8.665451%2C+49.4403%5D%2C+%5B8.665403%2C+49.440276%5D%2C+%5B8.665344%2C+49.440267%5D%2C+%5B8.665214%2C+49.440227%5D%2C+%5B8.663494%2C+49.439941%5D%2C+%5B8.663245%2C+49.439948%5D%2C+%5B8.663238%2C+49.439857%5D%2C+%5B8.663046%2C+49.43963%5D%2C+%5B8.662637%2C+49.439686%5D%2C+%5B8.662439%2C+49.439689%5D%2C+%5B8.662374%2C+49.439664%5D%2C+%5B8.661735%2C+49.439538%5D%2C+%5B8.66046%2C+49.439285%5D%2C+%5B8.658385%2C+49.438873%5D%2C+%5B8.658267%2C+49.439039%5D%2C+%5B8.657003%2C+49.438758%5D%2C+%5B8.656308%2C+49.438606%5D%2C+%5B8.65531%2C+49.439943%5D%2C+%5B8.653394%2C+49.439318%5D%2C+%5B8.649054%2C+49.437866%5D%2C+%5B8.648862%2C+49.437785%5D%2C+%5B8.648968%2C+49.437693%5D%2C+%5B8.648204%2C+49.437252%5D%2C+%5B8.647218%2C+49.436878%5D%2C+%5B8.646552%2C+49.436626%5D%2C+%5B8.646193%2C+49.436973%5D%2C+%5B8.646016%2C+49.437132%5D%2C+%5B8.645786%2C+49.437345%5D%2C+%5B8.645488%2C+49.437604%5D%2C+%5B8.645159%2C+49.437851%5D%2C+%5B8.644754%2C+49.438187%5D%2C+%5B8.644168%2C+49.438623%5D%2C+%5B8.643741%2C+49.438944%5D%2C+%5B8.643149%2C+49.439309%5D%2C+%5B8.64261%2C+49.43961%5D%2C+%5B8.642565%2C+49.439635%5D%2C+%5B8.642246%2C+49.439785%5D%2C+%5B8.641292%2C+49.440204%5D%2C+%5B8.64031%2C+49.440607%5D%2C+%5B8.639305%2C+49.44098%5D%2C+%5B8.638212%2C+49.441336%5D%2C+%5B8.637172%2C+49.441631%5D%2C+%5B8.636078%2C+49.441893%5D%2C+%5B8.634983%2C+49.442126%5D%2C+%5B8.633858%2C+49.442342%5D%2C+%5B8.632702%2C+49.442524%5D%2C+%5B8.631601%2C+49.44272%5D%2C+%5B8.630453%2C+49.442879%5D%2C+%5B8.629367%2C+49.443018%5D%2C+%5B8.628703%2C+49.443115%5D%2C+%5B8.628211%2C+49.441976%5D%2C+%5B8.628012%2C+49.44157%5D%2C+%5B8.627351%2C+49.440827%5D%2C+%5B8.626819%2C+49.440265%5D%2C+%5B8.626616%2C+49.440059%5D%2C+%5B8.626743%2C+49.439998%5D%2C+%5B8.626134%2C+49.439394%5D%2C+%5B8.62331%2C+49.436631%5D%2C+%5B8.623037%2C+49.436356%5D%2C+%5B8.622925%2C+49.436225%5D%2C+%5B8.622831%2C+49.436102%5D%2C+%5B8.62272%2C+49.435915%5D%2C+%5B8.622619%2C+49.43575%5D%2C+%5B8.622521%2C+49.435595%5D%2C+%5B8.622406%2C+49.435412%5D%2C+%5B8.622309%2C+49.435279%5D%2C+%5B8.622204%2C+49.435144%5D%2C+%5B8.621395%2C+49.434225%5D%2C+%5B8.621165%2C+49.433964%5D%2C+%5B8.621049%2C+49.433843%5D%2C+%5B8.620927%2C+49.433893%5D%2C+%5B8.619493%2C+49.432264%5D%2C+%5B8.61626%2C+49.428621%5D%2C+%5B8.615974%2C+49.428303%5D%2C+%5B8.61531%2C+49.427884%5D%2C+%5B8.609952%2C+49.424382%5D%2C+%5B8.609733%2C+49.424242%5D%2C+%5B8.605472%2C+49.425826%5D%2C+%5B8.599884%2C+49.427972%5D%2C+%5B8.598382%2C+49.428508%5D%2C+%5B8.59849%2C+49.428044%5D%2C+%5B8.59823%2C+49.428143%5D%2C+%5B8.593259%2C+49.430025%5D%2C+%5B8.592963%2C+49.430133%5D%2C+%5B8.590778%2C+49.427735%5D%2C+%5B8.59045%2C+49.427367%5D%2C+%5B8.590054%2C+49.427347%5D%2C+%5B8.589757%2C+49.427329%5D%2C+%5B8.589435%2C+49.427296%5D%2C+%5B8.588442%2C+49.427151%5D%2C+%5B8.587764%2C+49.427038%5D%2C+%5B8.58724%2C+49.426958%5D%2C+%5B8.587079%2C+49.426934%5D%2C+%5B8.586232%2C+49.426846%5D%2C+%5B8.584079%2C+49.4266%5D%2C+%5B8.583508%2C+49.426541%5D%2C+%5B8.582919%2C+49.426506%5D%2C+%5B8.582023%2C+49.426473%5D%2C+%5B8.581379%2C+49.42645%5D%2C+%5B8.579833%2C+49.426199%5D%2C+%5B8.577791%2C+49.425274%5D%2C+%5B8.577288%2C+49.425085%5D%2C+%5B8.575385%2C+49.424356%5D%2C+%5B8.57529%2C+49.424422%5D%2C+%5B8.574243%2C+49.424021%5D%2C+%5B8.573179%2C+49.4236%5D%5D%5D%7D%2C+%22properties%22%3A+%7B%22osm_id%22%3A+-285864%2C+%22boundary%22%3A+%22administrative%22%2C+%22admin_level%22%3A+6%2C+%22parents%22%3A+%22-22027%2C-62611%2C-51477%22%2C+%22name%22%3A+%22Heidelberg%22%2C+%22local_name%22%3A+%22Heidelberg%22%2C+%22name_en%22%3A+null%7D%7D%5D%7D
- headers:
- accept:
- - '*/*'
- accept-encoding:
- - gzip, deflate
- connection:
- - keep-alive
- content-length:
- - '30534'
- content-type:
- - application/x-www-form-urlencoded
- host:
- - api.ohsome.org
- user-agent:
- - ohsome-quality-api/1.0.1
- method: POST
- uri: https://api.ohsome.org/v1/elements/area
- response:
- content: "{\n \"attribution\" : {\n \"url\" : \"https://ohsome.org/copyrights\",\n
- \ \"text\" : \"\xA9 OpenStreetMap contributors\"\n },\n \"apiVersion\" :
- \"1.10.0\",\n \"result\" : [ {\n \"timestamp\" : \"2023-09-10T20:00:00Z\",\n
- \ \"value\" : 6519581.21\n } ]\n}"
- headers:
- access-control-allow-credentials:
- - 'true'
- access-control-allow-headers:
- - Origin,Accept,X-Requested-With,Content-Type,Access-Control-Request-Method,Access-Control-Request-Headers,Authorization
- access-control-allow-methods:
- - POST, GET
- access-control-allow-origin:
- - '*'
- access-control-max-age:
- - '3600'
- cache-control:
- - no-cache, no-store, must-revalidate
- connection:
- - Keep-Alive
- content-encoding:
- - gzip
- content-type:
- - application/json
- date:
- - Tue, 19 Sep 2023 13:46:47 GMT
- keep-alive:
- - timeout=5, max=100
- server:
- - Apache/2.4.52 (Ubuntu)
- strict-transport-security:
- - max-age=63072000; includeSubdomains;
- transfer-encoding:
- - chunked
- vary:
- - accept-encoding
- http_version: HTTP/1.1
- status_code: 200
- request:
body: filter=building%3D%2A+and+building%21%3Dno+and+geometry%3Apolygon&bpolys=%7B%22type%22%3A+%22FeatureCollection%22%2C+%22features%22%3A+%5B%7B%22type%22%3A+%22Feature%22%2C+%22geometry%22%3A+%7B%22type%22%3A+%22MultiPolygon%22%2C+%22coordinates%22%3A+%5B%5B%5B%5B13.368229%2C+52.493336%5D%2C+%5B13.376562%2C+52.49167%5D%2C+%5B13.373518%2C+52.48797%5D%2C+%5B13.374019%2C+52.485167%5D%2C+%5B13.371607%2C+52.484979%5D%2C+%5B13.394261%2C+52.485775%5D%2C+%5B13.394613%2C+52.484022%5D%2C+%5B13.406346%2C+52.482792%5D%2C+%5B13.407887%2C+52.48886%5D%2C+%5B13.423705%2C+52.486384%5D%2C+%5B13.42535%2C+52.488182%5D%2C+%5B13.4204%2C+52.495864%5D%2C+%5B13.439262%2C+52.48961%5D%2C+%5B13.445549%2C+52.494856%5D%2C+%5B13.45293%2C+52.497707%5D%2C+%5B13.463355%2C+52.495486%5D%2C+%5B13.464279%2C+52.493719%5D%2C+%5B13.476147%2C+52.489944%5D%2C+%5B13.478628%2C+52.487033%5D%2C+%5B13.481678%2C+52.487638%5D%2C+%5B13.482954%2C+52.48605%5D%2C+%5B13.491443%2C+52.488283%5D%2C+%5B13.473076%2C+52.499003%5D%2C+%5B13.468573%2C+52.499657%5D%2C+%5B13.471164%2C+52.505138%5D%2C+%5B13.476266%2C+52.510439%5D%2C+%5B13.475888%2C+52.514863%5D%2C+%5B13.477729%2C+52.51472%5D%2C+%5B13.47239%2C+52.520571%5D%2C+%5B13.462695%2C+52.519928%5D%2C+%5B13.45529%2C+52.521272%5D%2C+%5B13.456157%2C+52.522458%5D%2C+%5B13.452183%2C+52.527796%5D%2C+%5B13.447168%2C+52.526408%5D%2C+%5B13.442277%2C+52.531026%5D%2C+%5B13.438748%2C+52.528778%5D%2C+%5B13.423642%2C+52.527915%5D%2C+%5B13.419753%2C+52.525546%5D%2C+%5B13.429188%2C+52.521203%5D%2C+%5B13.425927%2C+52.518393%5D%2C+%5B13.42278%2C+52.512234%5D%2C+%5B13.429402%2C+52.508563%5D%2C+%5B13.4272%2C+52.505667%5D%2C+%5B13.414072%2C+52.504037%5D%2C+%5B13.409969%2C+52.506928%5D%2C+%5B13.40803%2C+52.506183%5D%2C+%5B13.400228%2C+52.509382%5D%2C+%5B13.39923%2C+52.508077%5D%2C+%5B13.37765%2C+52.507966%5D%2C+%5B13.37498%2C+52.503376%5D%2C+%5B13.373609%2C+52.504164%5D%2C+%5B13.369514%2C+52.498879%5D%2C+%5B13.368229%2C+52.493336%5D%5D%5D%5D%7D%2C+%22properties%22%3A+%7B%22osm_id%22%3A+-55764%2C+%22boundary%22%3A+%22administrative%22%2C+%22admin_level%22%3A+9%2C+%22parents%22%3A+%22-62422%2C-51477%22%2C+%22name%22%3A+%22Friedrichshain-Kreuzberg%22%2C+%22local_name%22%3A+%22Friedrichshain-Kreuzberg%22%2C+%22name_en%22%3A+null%7D%7D%5D%7D
headers:
@@ -72,14 +15,14 @@ interactions:
host:
- api.ohsome.org
user-agent:
- - ohsome-quality-api/1.0.1
+ - ohsome-quality-api/1.2.1
method: POST
uri: https://api.ohsome.org/v1/elements/area
response:
content: "{\n \"attribution\" : {\n \"url\" : \"https://ohsome.org/copyrights\",\n
\ \"text\" : \"\xA9 OpenStreetMap contributors\"\n },\n \"apiVersion\" :
- \"1.10.0\",\n \"result\" : [ {\n \"timestamp\" : \"2023-09-10T20:00:00Z\",\n
- \ \"value\" : 5036441.31\n } ]\n}"
+ \"1.10.1\",\n \"result\" : [ {\n \"timestamp\" : \"2024-01-30T09:00:00Z\",\n
+ \ \"value\" : 5037018.84\n } ]\n}"
headers:
access-control-allow-credentials:
- 'true'
@@ -100,11 +43,11 @@ interactions:
content-type:
- application/json
date:
- - Tue, 26 Sep 2023 12:12:22 GMT
+ - Sat, 03 Feb 2024 10:37:04 GMT
keep-alive:
- timeout=5, max=100
server:
- - Apache/2.4.52 (Ubuntu)
+ - Apache
strict-transport-security:
- max-age=63072000; includeSubdomains;
transfer-encoding:
@@ -114,7 +57,7 @@ interactions:
http_version: HTTP/1.1
status_code: 200
- request:
- body: filter=building%3D%2A+and+building%21%3Dno+and+geometry%3Apolygon&bpolys=%7B%22type%22%3A+%22FeatureCollection%22%2C+%22features%22%3A+%5B%7B%22type%22%3A+%22Feature%22%2C+%22geometry%22%3A+%7B%22type%22%3A+%22Polygon%22%2C+%22coordinates%22%3A+%5B%5B%5B13.369514%2C+52.498879%5D%2C+%5B13.373609%2C+52.504164%5D%2C+%5B13.37498%2C+52.503376%5D%2C+%5B13.37765%2C+52.507966%5D%2C+%5B13.39923%2C+52.508077%5D%2C+%5B13.400228%2C+52.509382%5D%2C+%5B13.40803%2C+52.506183%5D%2C+%5B13.409969%2C+52.506928%5D%2C+%5B13.414072%2C+52.504037%5D%2C+%5B13.4272%2C+52.505667%5D%2C+%5B13.429402%2C+52.508563%5D%2C+%5B13.42278%2C+52.512234%5D%2C+%5B13.425927%2C+52.518393%5D%2C+%5B13.429188%2C+52.521203%5D%2C+%5B13.419753%2C+52.525546%5D%2C+%5B13.423642%2C+52.527915%5D%2C+%5B13.438748%2C+52.528778%5D%2C+%5B13.442277%2C+52.531026%5D%2C+%5B13.447168%2C+52.526408%5D%2C+%5B13.452183%2C+52.527796%5D%2C+%5B13.456157%2C+52.522458%5D%2C+%5B13.45529%2C+52.521272%5D%2C+%5B13.462695%2C+52.519928%5D%2C+%5B13.47239%2C+52.520571%5D%2C+%5B13.477729%2C+52.51472%5D%2C+%5B13.475888%2C+52.514863%5D%2C+%5B13.476266%2C+52.510439%5D%2C+%5B13.471164%2C+52.505138%5D%2C+%5B13.468573%2C+52.499657%5D%2C+%5B13.473076%2C+52.499003%5D%2C+%5B13.491443%2C+52.488283%5D%2C+%5B13.482954%2C+52.48605%5D%2C+%5B13.481678%2C+52.487638%5D%2C+%5B13.478628%2C+52.487033%5D%2C+%5B13.476147%2C+52.489944%5D%2C+%5B13.464279%2C+52.493719%5D%2C+%5B13.463355%2C+52.495486%5D%2C+%5B13.45293%2C+52.497707%5D%2C+%5B13.445549%2C+52.494856%5D%2C+%5B13.439262%2C+52.48961%5D%2C+%5B13.4204%2C+52.495864%5D%2C+%5B13.42535%2C+52.488182%5D%2C+%5B13.423705%2C+52.486384%5D%2C+%5B13.407887%2C+52.48886%5D%2C+%5B13.406346%2C+52.482792%5D%2C+%5B13.394613%2C+52.484022%5D%2C+%5B13.394261%2C+52.485775%5D%2C+%5B13.371607%2C+52.484979%5D%2C+%5B13.374019%2C+52.485167%5D%2C+%5B13.373518%2C+52.48797%5D%2C+%5B13.376562%2C+52.49167%5D%2C+%5B13.368229%2C+52.493336%5D%2C+%5B13.369514%2C+52.498879%5D%5D%5D%7D%2C+%22properties%22%3A+%7B%22osm_id%22%3A+-55764%2C+%22boundary%22%3A+%22administrative%22%2C+%22admin_level%22%3A+9%2C+%22parents%22%3A+%22-62422%2C-51477%22%2C+%22name%22%3A+%22Friedrichshain-Kreuzberg%22%2C+%22local_name%22%3A+%22Friedrichshain-Kreuzberg%22%2C+%22name_en%22%3A+null%7D%7D%5D%7D
+ body: filter=building%3D%2A+and+building%21%3Dno+and+geometry%3Apolygon&bpolys=%7B%22type%22%3A+%22FeatureCollection%22%2C+%22features%22%3A+%5B%7B%22type%22%3A+%22Feature%22%2C+%22geometry%22%3A+%7B%22type%22%3A+%22MultiPolygon%22%2C+%22coordinates%22%3A+%5B%5B%5B%5B13.368229%2C+52.493336%5D%2C+%5B13.376562%2C+52.49167%5D%2C+%5B13.373518%2C+52.48797%5D%2C+%5B13.374019%2C+52.485167%5D%2C+%5B13.371607%2C+52.484979%5D%2C+%5B13.394261%2C+52.485775%5D%2C+%5B13.394613%2C+52.484022%5D%2C+%5B13.406346%2C+52.482792%5D%2C+%5B13.407887%2C+52.48886%5D%2C+%5B13.423705%2C+52.486384%5D%2C+%5B13.42535%2C+52.488182%5D%2C+%5B13.4204%2C+52.495864%5D%2C+%5B13.439262%2C+52.48961%5D%2C+%5B13.445549%2C+52.494856%5D%2C+%5B13.45293%2C+52.497707%5D%2C+%5B13.463355%2C+52.495486%5D%2C+%5B13.464279%2C+52.493719%5D%2C+%5B13.476147%2C+52.489944%5D%2C+%5B13.478628%2C+52.487033%5D%2C+%5B13.481678%2C+52.487638%5D%2C+%5B13.482954%2C+52.48605%5D%2C+%5B13.491443%2C+52.488283%5D%2C+%5B13.473076%2C+52.499003%5D%2C+%5B13.468573%2C+52.499657%5D%2C+%5B13.471164%2C+52.505138%5D%2C+%5B13.476266%2C+52.510439%5D%2C+%5B13.475888%2C+52.514863%5D%2C+%5B13.477729%2C+52.51472%5D%2C+%5B13.47239%2C+52.520571%5D%2C+%5B13.462695%2C+52.519928%5D%2C+%5B13.45529%2C+52.521272%5D%2C+%5B13.456157%2C+52.522458%5D%2C+%5B13.452183%2C+52.527796%5D%2C+%5B13.447168%2C+52.526408%5D%2C+%5B13.442277%2C+52.531026%5D%2C+%5B13.438748%2C+52.528778%5D%2C+%5B13.423642%2C+52.527915%5D%2C+%5B13.419753%2C+52.525546%5D%2C+%5B13.429188%2C+52.521203%5D%2C+%5B13.425927%2C+52.518393%5D%2C+%5B13.42278%2C+52.512234%5D%2C+%5B13.429402%2C+52.508563%5D%2C+%5B13.4272%2C+52.505667%5D%2C+%5B13.414072%2C+52.504037%5D%2C+%5B13.409969%2C+52.506928%5D%2C+%5B13.40803%2C+52.506183%5D%2C+%5B13.400228%2C+52.509382%5D%2C+%5B13.39923%2C+52.508077%5D%2C+%5B13.37765%2C+52.507966%5D%2C+%5B13.37498%2C+52.503376%5D%2C+%5B13.373609%2C+52.504164%5D%2C+%5B13.369514%2C+52.498879%5D%2C+%5B13.368229%2C+52.493336%5D%5D%5D%5D%7D%2C+%22properties%22%3A+%7B%22osm_id%22%3A+-55764%2C+%22boundary%22%3A+%22administrative%22%2C+%22admin_level%22%3A+9%2C+%22parents%22%3A+%22-62422%2C-51477%22%2C+%22name%22%3A+%22Friedrichshain-Kreuzberg%22%2C+%22local_name%22%3A+%22Friedrichshain-Kreuzberg%22%2C+%22name_en%22%3A+null%7D%7D%5D%7D
headers:
accept:
- '*/*'
@@ -123,20 +66,20 @@ interactions:
connection:
- keep-alive
content-length:
- - '2231'
+ - '2242'
content-type:
- application/x-www-form-urlencoded
host:
- api.ohsome.org
user-agent:
- - ohsome-quality-api/1.0.2
+ - ohsome-quality-api/1.2.1
method: POST
uri: https://api.ohsome.org/v1/elements/area
response:
content: "{\n \"attribution\" : {\n \"url\" : \"https://ohsome.org/copyrights\",\n
\ \"text\" : \"\xA9 OpenStreetMap contributors\"\n },\n \"apiVersion\" :
- \"1.10.1\",\n \"result\" : [ {\n \"timestamp\" : \"2023-10-22T20:00:00Z\",\n
- \ \"value\" : 5026307.68\n } ]\n}"
+ \"1.10.1\",\n \"result\" : [ {\n \"timestamp\" : \"2024-01-30T09:00:00Z\",\n
+ \ \"value\" : 5037018.84\n } ]\n}"
headers:
access-control-allow-credentials:
- 'true'
@@ -157,7 +100,7 @@ interactions:
content-type:
- application/json
date:
- - Mon, 13 Nov 2023 11:14:11 GMT
+ - Sat, 03 Feb 2024 10:37:12 GMT
keep-alive:
- timeout=5, max=100
server:
diff --git a/tests/integrationtests/indicators/test_building_comparison.py b/tests/integrationtests/indicators/test_building_comparison.py
index 4c645f0be..291b951eb 100644
--- a/tests/integrationtests/indicators/test_building_comparison.py
+++ b/tests/integrationtests/indicators/test_building_comparison.py
@@ -8,52 +8,96 @@
from ohsome_quality_api.indicators.building_comparison.indicator import (
BuildingComparison,
- get_sources,
)
from tests.integrationtests.utils import oqapi_vcr
-@pytest.fixture(scope="class")
+@pytest.fixture
def mock_get_building_area(class_mocker):
- async_mock = AsyncMock(return_value=4842587.791645115)
+ async def side_effect_function(*args, **kwargs):
+ if args[1] == "EUBUCCO":
+ return 6000000.791645115
+ else:
+ return 5000000.791645115
+
+ async_mock = AsyncMock(side_effect=side_effect_function)
class_mocker.patch(
- "ohsome_quality_api.indicators.building_comparison.indicator.get_eubucco_building_area",
+ "ohsome_quality_api.indicators.building_comparison.indicator.get_reference_building_area",
side_effect=async_mock,
)
-@pytest.fixture(scope="class")
+@pytest.fixture
def mock_get_building_area_low(class_mocker):
- async_mock = AsyncMock(return_value=1)
+ async_mock = AsyncMock(return_value=1000000)
+ class_mocker.patch(
+ "ohsome_quality_api.indicators.building_comparison.indicator.get_reference_building_area",
+ side_effect=async_mock,
+ )
+
+
+@pytest.fixture
+def mock_get_building_area_low_some(class_mocker):
+ async def side_effect_function(*args, **kwargs):
+ if args[1] == "EUBUCCO":
+ return 1
+ else:
+ return 6000000.791645115
+
+ async_mock = AsyncMock(side_effect=side_effect_function)
class_mocker.patch(
- "ohsome_quality_api.indicators.building_comparison.indicator.get_eubucco_building_area",
+ "ohsome_quality_api.indicators.building_comparison.indicator.get_reference_building_area",
side_effect=async_mock,
)
-@pytest.fixture(scope="class")
+@pytest.fixture
def mock_get_building_area_empty(class_mocker):
async_mock = AsyncMock(return_value=0)
class_mocker.patch(
- "ohsome_quality_api.indicators.building_comparison.indicator.get_eubucco_building_area",
+ "ohsome_quality_api.indicators.building_comparison.indicator.get_reference_building_area",
side_effect=async_mock,
)
-@pytest.fixture(scope="class")
-def mock_get_eubucco_coverage_intersection(class_mocker, feature_germany_berlin):
+@pytest.fixture
+def mock_get_intersection_geom(class_mocker, feature_germany_berlin):
async_mock = AsyncMock(return_value=feature_germany_berlin)
class_mocker.patch(
- "ohsome_quality_api.indicators.building_comparison.indicator.db_client.get_eubucco_coverage_intersection",
+ "ohsome_quality_api.indicators.building_comparison.indicator.db_client.get_intersection_geom",
side_effect=async_mock,
)
-@pytest.fixture(scope="class")
-def mock_get_eubucco_coverage_intersection_area(class_mocker):
- async_mock = AsyncMock(return_value=[{"area_ratio": 1}])
+@pytest.fixture
+def mock_get_intersection_area(class_mocker):
+ async_mock = AsyncMock(return_value=1.0)
class_mocker.patch(
- "ohsome_quality_api.indicators.building_comparison.indicator.db_client.get_eubucco_coverage_intersection_area",
+ "ohsome_quality_api.indicators.building_comparison.indicator.db_client.get_intersection_area",
+ side_effect=async_mock,
+ )
+
+
+@pytest.fixture
+def mock_get_intersection_area_none(class_mocker):
+ async_mock = AsyncMock(return_value=0)
+ class_mocker.patch(
+ "ohsome_quality_api.indicators.building_comparison.indicator.db_client.get_intersection_area",
+ side_effect=async_mock,
+ )
+
+
+@pytest.fixture
+def mock_get_intersection_area_some(class_mocker):
+ async def side_effect(*args, **kwargs):
+ if "eubucco" in args[1]:
+ return 0.0 # 0 %
+ else:
+ return 1.0 # 100 %
+
+ async_mock = AsyncMock(side_effect=side_effect)
+ class_mocker.patch(
+ "ohsome_quality_api.indicators.building_comparison.indicator.db_client.get_intersection_area",
side_effect=async_mock,
)
@@ -64,39 +108,83 @@ def test_init(self, topic_building_area, feature_germany_berlin):
indicator = BuildingComparison(topic_building_area, feature_germany_berlin)
assert indicator.th_high == 0.85
assert indicator.th_low == 0.5
+ assert isinstance(indicator.data_ref, dict)
+
+ def test_get_sources(self, topic_building_area, feature_germany_berlin):
+ indicator = BuildingComparison(topic_building_area, feature_germany_berlin)
+ source = indicator.format_sources()
+ assert "EUBUCCO" in source
+
+ def test_attribution(self, topic_building_area, feature_germany_berlin):
+ indicator = BuildingComparison(topic_building_area, feature_germany_berlin)
+ assert indicator.attribution is not None
+ assert indicator.attribution != ""
class TestPreprocess:
@oqapi_vcr.use_cassette
- def test_preprocess(
+ @pytest.mark.usefixtures(
+ "mock_get_building_area",
+ "mock_get_intersection_area",
+ "mock_get_intersection_geom",
+ )
+ def test_preprocess(self, topic_building_area, feature_germany_berlin):
+ indicator = BuildingComparison(topic_building_area, feature_germany_berlin)
+ asyncio.run(indicator.preprocess())
+
+ for area in indicator.area_osm.values():
+ assert area is not None
+ assert area > 0
+ assert isinstance(indicator.result.timestamp, datetime)
+ assert isinstance(indicator.result.timestamp_osm, datetime)
+
+ @oqapi_vcr.use_cassette
+ def test_preprocess_no_intersection(
self,
mock_get_building_area,
topic_building_area,
feature_germany_berlin,
- mock_get_eubucco_coverage_intersection_area,
- mock_get_eubucco_coverage_intersection,
+ mock_get_intersection_area_none,
+ ):
+ indicator = BuildingComparison(topic_building_area, feature_germany_berlin)
+ asyncio.run(indicator.preprocess())
+
+ for area in indicator.area_cov.values():
+ assert area == 0.0
+ assert isinstance(indicator.result.timestamp, datetime)
+ assert indicator.result.timestamp_osm is None
+
+ @oqapi_vcr.use_cassette
+ @pytest.mark.usefixtures(
+ "mock_get_building_area",
+ "mock_get_intersection_geom",
+ "mock_get_intersection_area_some",
+ )
+ def test_preprocess_some_intersection(
+ self,
+ topic_building_area,
+ feature_germany_berlin,
):
indicator = BuildingComparison(topic_building_area, feature_germany_berlin)
asyncio.run(indicator.preprocess())
- assert indicator.area_osm is not None
- assert indicator.area_osm > 0
- assert indicator.area_references == {
- "EUBUCCO": 4.842587791645116,
- }
+ assert 1.0 in list(indicator.area_cov.values())
+ assert 0.0 in list(indicator.area_cov.values())
assert isinstance(indicator.result.timestamp, datetime)
assert isinstance(indicator.result.timestamp_osm, datetime)
class TestCalculate:
@oqapi_vcr.use_cassette
+ @pytest.mark.usefixtures(
+ "mock_get_building_area",
+ "mock_get_intersection_area",
+ "mock_get_intersection_geom",
+ )
def test_calculate(
self,
- mock_get_building_area,
topic_building_area,
feature_germany_berlin,
- mock_get_eubucco_coverage_intersection_area,
- mock_get_eubucco_coverage_intersection,
):
indicator = BuildingComparison(topic_building_area, feature_germany_berlin)
asyncio.run(indicator.preprocess())
@@ -104,82 +192,172 @@ def test_calculate(
assert indicator.result.value is not None
assert indicator.result.value > 0
assert indicator.result.class_ is not None
- assert indicator.result.class_ == 5
+ assert indicator.result.class_ >= 0
@oqapi_vcr.use_cassette
+ @pytest.mark.usefixtures(
+ "mock_get_building_area_empty",
+ "mock_get_intersection_area",
+ "mock_get_intersection_geom",
+ )
def test_calculate_reference_area_0(
self,
- mock_get_building_area_empty,
topic_building_area,
feature_germany_heidelberg,
- mock_get_eubucco_coverage_intersection_area,
- mock_get_eubucco_coverage_intersection,
):
indicator = BuildingComparison(topic_building_area, feature_germany_heidelberg)
asyncio.run(indicator.preprocess())
- indicator.coverage["EUBUCCO"] is None
indicator.calculate()
- assert indicator.result.value is None
+ assert indicator.result.value == 0.0
@oqapi_vcr.use_cassette
+ @pytest.mark.usefixtures(
+ "mock_get_intersection_area",
+ "mock_get_intersection_geom",
+ "mock_get_building_area_low",
+ )
def test_calculate_above_one_th(
self,
- mock_get_building_area_low,
topic_building_area,
feature_germany_heidelberg,
- mock_get_eubucco_coverage_intersection_area,
- mock_get_eubucco_coverage_intersection,
):
indicator = BuildingComparison(topic_building_area, feature_germany_heidelberg)
asyncio.run(indicator.preprocess())
indicator.calculate()
- assert indicator.result.value is not None
- assert indicator.result.value > 0
+ assert indicator.result.value is None
assert indicator.result.class_ is None
assert indicator.result.description is not None
+ for v in indicator.area_ref.values():
+ assert v is not None
+ for v in indicator.area_osm.values():
+ assert v is not None
assert (
- "Warning: Because of a big difference between OSM and the reference "
- + "data no quality estimation has been made. "
- + "It could be that the reference data is outdated. "
+ "Warning: OSM has substantivly more buildings mapped than the Reference "
+ "datasets. No quality estimation has been made."
in indicator.result.description
)
assert indicator.result.label == "undefined"
+ @oqapi_vcr.use_cassette
+ @pytest.mark.usefixtures("mock_get_intersection_area_none")
+ def test_calculate_no_intersection(
+ self,
+ topic_building_area,
+ feature_germany_heidelberg,
+ ):
+ indicator = BuildingComparison(topic_building_area, feature_germany_heidelberg)
+ asyncio.run(indicator.preprocess())
+ indicator.calculate()
+ assert indicator.result.value is None
+ assert indicator.result.class_ is None
+ assert indicator.result.description is not None
+ assert (
+ "Comparison could not be made. None of the reference datasets covers the "
+ "area-of-interest." in indicator.result.description
+ )
+ assert indicator.result.label == "undefined"
+
+ @oqapi_vcr.use_cassette
+ @pytest.mark.usefixtures(
+ "mock_get_building_area",
+ "mock_get_intersection_geom",
+ "mock_get_intersection_area_some",
+ )
+ def test_calculate_some_intersection(
+ self,
+ topic_building_area,
+ feature_germany_heidelberg,
+ ):
+ indicator = BuildingComparison(topic_building_area, feature_germany_heidelberg)
+ asyncio.run(indicator.preprocess())
+ indicator.calculate()
+ assert indicator.result.value is not None
+ assert indicator.result.value > 0
+ assert indicator.result.class_ is not None
+ assert indicator.result.class_ >= 0
+ assert indicator.result.description is not None
+ # major edge case description
+ assert (
+ "Reference dataset EUBUCCO does not cover area-of-interest."
+ in indicator.result.description
+ )
+ assert (
+ "of the area-of-interest is covered by the reference dataset"
+ in indicator.result.description
+ )
-class TestFigure:
- @pytest.fixture(scope="class")
@oqapi_vcr.use_cassette
- def indicator(
+ @pytest.mark.usefixtures(
+ "mock_get_building_area",
+ "mock_get_intersection_geom",
+ "mock_get_intersection_area",
+ "mock_get_building_area_low_some",
+ )
+ def test_calculate_above_one_th_and_expected(
self,
- mock_get_building_area,
topic_building_area,
- feature_germany_berlin,
- mock_get_eubucco_coverage_intersection_area,
- mock_get_eubucco_coverage_intersection,
+ feature_germany_heidelberg,
):
- indicator = BuildingComparison(topic_building_area, feature_germany_berlin)
+ indicator = BuildingComparison(topic_building_area, feature_germany_heidelberg)
asyncio.run(indicator.preprocess())
indicator.calculate()
- return indicator
+ assert indicator.result.value is not None
+ assert indicator.result.value > 0
+ assert indicator.result.class_ is not None
+ assert indicator.result.class_ >= 0
+ assert indicator.result.label != "undefined"
+ assert indicator.result.description is not None
+ assert (
+ "of the area-of-interest is covered by the reference dataset"
+ in indicator.result.description
+ )
+ # TODO: should user be warned if a dataset was not fit for comparison?
+ # -> for ratio above self.above_one_th
+ # assert (
+ # "this data is not considered in the overall result value."
+ # in indicator.result.description
+ # )
+
- def test_create_figure(self, indicator):
+class TestFigure:
+ @oqapi_vcr.use_cassette
+ @pytest.mark.usefixtures(
+ "mock_get_building_area",
+ "mock_get_intersection_geom",
+ "mock_get_intersection_area",
+ )
+ def test_create_figure(self, topic_building_area, feature_germany_berlin):
+ indicator = BuildingComparison(topic_building_area, feature_germany_berlin)
+ asyncio.run(indicator.preprocess())
+ indicator.calculate()
indicator.create_figure()
assert isinstance(indicator.result.figure, dict)
pgo.Figure(indicator.result.figure) # test for valid Plotly figure
+ @oqapi_vcr.use_cassette
@pytest.mark.skip(reason="Only for manual testing.") # comment for manual test
- def test_create_figure_manual(self, indicator):
+ @pytest.mark.usefixtures(
+ "mock_get_building_area",
+ "mock_get_intersection_geom",
+ "mock_get_intersection_area",
+ )
+ def test_create_figure_manual(self, topic_building_area, feature_germany_berlin):
+ indicator = BuildingComparison(topic_building_area, feature_germany_berlin)
+ asyncio.run(indicator.preprocess())
+ indicator.calculate()
indicator.create_figure()
pio.show(indicator.result.figure)
@oqapi_vcr.use_cassette
+ @pytest.mark.usefixtures(
+ "mock_get_building_area",
+ "mock_get_intersection_geom",
+ "mock_get_intersection_area",
+ )
def test_create_figure_above_one_th(
self,
- mock_get_building_area_low,
topic_building_area,
feature_germany_berlin,
- mock_get_eubucco_coverage_intersection_area,
- mock_get_eubucco_coverage_intersection,
):
indicator = BuildingComparison(topic_building_area, feature_germany_berlin)
asyncio.run(indicator.preprocess())
@@ -190,13 +368,15 @@ def test_create_figure_above_one_th(
pgo.Figure(indicator.result.figure)
@oqapi_vcr.use_cassette
+ @pytest.mark.usefixtures(
+ "mock_get_building_area",
+ "mock_get_intersection_geom",
+ "mock_get_intersection_area",
+ )
def test_create_figure_building_area_zero(
self,
- mock_get_building_area_empty,
topic_building_area,
feature_germany_berlin,
- mock_get_eubucco_coverage_intersection_area,
- mock_get_eubucco_coverage_intersection,
):
indicator = BuildingComparison(topic_building_area, feature_germany_berlin)
asyncio.run(indicator.preprocess())
@@ -205,8 +385,3 @@ def test_create_figure_building_area_zero(
assert isinstance(indicator.result.figure, dict)
assert indicator.result.figure["data"][0]["type"] == "bar"
pgo.Figure(indicator.result.figure)
-
-
-def test_get_sources():
- source = get_sources(["EUBUCCO"])
- assert source == "EUBUCCO"
diff --git a/tests/integrationtests/test_base_indicator.py b/tests/integrationtests/test_base_indicator.py
index 155345e76..eb31bbb95 100644
--- a/tests/integrationtests/test_base_indicator.py
+++ b/tests/integrationtests/test_base_indicator.py
@@ -2,7 +2,7 @@
import plotly.graph_objects as pgo
import pytest
-from geojson import Polygon
+from geojson import Feature
from ohsome_quality_api.indicators.minimal.indicator import Minimal
from ohsome_quality_api.indicators.models import Result
@@ -59,15 +59,18 @@ def test_attribution_class_property(self):
def test_coverage(self):
coverage = asyncio.run(Minimal.coverage(inverse=False))
- assert isinstance(coverage, Polygon)
- assert coverage.is_valid
+ for feature in coverage:
+ assert isinstance(feature, Feature)
+ assert feature.is_valid
coverage_default = asyncio.run(Minimal.coverage())
- assert isinstance(coverage_default, Polygon)
- assert coverage_default.is_valid
+ for feature in coverage_default:
+ assert isinstance(feature, Feature)
+ assert feature.is_valid
assert coverage_default == coverage
coverage_inversed = asyncio.run(Minimal.coverage(inverse=True))
- assert isinstance(coverage_inversed, Polygon)
- assert coverage_inversed.is_valid
+ for feature in coverage_inversed:
+ assert isinstance(feature, Feature)
+ assert feature.is_valid
assert coverage != coverage_inversed
assert coverage_default != coverage_inversed
diff --git a/tests/integrationtests/test_geodatabase.py b/tests/integrationtests/test_geodatabase.py
index 8b27feddf..af4858c16 100644
--- a/tests/integrationtests/test_geodatabase.py
+++ b/tests/integrationtests/test_geodatabase.py
@@ -3,6 +3,7 @@
import geojson
import pytest
+from geojson import Feature
import ohsome_quality_api.geodatabase.client as db_client
@@ -64,35 +65,38 @@ def test_get_shdi_multiple_intersections():
assert result[0]["shdi"] <= 1.0
-def test_get_building_area(feature_germany_berlin):
- result = asyncio.run(db_client.get_building_area(feature_germany_berlin))
- assert result[0]["area"] == 4842587.791645115
-
-
-def test_get_eubucco_coverage():
- result = asyncio.run(db_client.get_eubucco_coverage())
- obj: geojson.MultiPolygon = geojson.loads(result[0]["geom"])
- assert obj.is_valid
- assert isinstance(obj, geojson.MultiPolygon)
+@pytest.mark.parametrize(
+ "table", ["eubucco_v0_1_coverage_simple", "eubucco_v0_1_coverage_inversed"]
+)
+def test_get_reference_coverage(table):
+ result = asyncio.run(db_client.get_reference_coverage(table))
+ assert result.is_valid
+ assert isinstance(result, Feature)
def test_get_eubucco_coverage_intersection_area_none(
feature_collection_germany_heidelberg,
):
bpoly = feature_collection_germany_heidelberg.features[0]
- result = asyncio.run(db_client.get_eubucco_coverage_intersection_area(bpoly))
- assert result == []
+ result = asyncio.run(
+ db_client.get_intersection_area(bpoly, "eubucco_v0_1_coverage_simple")
+ )
+ assert result == 0.0
def test_get_eubucco_coverage_intersection_area(feature_germany_berlin):
bpoly = feature_germany_berlin
- result = asyncio.run(db_client.get_eubucco_coverage_intersection_area(bpoly))
- assert pytest.approx(1.0, 0.1) == result[0]["area_ratio"]
+ result = asyncio.run(
+ db_client.get_intersection_area(bpoly, "eubucco_v0_1_coverage_simple")
+ )
+ assert pytest.approx(1.0, 0.1) == result
def test_get_coverage_intersection(feature_germany_berlin):
bpoly = feature_germany_berlin
- result = asyncio.run(db_client.get_eubucco_coverage_intersection(bpoly))
+ result = asyncio.run(
+ db_client.get_intersection_geom(bpoly, "eubucco_v0_1_coverage_simple")
+ )
assert result["geometry"].is_valid
assert isinstance(result, geojson.feature.Feature)
diff --git a/tests/unittests/test_indicators_definitions.py b/tests/unittests/test_indicators_definitions.py
index e5564f244..f6d28640b 100644
--- a/tests/unittests/test_indicators_definitions.py
+++ b/tests/unittests/test_indicators_definitions.py
@@ -9,34 +9,26 @@
@pytest.fixture(scope="class")
-def mock_select_eubucco_coverage(class_mocker, feature_germany_berlin):
- async def side_effect(*args, **kwargs):
- inverse = args[0]
-
- if inverse:
- return [
- {
- "geom": geojson.dumps(
- Polygon(
- coordinates=[
- [
- (-180, 90),
- (-180, -90),
- (180, -90),
- (180, 90),
- (-180, 90),
- ]
- ]
- )
- )
- }
- ]
- else:
- return [{"geom": geojson.dumps(Polygon(coordinates=[]))}]
-
- async_mock = AsyncMock(side_effect=side_effect)
+def mock_get_reference_coverage(class_mocker):
+ async_mock = AsyncMock(
+ return_value=str(
+ geojson.dumps(
+ Polygon(
+ coordinates=[
+ [
+ (-180, 90),
+ (-180, -90),
+ (180, -90),
+ (180, 90),
+ (-180, 90),
+ ]
+ ]
+ )
+ )
+ )
+ )
class_mocker.patch(
- "ohsome_quality_api.indicators.building_completeness.indicator.db_client.get_eubucco_coverage",
+ "ohsome_quality_api.indicators.building_comparison.indicator.db_client.get_reference_coverage",
side_effect=async_mock,
)
@@ -66,22 +58,23 @@ def test_get_indicator_definitions_with_project():
assert indicator.projects == ["core"]
-def test_get_coverage(mock_select_eubucco_coverage):
+def test_get_coverage(mock_get_reference_coverage):
coverage = asyncio.run(
definitions.get_coverage("building-comparison", inverse=False)
)
assert coverage.is_valid
- coverage_default = asyncio.run(definitions.get_coverage("building-comparison"))
- assert coverage_default.is_valid
- assert coverage == coverage_default
- coverage_inversed = asyncio.run(
+ assert isinstance(coverage, geojson.FeatureCollection)
+
+ coverage = asyncio.run(definitions.get_coverage("building-comparison"))
+ assert coverage.is_valid
+ assert isinstance(coverage, geojson.FeatureCollection)
+
+ coverage = asyncio.run(
definitions.get_coverage("building-comparison", inverse=True)
)
- assert coverage_inversed.is_valid
- assert coverage != coverage_inversed
- assert coverage_default != coverage_inversed
-
+ assert coverage.is_valid
assert isinstance(coverage, geojson.FeatureCollection)
+
coverage = asyncio.run(definitions.get_coverage("mapping-saturation"))
assert coverage.is_valid
assert isinstance(coverage, geojson.FeatureCollection)