6 GLORYS Gridded Sea Bottom Temperature

Data Type: Gridded Data

Spatial Scope: Northwest Atlantic

Duration: 2020-2025

Source: CMEMS Global Ocean Physics Reanalysis

6.1 Introduction to Indicator

The GLORYS12V1 dataset is a product of the Copernicus Marine Environment Monitoring Service (CMEMS), providing spatiotemporal modeled estimates of environmental data for global oceans at 1/12° horizontal resolution and 50 vertical levels (Copernicus Marine Service 2023). Here, we use the bottom temperature estimate for the Northwest Atlantic, encompassing the Scotian Shelf region.

GLORYS bottom temperature estimates are generated using a numerical ocean model with assimilated satellite and in-situ observations, but see Chapter 5 for summarized empirical temperature measurements.

6.2 View Data


library(terra)
library(plotly)

# prepare sf shapes as coordinates
# NAFO regions
#sf <- readRDS("data/derived_data/azmp_area.rds") %>%
#  filter(area %in% c("4X","4Vn","4Vs","4W")) %>%
#  inner_join(global_cols2 %>% rename("area" = "region"))
#sf <- sf %>% st_transform(crs = crs(r_stack))
#sf_coords <- st_coordinates(st_cast(sf, "MULTILINESTRING") ) %>%
#  as.data.frame() %>% 
#  split(.,f = .$L2) %>%
#  purrr::map(.x = .,
#             .f = ~.x %>% rbind(c(NA,NA,NA,NA))) 
#

sf <- readRDS("data/derived_data/nafo_regions_correct.rds") %>%
  filter(region %in% c("4X","4Vn","4Vs","4W")) %>%
  inner_join(global_cols2) %>%
  rename(area = region)
sf <- sf %>% st_buffer(-.05)
sf <- sf %>% st_transform(crs = crs(r_stack)) 
# add NA after multipolygons so that plotly draws lines correctly
sf_coords <- st_coordinates(st_cast(sf, "MULTILINESTRING") ) %>%
  as.data.frame() %>% 
  split(.,f = interaction(.$L2,.$L1), drop = T) %>%
  purrr::map(.x = .,
             .f = ~.x %>% rbind(c(NA,NA,NA,NA))) 
# bind back together by region
name_ids <- sub("\\..*$", "",  names(sf_coords))
grouped <- split(sf_coords, name_ids)
grouped <- purrr::map(.x = grouped, 
                      .f = ~.x %>% bind_rows)

data("coastline")
coast_coords <- st_coordinates(coastline) %>%
    as.data.frame() %>% 
  split(.,f = interaction(.$L1,.$L2,.$L3, drop = T)) %>% 
  purrr::map(.x = .,
             .f = ~.x %>% rbind(c(NA,NA,NA,NA,NA))) %>%
  bind_rows()   


times <- names(r_stack)

# consistent color scale
zmin <- range(values(r_stack), na.rm = TRUE)[1]
zmax <- range(values(r_stack), na.rm = TRUE)[2]

x_vals <- xFromCol(r_stack, 1:ncol(r_stack))
y_vals <- yFromRow(r_stack, 1:nrow(r_stack))
ext <- ext(r_stack)

# Base plot
p <- plot_ly(
  x = x_vals, y = y_vals,
  z =as.matrix(r_stack[[1]], wide = TRUE),
  type = "heatmap",
  colorscale = "YlGnBu",
  hoverinfo = "none",
  colorbar = list(title = "Bottom<br>Temperature<br>(°C)"),
  zmin = zmin, zmax = zmax,
  showscale = TRUE
)

# add polygons
p <- p %>%
    add_polygons(
    x = coast_coords[,1],
    y = coast_coords[,2],
    fillcolor = "#dcdedc",
    showlegend = F,
    line = list(color = "black", width= .2),
    hoverinfo = "none",
    inherit = FALSE
  ) %>% 
  add_paths(x = grouped[[1]][,1],
            y = grouped[[1]][,2],
            line = list(color = unique(sf$color[1]),
                        width = 3),
            hoverinfo = "none",
            inherit = F,
            name = unique(sf$area[1])) %>%
    add_paths(x = grouped[[2]][,1],
            y = grouped[[2]][,2],
            line = list(color = unique(sf$color[2]),
                        width = 3),
            hoverinfo = "none",
            inherit = F,
            name = unique(sf$area[2])) %>%
    add_paths(x = grouped[[3]][,1],
            y = grouped[[3]][,2],
            line = list(color = unique(sf$color[3]),
                        width = 3),
            hoverinfo = "none",
            inherit = F,
            name = unique(sf$area[3])) %>%
    add_paths(x = grouped[[4]][,1],
            y = grouped[[4]][,2],
            line = list(color = unique(sf$color[4]),
                        width = 3),
            hoverinfo = "none",
            inherit = F,
            name = unique(sf$area[4]))


# loop through raster layers to make frames
frames <- purrr::map(
  .x = c(1:nlyr(r_stack)),
  .f = ~list(
    name = times[.x],
    data = list(list(
      z = as.matrix(r_stack[[.x]], wide = TRUE),
      type = "heatmap",
      zmin = zmin,
      zmax = zmax,
      hoverinfo = "none"
    ))
  )
)

# add frames to map
p$x$frames <- frames

# make animation list
steps <- purrr::map(
  .x = c(1:nlyr(r_stack)),
  .f = ~list(
    method = "animate",
    label = times[.x],
    args = list(
      list(times[.x]),
      list(
        mode = "immediate",
        frame = list(duration = 0, redraw = T),
        transition = list(duration = 0)
      )
    )
  )
)

# Slider steps (scrub)
steps <- lapply(seq_along(times), function(i) {
  list(
    method = "animate",
    label  = times[i],
    args   = list(
      list(times[i]),
      list(
        mode = "immediate",
        frame = list(duration = 0, redraw = TRUE),
        transition = list(duration = 0)
      )
    )
  )
})

# Layout + aspect lock + slider + play/pause
p <- p %>%
  layout(
    xaxis = list(
      title = "",
      showgrid = FALSE, zeroline = FALSE,
      range = c(xmin(ext), xmax(ext)),
      constrain = "domain"
    ),
    yaxis = list(
      title = "",
      showgrid = FALSE, zeroline = FALSE,
      range = c(ymin(ext), ymax(ext)),
      scaleanchor = "x",
      scaleratio = 1.5
    ),
    margin = list(l = 0, r = 0, t = 50, b = 70),

    sliders = list(list(
      active = 0,
      y = -.05,
      currentvalue = list(prefix = "Time: "),
      pad = list(t = 10),
      steps = steps
    )),

    updatemenus = list(list(
      type = "buttons",
      direction = "left",
      x = 0.02, y = 1.15,
      xanchor = "left", yanchor = "top",
      pad = list(r = 10, t = 0),
      buttons = list(
        # PLAY: explicitly animate through *all frame names*
        list(
          label = "Play",
          method = "animate",
          args = list(
            as.list(times),
            list(
              mode = "immediate",
              fromcurrent = TRUE,
              frame = list(duration = 250, redraw = TRUE),
              transition = list(duration = 0)
            )
          )
        ),
        # PAUSE
        list(
          label = "Pause",
          method = "animate",
          args = list(
            list(NULL),
            list(
              mode = "immediate",
              frame = list(duration = 0, redraw = FALSE),
              transition = list(duration = 0)
            )
          )
        )
      )
    ))
  )

p %>% config(displayModeBar = F)

Figure 6.1: GLORYS bottom temperature data for Scotian Shelf region; 2020-2025. Use pause and play button or slider bar to filter through month/years, and click legend to isolate target NAFO divisions.

6.4 Relevance to Research and Stock Assessments

Sea bottom temperature can strongly affect the populations, distribtuions, and productivity of marine species. See Chapter 5 for an overview of known effects in Atlantic Canada.

6.5 Variable Definitions

GLORYS bottom temperature is stored as a spatial dataframe in marea. See variable names and definitions in the table below (Table 6.2)

Table 6.2: Column names and definitions in the glorys bottom temperature dataset.
variable description unit
geometry Spatial polygon denoting the boundaries of 12° grid cells Spatial Polygon
time_descriptor Year and month of modeled value
value Modeled sea bottom temperature °C
year Year of modeled value
month Month of modeled value

6.6 Additional Data

Data in the GLORYS Bottom Temperature dataset are gridded with no regional groupings. Summary values displayed on this page were generated, not explicitly provided in the marea package.

6.7 Get the Data

library(marea)
data('glorys_bottom_temperature')
plot(glorys_bottom_temperature, style = "fill")

References

Copernicus Marine Service. 2023. “Global Ocean Physics Reanalysis (GLOBAL_MULTIYEAR_PHY_001_030).” https://data.marine.copernicus.eu/product/GLOBAL_MULTIYEAR_PHY_001_030/description.