library(rgbif)
library(tidyverse)
library(sf)
library(leaflet)
library(dbscan)
library(concaveman)
# use existing data from GBIF
# keep valid and recent sightings in France.
<- occ_download_get("0034730-231002084531237") |>
lynx occ_download_import() |>
drop_na(decimalLongitude, decimalLatitude) |>
filter(year >= "2015",
== "FR",
countryCode == "PRESENT") |>
occurrenceStatus st_as_sf(coords = c("decimalLongitude", "decimalLatitude"),
crs = "EPSG:4326",
remove = FALSE)
# Create clusters
# we reproject to a Lambert projection to have units in meters
<- lynx |>
clusters st_transform("EPSG:2154") |>
st_coordinates() |>
dbscan(eps = 12000, minPts = 5)
# Create concave hulls
# we can chose an appropriate concavity parameter
<- lynx |>
concave_hulls bind_cols(tibble(cluster = clusters$cluster)) |>
filter(cluster != 0) |>
group_by(cluster) |>
summarise(nd = n_distinct(decimalLongitude, decimalLatitude),
.groups = "drop") |>
filter(nd > 2) |>
mutate(geom = map(geometry, ~ concaveman(st_sf(st_sfc(.x)),
concavity = 1.7))) |>
st_drop_geometry() |>
unnest(geom) |>
st_sf(crs = "EPSG:4326") |>
st_zm()
Day 3 of 30DayMapChallenge: « Polygons » (previously). Using data from a previous post on lynx occurrences.
So we mapped the sightings of lynx, but there are a lot of outliers; how can we map the core habitat of the species?
We will use DBSCAN to cluster the points, then we will build a concave hull of these clusters. We arbitrary chose a minimal distance of 12 km between clusters and at least 5 points per clusters. Many coordinates are duplicated so we’ll get rid of artificial one-dimension polygons.
|>
lynx leaflet() |>
addCircleMarkers(radius = 0.1, opacity = 0.1) |>
addPolygons(data = concave_hulls, color = "red") |>
addTiles()
We get 4 clusters: Jura, Vosges (North and South) and West of Dijon. We could estimate a rough lynx occupancy area in France:
|>
concave_hulls st_area() |>
sum() |>
::set_units(km^2) units
17925.6 [km^2]