# load_all() # for developers
library(pacea) # for users
library(dplyr)
library(tibble) # Else prints all of a tibble
library(ggplot2)In pacea we include daily average sea surface temperature (SST) that we have calculated from two-minute measurements from 19 buoys in Canadian Pacific waters, yielding over 200,000 daily means. Data are from Environment and Climate Change Canada, and Fisheries and Oceans Canada. The earliest data are from September 1987, and 18 buoys were still providing data as of August 2026.
See the buoys_vignette
and the help file ?buoy_sst for background concerning the
calculated daily mean sea surface temperatures and associated simple
plotting functions in pacea. Here we focus on constructing climatologies
and subsequent anomalies, to plot in a standardised way.
The locations of the buoys are:
If you want to quickly get a sense of current temperatures (and also across the wider northeast Pacific Ocean), check out Andrea Hilborn et al.’s Pacific_SST_Monitoring website. This complements pacea, which is suited for doing specific plots and analyses defined by the user.
We can easily calculate a climatology (by month) and subsequent anomalies for each buoy, and plot results:
The plot’s title describes that this plot is for the anomalies in April (the default) for all buoys, and the climatology was 1991-2020 where available. Buoys are arranged in a roughly north-to-south order (see map). So each square gives the SST anomaly for that buoy for April of that year. Empty (white) squares indicate not enough data available for that particular calculation.
The figure clearly shows that April 2015 and April 2016 were warmer than usual for April, for every buoy (with those years having the warmest two Aprils for almost every buoy). The bottom three buoys clearly have limited data; in particular the anomalies in 2020 for both Entrance English Bay and South Georgia Strait are 0, because the climatology for 1991-2020 only includes the value for 2020.
To show the actual monthly average SST’s (rather than anomalies), again for the default month of April:
Here you can roughly see the water getting warmer from north to south,
noting that the three “NOMAD” buoys are much further offshore than the
others, and look slightly cooler.
If you specify a buoy, you get the monthly anomalies across the years (again with an automated title), with months running from top to bottom:
You can check that the April 2016 high anomaly matches that shown in the first anomaly plot shown above.
You can specify a single month (the default being “4” for April); here is December:
Interestingly, in 2023 the December anomalies are all positive, whereas in the first anomaly plot above the April anomalies are all negative (for the available buoys in each case). Discuss. (We may use this example in future vignettes for future plots; stay tuned).
If you specify multiple consecutive months (e.g. 4:6),
then the plot shows the anomalies averaged over those months (and the
title is automatically correct):
The eagle-eyed among you will have spotted that the S. Georgia Strait
buoy does not appear on this plot (it was second from bottom in the
previous plots). We will come back to this later (briefly, the plot
requires every specified month in months to have an anomaly
available, else it shows a blank).
And if you want a wintertime-ish (not strictly ‘winter’) index that includes December, that can be done:
As stated in the title, the year on the x-axis is the year of the January.
If you specify months and a single buoy, the anomalies
for those months are all shown individually:
This plot can be used as a check to see what anomalies are available (if you are only interested in a particular buoy). It also shows explicitly that Dec-Mar is missing at least one month in 1993 (i.e. Dec 1992 - Mar 1993) and 1994, but has all four months available for 1995. That is why in the plot above that one, “Halibut Bank” has no anomaly shown for 1993 or 1994, but does for 1995.
Setting return_results = TRUE returns a list containing
the plot and then the results used for the plot (and also automatically
shows the plot). Repeating the previous plot with this setting:
res <- plot(all_buoys_anomalies,
months = c(12, 1, 2, 3),
stn_id = "Halibut Bank",
return_results = TRUE) res$results
#> # A tibble: 124 × 9
#> stn_id year month sst_mean sst_n sst_anomaly month_as_factor sst_plot_value
#> <fct> <dbl> <dbl> <dbl> <int> <dbl> <fct> <dbl>
#> 1 C46146 1992 12 7.56 26 0.152 Dec 0.152
#> 2 C46146 1993 2 6.82 27 -0.0682 Feb -0.0682
#> 3 C46146 1993 3 7.89 30 0.0577 Mar 0.0577
#> 4 C46146 1993 12 7.65 31 0.244 Dec 0.244
#> 5 C46146 1994 1 7.61 24 0.797 Jan 0.797
#> 6 C46146 1994 12 7.24 20 -0.165 Dec -0.165
#> 7 C46146 1995 1 6.56 17 -0.247 Jan -0.247
#> 8 C46146 1995 2 7.03 18 0.142 Feb 0.142
#> 9 C46146 1995 3 7.91 26 0.0768 Mar 0.0768
#> 10 C46146 1996 1 6.69 31 -0.118 Jan -0.118
#> # ℹ 114 more rows
#> # ℹ 1 more variable: label <chr>So res is a list (res$plot will show the
above plot again), and res$results is a tibble that
includes the values in the plot, as sst_plot_value and then
label for the rounded values that are shown numerically.
You can then use these for analyses if desired.
That tibble contains results that depend on options used in the
plotting. But we will now examine the full results generated at the
start in the all_buoys_anomalies object.
At the beginning we ran
which we have plotted using various options. We now examine
all_buoys_anomalies in detail:
all_buoys_anomalies
#> $climatology
#> # A tibble: 228 × 5
#> stn_id month clim_sst_mean clim_sst_sd clim_sst_n
#> <fct> <dbl> <dbl> <dbl> <int>
#> 1 C46184 1 6.24 0.913 718
#> 2 C46184 2 5.82 0.864 623
#> 3 C46184 3 5.65 0.849 692
#> 4 C46184 4 6.13 0.821 696
#> 5 C46184 5 7.52 1.21 658
#> 6 C46184 6 10.0 1.41 758
#> 7 C46184 7 12.5 1.38 839
#> 8 C46184 8 14.0 1.16 753
#> 9 C46184 9 13.5 1.23 727
#> 10 C46184 10 11.3 1.23 730
#> # ℹ 218 more rows
#>
#> $anomalies
#> # A tibble: 7,341 × 6
#> stn_id year month sst_mean sst_n sst_anomaly
#> <fct> <dbl> <dbl> <dbl> <int> <dbl>
#> 1 C46184 1987 9 NA 0 NA
#> 2 C46184 1987 10 10.1 29 -1.16
#> 3 C46184 1987 11 NA 0 NA
#> 4 C46184 1987 12 NA 0 NA
#> 5 C46184 1988 1 NA 0 NA
#> 6 C46184 1988 2 4.57 24 -1.25
#> 7 C46184 1988 3 4.33 27 -1.32
#> 8 C46184 1988 4 NA 0 NA
#> 9 C46184 1988 5 6.18 31 -1.34
#> 10 C46184 1988 6 7.97 22 -2.04
#> # ℹ 7,331 more rows
#>
#> $climatology_years
#> [1] 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005
#> [16] 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020
#>
#> $climatology_time
#> [1] "month"
#>
#> attr(,"class")
#> [1] "pacea_buoy_anomalies_list" "list"This is a list object, with $climatology giving, for
each buoy and month, a mean SST (clim_sst_mean), standard
deviation (clim_sst_sd), and sample size
(clim_sst_n) of the values used for that buoy-month
combination. The default for calculate_anomalies() creates
the monthly climatology for each buoy based on the years 1991-2020
(details of other arguments will be investigated later).
The $anomalies tibble gives, for each buoy-year-month
combination, the anomaly for that month compared to the climatology. The
first buoy shown is “C46184” which is the North NOMAD buoy. For October
1987 the mean SST was 10.1 degC (sst_mean), which was
calculated from 29 days (sst_n) in that month. The
resulting anomaly from the climatology is -1.16
(sst_anomaly). This can be manually checked – the
climatology for buoy C46184 in October is a mean SST of 11.3 (the top
tibble), the mean SST in October 1987 was 10.1, which is -1.16 less
(sst_anomaly). This should help you understand how
calculations are done.
So the same calculations are done for all buoy-year-month combinations. There happen to be a few NA’s early on in the data for this buoy (more on that later).
The vector $climatology_years gives the years prescribed
for the climatology in the calculate_anomalies() call, for
which the default is 1991:2020.
The attribute shown (under attr(, "class")) given just
tells R to use our customised plotting function on these results, which
is automatically called with plot().
The calculate_anomalies(buoy_sst) uses the function
calculate_anomalies.pacea_buoy(buoy_sst), which has further
arguments that users can tweak. See
?calculate_anomalies.pacea_buoy(buoy_sst) for details, but
briefly these allow users to change:
We (Elise Keppel and Andy) pragmatically decided on requiring 15 days (roughly half) of daily SST within a month, and a maximum consecutive number of missing days of 6. This avoids having, say, 15 days of data but all at the beginning of the month – they need to be somewhat spread out. These are the defaults, but can be changed to any number.
The resulting plot(all_buoys_anomalies) uses
plot.pacea_buoy_anomalies_list(all_buoys_anomalies), which
also has arguments that users can tweak. See
?plot.pacea_buoy_anomalies_list for details, but briefly
these allow users to change:
Middle NOMAD) or the stn_id
(e.g. C46004), by setting use_stn_id_name to
TRUE or FALSE, respectively.sst_plot = "mean" for absolute
SST rather than anomalies, or sst_plot = "count" to check
how many days of data are available (see example below); for the latter,
count_breaks adjusts the break points used for the colour
scale.months to compute an average anomaly, by changing
require_requested_months (see below).scale_limits.heatmap_colours.We suggest the following workflow if users want to tweak some of the defaults (explained in detail below):
create_anomalies() with a different
min_days_per_month value if desired, and maybe also
max_consecutive_missing_days.The sst_plot = "counts" setting shows how many daily
counts are available to calculate each anomaly over the defined period.
Say we want to look at the North NOMAD buoy over Dec-Feb, we would plot
the counts for those three months:
plot(all_buoys_anomalies,
stn_id = "East Dellwood Knolls",
sst_plot = "count",
months = c(12, 1, 2))
So every month here has SST values for at least 16 days. Say we wanted
to instead insist on having 25 days of values for each month, we could
plot the same figure with a different breaks in the colour scale (this
also changes the actual colour palette for some reason):
plot(all_buoys_anomalies,
stn_id = "East Dellwood Knolls",
sst_plot = "count",
months = c(12, 1, 2),
count_breaks = c(0, 25, 31))
which shows the months that would get dropped if we used the more
stringent criterion of 25 days per month. We can apply this criterion by
recalculating the climatology and anomalies:
all_buoys_anomalies_require_25_days <- calculate_anomalies(buoy_sst,
min_days_per_month = 25)
plot(all_buoys_anomalies_require_25_days,
stn_id = "East Dellwood Knolls",
months = c(12, 1, 2))
Plotting the same figure with the default criterion of 15 days for each
month, we can see the extra months that get calculated (e.g. Dec 1989,
Feb and Dec 1994):
The extreme case of using all available data would be
min_days_per_months = 0 and
max_consecutive_missing_days = 32 in
calculate_anomalies(), though this is not recommended (but
can be used to check the upper limit of how much data is available).
We can also change the number of required months for a plot that averages over multiple months. Above, we noted that the S. Georgia Strait buoy does not appear in this plot:
This is because it does not have a climatology for Jun therefore we
cannot do a mean climatology for Apr-Jun:
all_buoys_anomalies$climatology %>%
filter(stn_id == "C46303") %>%
a()
#> stn_id month clim_sst_mean clim_sst_sd clim_sst_n
#> 1 C46303 1 7.258448 0.6485600 28
#> 2 C46303 2 6.676682 0.5304471 29
#> 3 C46303 3 7.468842 0.5445882 31
#> 4 C46303 4 9.875364 1.0869259 30
#> 5 C46303 5 12.608609 1.3637622 31
#> 6 C46303 6 NA NA 0
#> 7 C46303 7 NA NA 0
#> 8 C46303 8 17.995327 0.9621684 30
#> 9 C46303 9 15.958602 1.6339430 30
#> 10 C46303 10 11.509418 1.5451591 59
#> 11 C46303 11 8.493295 0.8989438 60
#> 12 C46303 12 7.407808 0.6118972 62and the anomalies for 2022 (as an example) are:
all_buoys_anomalies$anomalies %>%
filter(year == 2022,
stn_id == "C46303") %>%
a()
#> stn_id year month sst_mean sst_n sst_anomaly
#> 1 C46303 2022 1 5.718514 25 -1.5399335
#> 2 C46303 2022 2 6.331062 26 -0.3456200
#> 3 C46303 2022 3 7.589869 31 0.1210265
#> 4 C46303 2022 4 9.117719 30 -0.7576448
#> 5 C46303 2022 5 11.449919 31 -1.1586901
#> 6 C46303 2022 6 14.067619 29 NA
#> 7 C46303 2022 7 17.680563 28 NA
#> 8 C46303 2022 8 19.550376 30 1.5550494
#> 9 C46303 2022 9 16.231981 29 0.2733790
#> 10 C46303 2022 10 13.307402 28 1.7979844
#> 11 C46303 2022 11 8.217504 28 -0.2757913
#> 12 C46303 2022 12 6.935964 20 -0.4718443where you can see that Jun and Jul have SST values, but no anomaly because there is no climatology for those months for this buoy (due to limited data, and the default climatology years of 1991-2020).
However, if we specify that we only require
require_requested_months = 2 months to be available to make
a climatology and anomalies for Apr-Jun
there are enough values, and so anomalies for this buoy can be
calculated, but beware that they are not truly anomalies that cover all
of Apr-Jun.
Given the huge number of options that users may wish to explore (many buoys, many years, many possible combinations of months), users may wish to relax or tighten the defaults, and have the power to do so.