library(here)
library(tidyverse)
library(stringr)
library(sf)
library(ncdf4)
library(marmap)
library(tidyterra)
library(ggnewscale)
library(gganimate)
library(lubridate)
Day 22 Movement
Re-create this image
Today’s goal is to recreate the ARGO float animated image from this blog post: annimate oceanographic data by Masumbuko Semba GitHub
I ended up using more of this code: @HansenDJohnson https://hansenjohnson.org/post/bathymetric-maps-in-r/ and @geokaramanis https://github.com/gkaramanis/30DayMapChallenge/tree/main/2022/07-raster-earth
This will allow me to practice some new skills:
- ARGO float data. I have never worked with that.
- Learn to process netCDF file in R. It’s been awhile since I have done that.
- {gganimate} to animate plots
- Use the {marmap} R package for oceanographic data
Set-up
Download the ARGO data
I went here and downloaded an ARGO float netCDF for a float in the Black Sea. https://dataselection.euro-argo.eu/
<- here::here("content", "data", "GL_PR_PF_6903766.nc")
ncfile <- ncdf4::nc_open(ncfile) argo
Figure out the names of things. Sadly this isn’t a proper ARGO file so oce:read.argo()
doesn’t work.
names(argo$var)
[1] "TIME_QC" "POSITION_QC"
[3] "DC_REFERENCE" "DIRECTION"
[5] "VERTICAL_SAMPLING_SCHEME" "PRES"
[7] "PRES_QC" "TEMP"
[9] "TEMP_QC" "PSAL"
[11] "PSAL_QC"
names(argo$dim)
[1] "TIME" "DEPTH" "LATITUDE" "LONGITUDE" "POSITION" "STRING32"
[7] "STRING256"
A bit of poking reveals that the ARGO float data is from 2 sampling schemes: one at the surface and the other that is sampling as the flow goes down. I’ll use just the data from the “Primary sampling” at the surface.
<- ncdf4::ncvar_get(argo, "VERTICAL_SAMPLING_SCHEME")
a <- stringr::str_detect(a, "Primary sampling")
good 1:3] a[
[1] "Primary sampling: averaged [10 sec sampling 1 dbar average from surface to 100 dbar; 10 sec sampling 2 dbar average from 100 dbar to 500 dbar; 10 sec sampling 5 dbar average from 500 dbar to 1000 dbar]"
[2] "Primary sampling: averaged [10 sec sampling 5 dbar average from 2000 dbar to 500 dbar; 10 sec sampling 2 dbar average from 500 dbar to 100 dbar; 10 sec sampling 1 dbar average from 100 dbar to 2.4 dbar]"
[3] "Near-surface sampling: averaged unpumped [10 sec sampling 1 dbar average from 2.4 dbar to surface]"
Next I notice that the time is in julian days so I will need to convert that. There are a few ways to convert julian to date/time. Making the origin date a POSIXlt date object and adding on the seconds is an easy way.
# print(argo) and you'll see the ref time
<- as.POSIXlt("1950-01-01") to
<- tibble(
argo_df time = ncvar_get(argo, "TIME"),
lon = ncvar_get(argo, "LONGITUDE"),
lat = ncvar_get(argo, "LATITUDE"),
temp = ncvar_get(argo, "TEMP")[1,],
psal = ncvar_get(argo, "PSAL")[1,]
%>% subset(good) %>%
) mutate(date = to+time*60*60*24) %>% # need to convert time to secs
mutate(qtr = as.character(quarter(date)))
Black Sea
Using https://www.latlong.net/, I grabbed box coordinates.
<- c(39, 47)
y <- c(26, 44) x
Make the bathymetry plot
Get bathymetry.
<- marmap::getNOAA.bathy(x[1], x[2], y[1], y[2], resolution = 3) bathy
Querying NOAA database ...
This may take seconds to minutes, depending on grid size
Building bathy matrix ...
<- marmap::fortify.bathy(bathy) bathy_df
autoplot.bathy(bathy, geom=c("tile","contour")) +
scale_fill_gradient2(low="dodgerblue4", mid="gainsboro", high="darkgreen")
Map a map with the ARGO data added.
<- ggplot() +
basemap # water raster
geom_raster(data = bathy_df %>% filter(z < 0), aes(x, y, fill = z), show.legend=FALSE) +
scale_fill_hypso_c("etopo1_bathy") +
# add contours
geom_contour(data = bathy_df %>% filter(z < 0),
aes(x=x, y=y, z=z),
breaks=c(-100),
linewidth=c(0.3),
colour="grey") +
geom_contour(data = bathy_df %>% filter(z < 0),
aes(x=x, y=y, z=z),
breaks=c(-500, -1000, -1500, -2000),
linewidth=c(0.3),
colour="white") +
new_scale_fill() +
# Add argo points
geom_point(data = argo_df, aes(x = lon, y = lat, color = temp), size=3) +
scale_colour_steps2(low = "blue", mid = "white", high = "red",
midpoint = mean(argo_df$temp), name="temperature (C)") +
new_scale_fill() +
# land raster
geom_raster(data = bathy_df %>% filter(z >= 0), aes(x, y, fill = z), show.legend=FALSE) +
scale_fill_hypso_c("gmt_globe_hypso") +
theme_void() +
theme(
legend.position = "bottom"
+
) ggtitle("An Argo bouy in the Black Sea")
basemap
## map the location
<- basemap +
argo.animate geom_label(
data = argo_df %>% slice(seq(1,dim(argo_df)[1],14)),
aes(label = format(date, "%b %Y")), x=35, y=43)+
transition_time(date)+
ease_aes("sine-in-out")+
shadow_mark()
::animate(argo.animate) gganimate
Save
::anim_save(here::here("content", "argo.gif")) gganimate