Getting GPS points to show up on plot
16:50 29 May 2026

I'm trying to make an animation of animal movements using the Seabird Tracking Animation Exercise (RPubs - gganimate tutorial) to help my own data. However when I go to plot the map my points do not show up. My basemap extent is set to the correct extent but the basemap that shows up is not correct. Any suggestions as to what might be going wrong?

For context, I'm using my own data to make a visualization of an individual animal's movements that show movement to the same breeding area year over year.

I expect the points from my df to show up on the map extent but nothing shows up.

Map extent it gives me:
xmin ymin xmax ymax
-93.10445 30.96946 -93.00416 31.04072

map_bbox25 <- map_extent25
map_bbox26 <- map_extent26
map_bbox25 <- c (left=-93.2, bottom=30.9, right= -92.9, top=31.1)
map_bbox26 <- c (left=-93.2, bottom=30.9, right= -92.9, top=31.1)

Map extent it displays:
X: -95.8 to -95.0
Y: 29.4 to 30.0

Here is the entire code I'm working with:

#Install/load needed packages.
install.packages("sf")
#install.packages("terra")
install.packages("gifski")
install.packages("magick")
install.packages("png")
install.packages("gganimate")
install.packages("ggmap")
install.packages("track2KBA")
library(sf)
library(lubridate)
library(gifski)
library(magick)
library(png)
library(gganimate)
library(ggmap)
library(tidyverse)
#library(track2KBA)

#Load bird's data.
tracking_data <- read_csv("C:/Users/PRyan/OneDrive - LSU AgCenter/Desktop/2495F Series.csv")
view(tracking_data)

#Look at data.
#Create POSIXct column.
tracking_data$GPSTime <- as.POSIXct(paste(tracking_data$CST.DATE, tracking_data$CST.TIME), format="%m/%d/%Y %H:%M:%S")
tracking_data$Month <- format(tracking_data$GPSTime, "%m")
tracking_data$hr <- as.numeric(format(tracking_data$GPSTime, "%H"))
tracking_data$min <- as.numeric(format(tracking_data$GPSTime, "%M"))
tracking_data <- subset(tracking_data, min<5|min>55)
view(tracking_data)
str(tracking_data)
unique(tracking_data$ID)
#How many years of data?
track_years <-  year(tracking_data$GPSTime) 
unique(track_years)

#Organize...
#Add a column with the year information to your dataset, then select only the rows from one particular year.
tracking_data <-  as.data.frame(tracking_data)%>%
  mutate(year = year(GPSTime)) 
year_2025_df  <- tracking_data %>%
  filter(year == 2025)
View(year_2025_df)
year_2026_df  <- tracking_data %>%
  filter(year == 2026)
View(year_2026_df)
#Make sure your date&time column are in a POSIXct format.
year_2025_df$datetime <- as.POSIXct(paste(year_2025_df$CST.DATE, year_2025_df$CST.TIME), format="%m/%d/%Y %H:%M:%S")
View(year_2025_df)
year_2026_df$datetime <- as.POSIXct(paste(year_2026_df$CST.DATE, year_2026_df$CST.TIME), format="%m/%d/%Y %H:%M:%S")
View(year_2026_df)
#Make sure your data is in the correct order, organise by bird ID then by date & time.
tracks25_df<- year_2025_df%>%
  group_by(ID,
           datetime)
tracks26_df<- year_2026_df%>%
  group_by(ID,
           datetime)
View(year_2025_df)
View(year_2026_df)

#Map Data.
#Convert your data into an ‘sf’ object and get the extent for your map.
trackssf25 <- st_as_sf(tracks25_df, coords = c("Longitude","Latitude"), crs = 4326)
View(trackssf25)
map_extent25<-st_bbox(trackssf25)
View(map_extent25)
trackssf26 <- st_as_sf(tracks26_df, coords = c("Longitude","Latitude"), crs = 4326)
View(trackssf26)
map_extent26<-st_bbox(trackssf26)
View(map_extent26)
#Convert to a dataframe. Create a dataframe from your spatial object, keeping relevant columns for your animation. Get co-ordinates from your sf object.
tracksgeo25 <- st_coordinates(trackssf25)
View(tracksgeo25)
tracksgeo26 <- st_coordinates(trackssf26)
View(tracksgeo26)
#Convert to data frame and rename Latitude & Longitude columns.
tracksgeo25 <- as.data.frame(tracksgeo25)
colnames(tracksgeo25) <- c("X", "Y")
View(tracksgeo25)
tracksgeo26 <- as.data.frame(tracksgeo26)
colnames(tracksgeo26) <- c("X", "Y")
View(tracksgeo26)
#Include relevant columns and make sure each is in the correct format (POSIXct for date and time, a factor for bird ids, as a date for date information).
tracksgeo25$id <- as.factor(tracks25_df$ID)
tracksgeo25$date_time <- as.POSIXct(tracks25_df$datetime, format="%Y-%m-%d %H:%M:%S")
head(tracks25_df, 3)
View(tracksgeo25)

tracksgeo26$id <- as.factor(tracks26_df$ID)
tracksgeo26$date_time <- as.POSIXct(tracks26_df$datetime, format="%Y-%m-%d %H:%M:%S")
head(tracks26_df, 3)
View(tracksgeo26)

tracksgeo25$date <- as.Date(tracks25_df$datetime)
tracksgeo26$date <- as.Date(tracks26_df$datetime)
View(tracksgeo25)
View(tracksgeo26)
#Create Basemap. Here you will create a basemap for your animation output & static maps using ggmap. For this step you will need to register on Stadia maps, directions for this can be found here. Using your map extent from earlier, create a basemap within the bounds of your tracking data.
print(map_extent25)
print(map_extent26)
#I round up/down the map_extent values to create a bbox that is just slightly bigger that the are covered by the tracks.
map_bbox25 <- map_extent25
map_bbox26 <- map_extent26
map_bbox25 <- c (left=-93.2, bottom=30.9, right= -92.9, top=31.1)
map_bbox26 <- c (left=-93.2, bottom=30.9, right= -92.9, top=31.1)
register_stadiamaps("456b242d-a8e8-462d-a11c-c4e654db7553", write = FALSE)
mybasemap25 <- get_stadiamap(bbox25 = map_bbox, zoom = 1)
mybasemap26 <- get_stadiamap(bbox26 = map_bbox, zoom = 1)
#Now, plot your basemap.
ggmap(mybasemap25)
ggmap(mybasemap26)
#Plot your seabird tracks on your basemap
#Here you will create a static map of the bird tracks which you can then animate using ggplot. First, you need to plot your track data points onto your ggmap basemap. Here we will group by id (as well as facet wrap with id values) & the point colours are based on bird ID. However, you can use other values for grouping or colours, depending on your dataset and what you are looking at.
mymap.paths25 <- ggmap(mybasemap25) + 
  geom_point(data = tracksgeo25, aes(x = X, y = Y, colour = id)) +
  geom_path(data = tracksgeo25, aes(x = X, y = Y, colour = id, group=id)) +
  labs(x = "longitude", y = "latitude") +
  scale_colour_manual(name = "Bird ID",
                      values = rainbow(length(unique(tracksgeo25$id))),
                      breaks = unique(tracksgeo25$id)) + 
  theme(legend.position = "bottom") +
  facet_wrap(~id)

mymap.paths26 <- ggmap(mybasemap26) + 
  geom_point(data = tracksgeo26, aes(x = X, y = Y, colour = id)) +
  geom_path(data = tracksgeo26, aes(x = X, y = Y, colour = id, group=id)) +
  labs(x = "longitude", y = "latitude") +
  scale_colour_manual(name = "Bird ID",
                      values = rainbow(length(unique(tracksgeo26$id))),
                      breaks = unique(tracksgeo26$id)) + 
  theme(legend.position = "bottom") +
  facet_wrap(~id)
#Now, plot your static map of the tracks from 2025/2026.
plot(mymap.paths25)
plot(mymap.paths26)
animation rstudio gis gif ggmap