83 lines
2.1 KiB
Python
83 lines
2.1 KiB
Python
import requests
|
|
import pandas as pd
|
|
import numpy as np
|
|
from pyproj import Transformer
|
|
|
|
# create transformer once (faster if used repeatedly)
|
|
_transformer = Transformer.from_crs("EPSG:4326", "EPSG:3857", always_xy=True)
|
|
|
|
|
|
def main(lat, lon, radius_m,
|
|
n_vertices=15,
|
|
page_size=10000,
|
|
species_summary=False):
|
|
"""
|
|
Fetch Artsdatabanken observations inside a semicircular polygon.
|
|
|
|
Parameters
|
|
----------
|
|
lat : float
|
|
lon : float
|
|
radius_m : float
|
|
Radius in meters
|
|
n_vertices : int
|
|
Polygon vertices approximating the circle
|
|
page_size : int
|
|
species_summary : bool
|
|
If True, also return species counts
|
|
|
|
Returns
|
|
-------
|
|
pandas.DataFrame
|
|
(optional) pandas.Series with species counts
|
|
"""
|
|
|
|
# -------------------
|
|
# Build polygon
|
|
# -------------------
|
|
|
|
cx, cy = _transformer.transform(lon, lat)
|
|
|
|
angles = np.linspace(0, 2*np.pi, n_vertices, endpoint=False)
|
|
|
|
x = np.float32(cx + radius_m * np.cos(angles))
|
|
y = np.float32(cy + radius_m * np.sin(angles))
|
|
|
|
points = [f"{xi}+{yi}" for xi, yi in zip(x, y)]
|
|
points.append(points[0]) # close polygon
|
|
|
|
polygon = "POLYGON((" + ",".join(points) + "))"
|
|
|
|
# -------------------
|
|
# API request
|
|
# -------------------
|
|
|
|
url = (
|
|
"https://artskart.artsdatabanken.no/publicapi/api/observations/list/"
|
|
f"?gmWktPolygon={polygon}&page=0&pageSize={page_size}"
|
|
)
|
|
|
|
r = requests.get(url)
|
|
r.raise_for_status()
|
|
|
|
data = r.json()
|
|
|
|
if "Observations" not in data:
|
|
return pd.DataFrame()
|
|
|
|
# -------------------
|
|
# Dataframe creation
|
|
# -------------------
|
|
|
|
df = pd.json_normalize(data["Observations"])[
|
|
["Latitude", "Longitude", "Notes", "ScientificName", "ScientificNameId"]
|
|
]
|
|
|
|
df["Latitude"] = df["Latitude"].str.replace(",", ".").astype(float)
|
|
df["Longitude"] = df["Longitude"].str.replace(",", ".").astype(float)
|
|
|
|
if species_summary:
|
|
return df, df["ScientificName"].value_counts()
|
|
|
|
return df
|