The Global Biodiversity Information Facility (GBIF) hosts large biodiversity datasets contributed by museums, researchers, and citizen scientists. These datasets can be used to explore patterns in species distribution and migration.
For this analysis, I selected the Common Nighthawk (Chordeiles minor), an easily recognizable and vocal migratory bird commonly observed across the Americas. Common Nighthawks migrate long distances between breeding grounds in northern latitudes and wintering areas closer to the equator, making them a useful species for examining migration patterns using citizen science data.
The dataset used in this analysis was downloaded from GBIF and contains georeferenced observation records.
library(tidyverse)
library(leaflet)
library(rnaturalearthdata)
library(elevatr)
library(viridis)
library(dbscan)
library(MASS)
library(raster)
library(rgbif)
library(dplyr)
library(ggplot2)
#After looking at the data, we want to narrow our observations down. There are over 2 million observations to date.
## We then want to narrow down our criteria to the americas
library(rnaturalearth)
##
## Attaching package: 'rnaturalearth'
## The following object is masked from 'package:rnaturalearthdata':
##
## countries110
library(sf)
## Linking to GEOS 3.13.0, GDAL 3.8.5, PROJ 9.5.1; sf_use_s2() is TRUE
states <- ne_countries(country = "united states of america", returnclass = "sf")
#We will import the data just for the USA that has coordinates, and will stop after 2000 observations
chordeiles_observations <- occ_search(
scientificName = "Chordeiles minor",
country = "US",
hasCoordinate = TRUE,
limit = 2000
)$data
# We then will compare winter observations to those breeding during the rest of the year.
chordeiles_observations_winter <- occ_search(
scientificName = "Chordeiles minor",
country = "MX",
hasCoordinate = TRUE,
limit = 2000
)$data
#Creating a map from our data. This shows the bird observations and migration) on a map via leaflet - include layers for temperature and elevation
library(maps)
states <- map("state", fill = TRUE, plot = FALSE) %>%
st_as_sf()
# Elevation Layer
# elevation color palette
elev_pal <- colorNumeric(
palette = c("lightgreen","green","darkgreen","yellow","orange","red"),
domain = c(0,2000)
)
map <- leaflet() %>%
setView(lng = -79, lat = 37.8, zoom = 5) %>%
addProviderTiles(providers$Esri.NatGeoWorldMap) %>%
addPolygons(
data = states,
fill = FALSE,
color = "gray",
weight = 1
) %>%
addProviderTiles(providers$OpenTopoMap) %>%
addCircleMarkers(
data = chordeiles_observations,
lng = ~decimalLongitude,
lat = ~decimalLatitude,
color = "#FFB6C1",
fillOpacity = 1,
radius = 3,
popup = ~paste(name, ":", scientificName, "<br>Date:", eventDate),
group = "Night Hawk observations"
) %>%
addCircleMarkers(
data = chordeiles_observations_winter,
lng = ~decimalLongitude,
lat = ~decimalLatitude,
color = "blue",
fillOpacity = 1,
radius = 3,
popup = ~paste(name, ":", scientificName, "<br>Date:", eventDate),
group = "Night Hawk winter observations"
) %>%
addLayersControl(
overlayGroups = c(
"Night Hawk observations",
"Night Hawk winter observations"
),
options = layersControlOptions(collapsed = FALSE)
) %>%
addLegend(
position = "bottomright",
colors = c("#FFB6C1","blue"),
labels = c(
"Night Hawk breeding observations",
"Night Hawk winter observations"
),
opacity = 1,
title = "Observation Type"
) %>%
addLegend(
position = "bottomleft",
pal = elev_pal,
values = c(0,2000),
title = "Elevation (m)",
opacity = 1
)
map
library(rnaturalearth)
library(sf)
cities <- ne_download(scale = 10, type = "populated_places",
category = "cultural", returnclass = "sf")
north_america_cities <- cities %>%
filter(LATITUDE > 5, LATITUDE < 85,
LONGITUDE > -170, LONGITUDE < -50) %>%
arrange(desc(POP_MAX)) %>%
slice(1:3)
##Now we plot
elev_pal <- colorNumeric(
palette = c("lightgreen","green","darkgreen","yellow","orange","red"),
domain = c(0,2000)
)
map <- leaflet() %>%
setView(lng = -79, lat = 37.8, zoom = 5) %>%
addProviderTiles(providers$Esri.NatGeoWorldMap) %>%
addPolygons(
data = states,
fill = FALSE,
color = "gray",
weight = 1
) %>%
addProviderTiles(providers$OpenTopoMap) %>%
addCircleMarkers(
data = chordeiles_observations,
lng = ~decimalLongitude,
lat = ~decimalLatitude,
color = "#FFB6C1",
fillOpacity = 1,
radius = 3,
popup = ~paste(name, ":", scientificName, "<br>Date:", eventDate),
group = "Night Hawk observations"
) %>%
addCircleMarkers(
data = chordeiles_observations_winter,
lng = ~decimalLongitude,
lat = ~decimalLatitude,
color = "blue",
fillOpacity = 1,
radius = 3,
popup = ~paste(name, ":", scientificName, "<br>Date:", eventDate),
group = "Night Hawk winter observations"
) %>%
addLabelOnlyMarkers(
data = north_america_cities,
lng = ~st_coordinates(geometry)[,1],
lat = ~st_coordinates(geometry)[,2],
label = ~NAME,
labelOptions = labelOptions(
noHide = TRUE,
textOnly = TRUE,
style = list("font-weight"="bold","font-size"="14px")
)
) %>%
addLayersControl(
overlayGroups = c(
"Night Hawk observations",
"Night Hawk winter observations"
),
options = layersControlOptions(collapsed = FALSE)
) %>%
addLegend(
position = "bottomright",
colors = c("#FFB6C1","blue"),
labels = c(
"Night Hawk breeding observations",
"Night Hawk winter observations"
),
opacity = 1,
title = "Observation Type"
) %>%
addLegend(
position = "bottomleft",
pal = elev_pal,
values = c(0,2000),
title = "Elevation (m)",
opacity = 1
)
map
This map visualizes observations of the migratory bird Chordeiles minor (Night Hawk) using GBIF citizen science data. Observation points are displayed using circle markers positioned by latitude and longitude coordinates from the dataset.
Color was used to represent estimated temperature values based on latitude, providing environmental context for migration patterns. More specifically, birds shown blue represent individuals observed during the winter (cold months), while the pink individuals represent birds observed during the other months, which are warmer and represent the breeding months. This color palette was chosen because it is perceptually uniform and accessible for viewers with color vision deficiencies.
Elevation data was overlayed on a map of North America to provide additional geographic context and illustrate how terrain may influence bird distribution and migration routes. The specific elevation can be seen in the elevation legend.
On my second plot, I added the three most three most populous cities in North America to better understand how population dynamics are affecting the bird populations and migration habits. We see the top populated cities are New York, Los Angeles, and Mexico City. There does not appear to be an impact of populated cities on Night Hawk migration.
Legends were included for both the temperature gradient and elevation layer so that viewers can interpret the environmental variables displayed on the map.
Overall, the design aims to clearly display bird observation patterns while integrating environmental and geographic context relevant to migration behavior.