Overview
Ocean reanalyses and models such as GLORYS12 provide temperature on a
4D grid (lon, lat, depth,
time), not just at the sea surface.
heatwave3 can compute climatologies and detect events
natively across a contiguous band of depth levels,
producing one 4D climatology/event NetCDF instead of per-level 3D
files.
Every chunk in this vignette runs against a tiny 2x2 pixel, 5
depth-level GLORYS12 fixture bundled with the package
(system.file("extdata/glorys_depth_test.nc", package = "heatwave3"))
– the same one used by the test suite – so that this vignette actually
compiles when the documentation is built. Everything shown works
identically on a full-resolution file with many more pixels and depth
levels; just substitute your own temp_file. The trade-off
of the small fixture is scale, not behaviour: with only 4 horizontal
pixels and 5 depth levels (0.49-5.08 m, all within the mixed layer),
don’t expect dramatic spatial or vertical structure in the figures
below.
library(heatwave3)
temp_file <- system.file("extdata/glorys_depth_test.nc", package = "heatwave3")
clim_period <- c("1993-01-01", "2019-12-31")Two ways to work across depth
Option A: per-level looping
Before depth_range existed, the only way to get
per-depth results was to run the ordinary 3D pipeline once per level,
squeezing to a single depth index each time with the existing
depth argument. This is still a legitimate, simple
approach: it can be run in parallel across depth and reuses the same
validated 3D code path as every other heatwave3 analysis.
n_depth <- 5L # number of depth levels in this fixture
depth_indices <- seq_len(n_depth) - 1L # depth= is a 0-based index: 0, 1, 2, 3, 4
purrr::walk(depth_indices, \(k) {
detect3(temp_file, name = file.path(tempdir(), paste0("mhw_z", k)),
climatologyPeriod = clim_period,
depth = k, category = TRUE, quiet = TRUE)
})#> Reading SST data from /tmp/RtmpxYwdBf/temp_libpath94004dd393d4/heatwave3/extdata/glorys_depth_test.nc...
#> Grid: 2 lon x 2 lat x 11688 time = 4 pixels
#> Computing climatology with 1 thread(s)...
#> 1/4 pixels (25%) 2/4 pixels (50%) 3/4 pixels (75%) 4/4 pixels (100%)
#> Writing climatology to /tmp/Rtmp9X0FXX/mhw_z0_clim.nc...
#> Done.
#> Reading climatology from /tmp/Rtmp9X0FXX/mhw_z0_clim.nc...
#> Reading SST data from /tmp/RtmpxYwdBf/temp_libpath94004dd393d4/heatwave3/extdata/glorys_depth_test.nc...
#> Grid: 2 lon x 2 lat x 11688 time = 4 pixels
#> Detecting events with 1 thread(s)...
#> 1/4 pixels (25%) 2/4 pixels (50%) 3/4 pixels (75%) 4/4 pixels (100%)
#> Found 316 events across 4 pixels
#> Writing events to /tmp/Rtmp9X0FXX/mhw_z0_events.nc...
#> Done.
#> Reading SST data from /tmp/RtmpxYwdBf/temp_libpath94004dd393d4/heatwave3/extdata/glorys_depth_test.nc...
#> Grid: 2 lon x 2 lat x 11688 time = 4 pixels
#> Computing climatology with 1 thread(s)...
#> 1/4 pixels (25%) 2/4 pixels (50%) 3/4 pixels (75%) 4/4 pixels (100%)
#> Writing climatology to /tmp/Rtmp9X0FXX/mhw_z1_clim.nc...
#> Done.
#> Reading climatology from /tmp/Rtmp9X0FXX/mhw_z1_clim.nc...
#> Reading SST data from /tmp/RtmpxYwdBf/temp_libpath94004dd393d4/heatwave3/extdata/glorys_depth_test.nc...
#> Grid: 2 lon x 2 lat x 11688 time = 4 pixels
#> Detecting events with 1 thread(s)...
#> 1/4 pixels (25%) 2/4 pixels (50%) 3/4 pixels (75%) 4/4 pixels (100%)
#> Found 323 events across 4 pixels
#> Writing events to /tmp/Rtmp9X0FXX/mhw_z1_events.nc...
#> Done.
#> Reading SST data from /tmp/RtmpxYwdBf/temp_libpath94004dd393d4/heatwave3/extdata/glorys_depth_test.nc...
#> Grid: 2 lon x 2 lat x 11688 time = 4 pixels
#> Computing climatology with 1 thread(s)...
#> 1/4 pixels (25%) 2/4 pixels (50%) 3/4 pixels (75%) 4/4 pixels (100%)
#> Writing climatology to /tmp/Rtmp9X0FXX/mhw_z2_clim.nc...
#> Done.
#> Reading climatology from /tmp/Rtmp9X0FXX/mhw_z2_clim.nc...
#> Reading SST data from /tmp/RtmpxYwdBf/temp_libpath94004dd393d4/heatwave3/extdata/glorys_depth_test.nc...
#> Grid: 2 lon x 2 lat x 11688 time = 4 pixels
#> Detecting events with 1 thread(s)...
#> 1/4 pixels (25%) 2/4 pixels (50%) 3/4 pixels (75%) 4/4 pixels (100%)
#> Found 323 events across 4 pixels
#> Writing events to /tmp/Rtmp9X0FXX/mhw_z2_events.nc...
#> Done.
#> Reading SST data from /tmp/RtmpxYwdBf/temp_libpath94004dd393d4/heatwave3/extdata/glorys_depth_test.nc...
#> Grid: 2 lon x 2 lat x 11688 time = 4 pixels
#> Computing climatology with 1 thread(s)...
#> 1/4 pixels (25%) 2/4 pixels (50%) 3/4 pixels (75%) 4/4 pixels (100%)
#> Writing climatology to /tmp/Rtmp9X0FXX/mhw_z3_clim.nc...
#> Done.
#> Reading climatology from /tmp/Rtmp9X0FXX/mhw_z3_clim.nc...
#> Reading SST data from /tmp/RtmpxYwdBf/temp_libpath94004dd393d4/heatwave3/extdata/glorys_depth_test.nc...
#> Grid: 2 lon x 2 lat x 11688 time = 4 pixels
#> Detecting events with 1 thread(s)...
#> 1/4 pixels (25%) 2/4 pixels (50%) 3/4 pixels (75%) 4/4 pixels (100%)
#> Found 326 events across 4 pixels
#> Writing events to /tmp/Rtmp9X0FXX/mhw_z3_events.nc...
#> Done.
#> Reading SST data from /tmp/RtmpxYwdBf/temp_libpath94004dd393d4/heatwave3/extdata/glorys_depth_test.nc...
#> Grid: 2 lon x 2 lat x 11688 time = 4 pixels
#> Computing climatology with 1 thread(s)...
#> 1/4 pixels (25%) 2/4 pixels (50%) 3/4 pixels (75%) 4/4 pixels (100%)
#> Writing climatology to /tmp/Rtmp9X0FXX/mhw_z4_clim.nc...
#> Done.
#> Reading climatology from /tmp/Rtmp9X0FXX/mhw_z4_clim.nc...
#> Reading SST data from /tmp/RtmpxYwdBf/temp_libpath94004dd393d4/heatwave3/extdata/glorys_depth_test.nc...
#> Grid: 2 lon x 2 lat x 11688 time = 4 pixels
#> Detecting events with 1 thread(s)...
#> 1/4 pixels (25%) 2/4 pixels (50%) 3/4 pixels (75%) 4/4 pixels (100%)
#> Found 326 events across 4 pixels
#> Writing events to /tmp/Rtmp9X0FXX/mhw_z4_events.nc...
#> Done.
The trade-off: this produces n_depth separate pairs of
_clim.nc/ _events.nc files, each with
n_depth-fold repeated I/O over the same lon/lat/time grid,
and there is no vertical linkage between levels (each is detected
completely independently, as if it were its own 3D dataset). For users
who just want “climatology and events at 20 m, 50 m, 100 m…” this may
already be enough – stack the files yourself downstream with
terra (R), xarray (python), or
CDO (bash).
Option B: native depth_range (recommended)
depth_range = c(min_depth, max_depth) (metres,
inclusive) tells ts2clm3() and detect3() to
read every depth level whose coordinate falls in that range and compute
an independent climatology/event table for every
(lon, lat, depth) triple, in one call
producing one 4D file. This avoids the repeated I/O and
per-level file bookkeeping of Option A above. The fixture’s 5 levels all
fall within 0-10 m:
stem <- file.path(tempdir(), "mhw4d")
clim_file <- ts2clm3(file_in = temp_file,
name = stem,
climatologyPeriod = clim_period,
depth_range = c(0, 10),
n_threads = 2)
#> Reading SST data from /tmp/RtmpxYwdBf/temp_libpath94004dd393d4/heatwave3/extdata/glorys_depth_test.nc...
#> Grid: 2 lon x 2 lat x 5 depth x 11688 time = 20 pixels
#> Computing climatology with 2 thread(s)...
#> 20/20 pixels (100%)
#> Writing climatology to /tmp/Rtmp9X0FXX/mhw4d_clim.nc...
#> Done.
#>
#> ------------------------------------------------------------------
#> Climatology written to: /tmp/Rtmp9X0FXX/mhw4d_clim.nc
#> Rows (long format): 7,320 grid: 2 lon x 2 lat
#>
#> Head:
#> lon lat doy seas thresh depth
#> 1 25.16667 -34.91667 1 24.4421 25.7957 0.494025
#> 2 25.16667 -34.91667 2 24.4798 25.8305 0.494025
#> 3 25.16667 -34.91667 3 24.5167 25.8673 0.494025
#> 4 25.16667 -34.91667 4 24.5528 25.9038 0.494025
#> 5 25.16667 -34.91667 5 24.5878 25.9396 0.494025
#>
#> Tail:
#> lon lat doy seas thresh depth
#> 7316 25.25 -34.83333 362 24.0087 25.4949 5.078224
#> 7317 25.25 -34.83333 363 24.0447 25.5349 5.078224
#> 7318 25.25 -34.83333 364 24.0814 25.5727 5.078224
#> 7319 25.25 -34.83333 365 24.1189 25.6097 5.078224
#> 7320 25.25 -34.83333 366 24.1567 25.6499 5.078224
#>
#> Summary:
#> ocean pixels (valid climatology): 4
#> seas: 20.98 to 25.55
#> thresh: 22 to 26.92
#>
#> Examine with hw3_export("/tmp/Rtmp9X0FXX/mhw4d_clim.nc", n = 20)
#> or export with hw3_export("/tmp/Rtmp9X0FXX/mhw4d_clim.nc", file_out = "out.csv") (.csv/.rds/.parquet)
#> ------------------------------------------------------------------detect_event3() needs no separate depth argument at all:
it reads the depth range straight back out of the climatology file it is
already loading, so climatology and event detection can never end up out
of sync about which levels they are comparing.
event_file <- detect_event3(file_in = temp_file,
name = stem,
category = TRUE,
n_threads = 2,
quiet = TRUE)
#> Reading climatology from /tmp/Rtmp9X0FXX/mhw4d_clim.nc...
#> Reading SST data from /tmp/RtmpxYwdBf/temp_libpath94004dd393d4/heatwave3/extdata/glorys_depth_test.nc...
#> Grid: 2 lon x 2 lat x 5 depth x 11688 time = 20 pixels
#> Detecting events with 2 thread(s)...
#> 20/20 pixels (100%)
#> Found 1614 events across 20 pixels
#> Writing events to /tmp/Rtmp9X0FXX/mhw4d_events.nc...
#> Done.Or as a single call via detect3():
detect3(file_in = temp_file,
name = stem,
climatologyPeriod = clim_period,
depth_range = c(0, 10),
category = TRUE,
n_threads = 2)
#> Reading SST data from /tmp/RtmpxYwdBf/temp_libpath94004dd393d4/heatwave3/extdata/glorys_depth_test.nc...
#> Grid: 2 lon x 2 lat x 5 depth x 11688 time = 20 pixels
#> Computing climatology with 2 thread(s)...
#> 20/20 pixels (100%)
#> Writing climatology to /tmp/Rtmp9X0FXX/mhw4d_clim.nc...
#> Done.
#>
#> ------------------------------------------------------------------
#> Climatology written to: /tmp/Rtmp9X0FXX/mhw4d_clim.nc
#> Rows (long format): 7,320 grid: 2 lon x 2 lat
#>
#> Head:
#> lon lat doy seas thresh depth
#> 1 25.16667 -34.91667 1 24.4421 25.7957 0.494025
#> 2 25.16667 -34.91667 2 24.4798 25.8305 0.494025
#> 3 25.16667 -34.91667 3 24.5167 25.8673 0.494025
#> 4 25.16667 -34.91667 4 24.5528 25.9038 0.494025
#> 5 25.16667 -34.91667 5 24.5878 25.9396 0.494025
#>
#> Tail:
#> lon lat doy seas thresh depth
#> 7316 25.25 -34.83333 362 24.0087 25.4949 5.078224
#> 7317 25.25 -34.83333 363 24.0447 25.5349 5.078224
#> 7318 25.25 -34.83333 364 24.0814 25.5727 5.078224
#> 7319 25.25 -34.83333 365 24.1189 25.6097 5.078224
#> 7320 25.25 -34.83333 366 24.1567 25.6499 5.078224
#>
#> Summary:
#> ocean pixels (valid climatology): 4
#> seas: 20.98 to 25.55
#> thresh: 22 to 26.92
#>
#> Examine with hw3_export("/tmp/Rtmp9X0FXX/mhw4d_clim.nc", n = 20)
#> or export with hw3_export("/tmp/Rtmp9X0FXX/mhw4d_clim.nc", file_out = "out.csv") (.csv/.rds/.parquet)
#> ------------------------------------------------------------------
#> Reading climatology from /tmp/Rtmp9X0FXX/mhw4d_clim.nc...
#> Reading SST data from /tmp/RtmpxYwdBf/temp_libpath94004dd393d4/heatwave3/extdata/glorys_depth_test.nc...
#> Grid: 2 lon x 2 lat x 5 depth x 11688 time = 20 pixels
#> Detecting events with 2 thread(s)...
#> 20/20 pixels (100%)
#> Found 1614 events across 20 pixels
#> Writing events to /tmp/Rtmp9X0FXX/mhw4d_events.nc...
#> Done.
#>
#> ------------------------------------------------------------------
#> Events written to: /tmp/Rtmp9X0FXX/mhw4d_events.nc
#> Rows (long format): 1,614
#>
#> Head:
#> lon lat pixel_index event_no date_start date_peak date_end
#> 1 25.16667 -34.91667 0 1 1996-01-21 1996-01-24 1996-01-26
#> 2 25.16667 -34.91667 0 2 1997-07-18 1997-07-21 1997-07-22
#> 3 25.16667 -34.91667 0 3 1997-10-03 1997-10-10 1997-10-12
#> 4 25.16667 -34.91667 0 4 1998-11-23 1998-11-27 1998-11-27
#> 5 25.16667 -34.91667 0 5 1999-05-09 1999-05-12 1999-05-15
#> duration intensity_mean intensity_max intensity_var intensity_cumulative
#> 1 6 1.5865 1.7736 0.1317 9.5189
#> 2 5 1.2510 1.5161 0.2516 6.2549
#> 3 10 1.2946 1.4676 0.1200 12.9463
#> 4 5 1.2410 1.4843 0.1530 6.2048
#> 5 7 1.4740 1.6994 0.1584 10.3179
#> intensity_mean_relThresh intensity_max_relThresh intensity_var_relThresh
#> 1 0.1453 0.3288 0.1244
#> 2 0.2992 0.5704 0.2586
#> 3 0.2006 0.3803 0.1188
#> 4 0.1795 0.4009 0.1383
#> 5 0.4610 0.6895 0.1601
#> intensity_cumulative_relThresh intensity_mean_abs intensity_max_abs
#> 1 0.8717 26.6664 26.8669
#> 2 1.4958 22.8343 23.0860
#> 3 2.0058 22.8490 23.0794
#> 4 0.8976 24.3392 24.6432
#> 5 3.2267 25.3127 25.5404
#> intensity_var_abs intensity_cumulative_abs rate_onset rate_decline depth
#> 1 0.1634 159.9986 0.0985 0.0729 0.494025
#> 2 0.2383 114.1717 0.1560 0.1805 0.494025
#> 3 0.1284 228.4898 0.0133 0.1407 0.494025
#> 4 0.1960 121.6961 0.0799 0.0000 0.494025
#> 5 0.1680 177.1892 0.0494 0.0851 0.494025
#> category p_moderate p_strong p_severe p_extreme season
#> 1 I Moderate 1 0.2276 0 0 Summer
#> 2 I Moderate 1 0.6032 0 0 Winter
#> 3 I Moderate 1 0.3498 0 0 Spring
#> 4 I Moderate 1 0.3700 0 0 Spring
#> 5 I Moderate 1 0.6828 0 0 Fall
#>
#> Tail:
#> lon lat pixel_index event_no date_start date_peak date_end
#> 1610 25.25 -34.83333 19 77 2024-06-23 2024-06-25 2024-07-01
#> 1611 25.25 -34.83333 19 78 2024-07-15 2024-07-19 2024-07-28
#> 1612 25.25 -34.83333 19 79 2024-08-07 2024-08-20 2024-09-03
#> 1613 25.25 -34.83333 19 80 2024-12-08 2024-12-08 2024-12-14
#> 1614 25.25 -34.83333 19 81 2024-12-18 2024-12-23 2024-12-29
#> duration intensity_mean intensity_max intensity_var intensity_cumulative
#> 1610 9 1.5018 1.6837 0.1564 13.5160
#> 1611 14 1.1989 1.6394 0.1932 16.7848
#> 1612 28 1.4304 2.3920 0.3483 40.0519
#> 1613 7 2.0314 2.4793 0.3988 14.2196
#> 1614 12 2.0886 2.3930 0.2649 25.0638
#> intensity_mean_relThresh intensity_max_relThresh intensity_var_relThresh
#> 1610 0.3836 0.5506 0.1543
#> 1611 0.2598 0.6808 0.1793
#> 1612 0.4680 1.4450 0.3469
#> 1613 0.8006 1.2799 0.4230
#> 1614 0.6494 0.9636 0.2617
#> intensity_cumulative_relThresh intensity_mean_abs intensity_max_abs
#> 1610 3.4525 23.4180 23.6375
#> 1611 3.6376 22.7199 23.1878
#> 1612 13.1050 22.5689 23.5094
#> 1613 5.6043 25.5093 25.8656
#> 1614 7.7930 25.9745 26.2589
#> intensity_var_abs intensity_cumulative_abs rate_onset rate_decline
#> 1610 0.1754 210.7624 0.1591 0.0695
#> 1611 0.2205 318.0784 0.1170 0.0720
#> 1612 0.3456 631.9298 0.0782 0.0736
#> 1613 0.3408 178.5654 0.0000 0.1790
#> 1614 0.2870 311.6935 0.1370 0.1078
#> depth category p_moderate p_strong p_severe p_extreme season
#> 1610 5.078224 I Moderate 1 0.4860 0.0000 0 Winter
#> 1611 5.078224 I Moderate 1 0.7102 0.0000 0 Winter
#> 1612 5.078224 II Strong 1 1.0000 0.5258 0 Winter
#> 1613 5.078224 II Strong 1 1.0000 0.0671 0 Summer
#> 1614 5.078224 I Moderate 1 0.6577 0.0000 0 Summer
#>
#> Summary:
#> events: 1614 pixels with events: 4
#> dates: 1996-01-21 to 2024-12-29
#> duration (days): 5 to 34
#> intensity_max: 0.9695 to 3.165
#> category: I Moderate=1531 II Strong=83
#>
#> Examine with hw3_export("/tmp/Rtmp9X0FXX/mhw4d_events.nc", n = 20)
#> or export with hw3_export("/tmp/Rtmp9X0FXX/mhw4d_events.nc", file_out = "out.csv") (.csv/.rds/.parquet)
#> ------------------------------------------------------------------Reading the depth-resolved output
hw3_export() surfaces a depth column
automatically whenever the source file is depth-resolved:
clim_df <- hw3_export(paste0(stem, "_clim.nc"))
event_df <- hw3_export(paste0(stem, "_events.nc"))
head(clim_df)#> lon lat doy seas thresh depth
#> 1 25.16667 -34.91667 1 24.4421 25.7957 0.494025
#> 2 25.16667 -34.91667 2 24.4798 25.8305 0.494025
#> 3 25.16667 -34.91667 3 24.5167 25.8673 0.494025
#> 4 25.16667 -34.91667 4 24.5528 25.9038 0.494025
#> 5 25.16667 -34.91667 5 24.5878 25.9396 0.494025
#> 6 25.16667 -34.91667 6 24.6215 25.9754 0.494025
#>
#> 0.49 1.54 2.65 3.82 5.08
#> 316 323 323 326 326
Because every (lon, lat, depth) triple gets its own
climatology, the seasonal cycle and threshold both flatten out with
depth – the surface has the largest seasonal amplitude and the highest
threshold, decaying as you move down through the mixed layer. This is
already visible directly from the exported climatology data frame, with
no new plotting functions required (the effect is subtle here since all
5 levels sit within the top 5 m; it’s more pronounced across a deeper
range on a real file):
library(ggplot2)
one_pixel <- subset(clim_df, lon == clim_df$lon[1] & lat == clim_df$lat[1])
ggplot(one_pixel, aes(doy, seas, colour = factor(round(depth, 1)))) +
geom_line(linewidth = 0.7) +
scale_colour_viridis_d(name = "depth (m)") +
labs(title = "Seasonal climatology by depth", x = "Day of year", y = "degC") +
theme_minimal(base_size = 11)
A depth-time Hovmoeller-style view of event intensity is also already
possible by building the plot directly from event_df,
without any new graphics functions:
one_pixel_events <- subset(event_df, lon == event_df$lon[1] & lat == event_df$lat[1])
ggplot(one_pixel_events, aes(x = date_peak, y = depth, fill = intensity_max)) +
geom_tile(height = 1) +
scale_fill_viridis_c(name = expression(I[max] ~ "(degC)"), option = "inferno") +
scale_y_reverse(name = "depth (m)") +
labs(title = "Event intensity by depth and peak date", x = NULL) +
theme_minimal(base_size = 11)
Depth-resolved event-line plots with geom_flame3() /
geom_lolli3()
The per-day product also carries a depth dimension now, so
daily = "also" works together with depth_range
– no separate depth argument needed here either, for the same reason
detect_event3() doesn’t need one:
detect3(file_in = temp_file,
name = stem,
climatologyPeriod = clim_period,
depth_range = c(0, 10),
category = TRUE,
daily = "also",
n_threads = 2)
#> Reading SST data from /tmp/RtmpxYwdBf/temp_libpath94004dd393d4/heatwave3/extdata/glorys_depth_test.nc...
#> Grid: 2 lon x 2 lat x 5 depth x 11688 time = 20 pixels
#> Computing climatology with 2 thread(s)...
#> 20/20 pixels (100%)
#> Writing climatology to /tmp/Rtmp9X0FXX/mhw4d_clim.nc...
#> Done.
#>
#> ------------------------------------------------------------------
#> Climatology written to: /tmp/Rtmp9X0FXX/mhw4d_clim.nc
#> Rows (long format): 7,320 grid: 2 lon x 2 lat
#>
#> Head:
#> lon lat doy seas thresh depth
#> 1 25.16667 -34.91667 1 24.4421 25.7957 0.494025
#> 2 25.16667 -34.91667 2 24.4798 25.8305 0.494025
#> 3 25.16667 -34.91667 3 24.5167 25.8673 0.494025
#> 4 25.16667 -34.91667 4 24.5528 25.9038 0.494025
#> 5 25.16667 -34.91667 5 24.5878 25.9396 0.494025
#>
#> Tail:
#> lon lat doy seas thresh depth
#> 7316 25.25 -34.83333 362 24.0087 25.4949 5.078224
#> 7317 25.25 -34.83333 363 24.0447 25.5349 5.078224
#> 7318 25.25 -34.83333 364 24.0814 25.5727 5.078224
#> 7319 25.25 -34.83333 365 24.1189 25.6097 5.078224
#> 7320 25.25 -34.83333 366 24.1567 25.6499 5.078224
#>
#> Summary:
#> ocean pixels (valid climatology): 4
#> seas: 20.98 to 25.55
#> thresh: 22 to 26.92
#>
#> Examine with hw3_export("/tmp/Rtmp9X0FXX/mhw4d_clim.nc", n = 20)
#> or export with hw3_export("/tmp/Rtmp9X0FXX/mhw4d_clim.nc", file_out = "out.csv") (.csv/.rds/.parquet)
#> ------------------------------------------------------------------
#> Reading climatology from /tmp/Rtmp9X0FXX/mhw4d_clim.nc...
#> Reading SST data from /tmp/RtmpxYwdBf/temp_libpath94004dd393d4/heatwave3/extdata/glorys_depth_test.nc...
#> Grid: 2 lon x 2 lat x 5 depth x 11688 time = 20 pixels
#> Detecting events with 2 thread(s)...
#> 20/20 pixels (100%)
#> Found 1614 events across 20 pixels
#> Writing per-day series to /tmp/Rtmp9X0FXX/mhw4d_events_daily.nc...
#> Done.
#> Writing events to /tmp/Rtmp9X0FXX/mhw4d_events.nc...
#> Done.
#>
#> ------------------------------------------------------------------
#> Events written to: /tmp/Rtmp9X0FXX/mhw4d_events.nc
#> Rows (long format): 1,614
#>
#> Head:
#> lon lat pixel_index event_no date_start date_peak date_end
#> 1 25.16667 -34.91667 0 1 1996-01-21 1996-01-24 1996-01-26
#> 2 25.16667 -34.91667 0 2 1997-07-18 1997-07-21 1997-07-22
#> 3 25.16667 -34.91667 0 3 1997-10-03 1997-10-10 1997-10-12
#> 4 25.16667 -34.91667 0 4 1998-11-23 1998-11-27 1998-11-27
#> 5 25.16667 -34.91667 0 5 1999-05-09 1999-05-12 1999-05-15
#> duration intensity_mean intensity_max intensity_var intensity_cumulative
#> 1 6 1.5865 1.7736 0.1317 9.5189
#> 2 5 1.2510 1.5161 0.2516 6.2549
#> 3 10 1.2946 1.4676 0.1200 12.9463
#> 4 5 1.2410 1.4843 0.1530 6.2048
#> 5 7 1.4740 1.6994 0.1584 10.3179
#> intensity_mean_relThresh intensity_max_relThresh intensity_var_relThresh
#> 1 0.1453 0.3288 0.1244
#> 2 0.2992 0.5704 0.2586
#> 3 0.2006 0.3803 0.1188
#> 4 0.1795 0.4009 0.1383
#> 5 0.4610 0.6895 0.1601
#> intensity_cumulative_relThresh intensity_mean_abs intensity_max_abs
#> 1 0.8717 26.6664 26.8669
#> 2 1.4958 22.8343 23.0860
#> 3 2.0058 22.8490 23.0794
#> 4 0.8976 24.3392 24.6432
#> 5 3.2267 25.3127 25.5404
#> intensity_var_abs intensity_cumulative_abs rate_onset rate_decline depth
#> 1 0.1634 159.9986 0.0985 0.0729 0.494025
#> 2 0.2383 114.1717 0.1560 0.1805 0.494025
#> 3 0.1284 228.4898 0.0133 0.1407 0.494025
#> 4 0.1960 121.6961 0.0799 0.0000 0.494025
#> 5 0.1680 177.1892 0.0494 0.0851 0.494025
#> category p_moderate p_strong p_severe p_extreme season
#> 1 I Moderate 1 0.2276 0 0 Summer
#> 2 I Moderate 1 0.6032 0 0 Winter
#> 3 I Moderate 1 0.3498 0 0 Spring
#> 4 I Moderate 1 0.3700 0 0 Spring
#> 5 I Moderate 1 0.6828 0 0 Fall
#>
#> Tail:
#> lon lat pixel_index event_no date_start date_peak date_end
#> 1610 25.25 -34.83333 18 79 2024-06-23 2024-06-25 2024-07-01
#> 1611 25.25 -34.83333 18 80 2024-07-15 2024-07-19 2024-07-28
#> 1612 25.25 -34.83333 18 81 2024-08-07 2024-08-20 2024-09-03
#> 1613 25.25 -34.83333 18 82 2024-12-08 2024-12-08 2024-12-14
#> 1614 25.25 -34.83333 18 83 2024-12-18 2024-12-23 2024-12-29
#> duration intensity_mean intensity_max intensity_var intensity_cumulative
#> 1610 9 1.5017 1.6836 0.1564 13.5150
#> 1611 14 1.1987 1.6393 0.1932 16.7822
#> 1612 28 1.4298 2.3913 0.3482 40.0337
#> 1613 7 2.0255 2.4800 0.4034 14.1785
#> 1614 12 2.0775 2.3796 0.2661 24.9299
#> intensity_mean_relThresh intensity_max_relThresh intensity_var_relThresh
#> 1610 0.3836 0.5506 0.1543
#> 1611 0.2597 0.6807 0.1793
#> 1612 0.4674 1.4444 0.3469
#> 1613 0.7981 1.2835 0.4274
#> 1614 0.6444 0.9559 0.2627
#> intensity_cumulative_relThresh intensity_mean_abs intensity_max_abs
#> 1610 3.4525 23.4180 23.6375
#> 1611 3.6362 22.7199 23.1878
#> 1612 13.0874 22.5690 23.5094
#> 1613 5.5866 25.5139 25.8759
#> 1614 7.7328 25.9767 26.2589
#> intensity_var_abs intensity_cumulative_abs rate_onset rate_decline
#> 1610 0.1754 210.7624 0.1591 0.0695
#> 1611 0.2205 318.0784 0.1170 0.0720
#> 1612 0.3456 631.9313 0.0781 0.0735
#> 1613 0.3446 178.5976 0.0000 0.1807
#> 1614 0.2882 311.7206 0.1368 0.1079
#> depth category p_moderate p_strong p_severe p_extreme season
#> 1610 3.819495 I Moderate 1 0.4860 0.0000 0 Winter
#> 1611 3.819495 I Moderate 1 0.7101 0.0000 0 Winter
#> 1612 3.819495 II Strong 1 1.0000 0.5254 0 Winter
#> 1613 3.819495 II Strong 1 1.0000 0.0727 0 Summer
#> 1614 3.819495 I Moderate 1 0.6553 0.0000 0 Summer
#>
#> Summary:
#> events: 1614 pixels with events: 4
#> dates: 1996-01-21 to 2024-12-29
#> duration (days): 5 to 34
#> intensity_max: 0.9695 to 3.165
#> category: I Moderate=1531 II Strong=83
#>
#> Examine with hw3_export("/tmp/Rtmp9X0FXX/mhw4d_events.nc", n = 20)
#> or export with hw3_export("/tmp/Rtmp9X0FXX/mhw4d_events.nc", file_out = "out.csv") (.csv/.rds/.parquet)
#> ------------------------------------------------------------------
#>
#> ------------------------------------------------------------------
#> Daily series written to: /tmp/Rtmp9X0FXX/mhw4d_events_daily.nc
#> Rows (long format): 233,760 grid: 2 lon x 2 lat
#>
#> Head:
#> lon lat t temp seas thresh intensity event
#> 1 25.16667 -34.91667 1993-01-01 25.30824 24.4421 25.7957 0.8661 FALSE
#> 2 25.16667 -34.91667 1993-01-02 25.82022 24.4798 25.8305 1.3404 FALSE
#> 3 25.16667 -34.91667 1993-01-03 25.55507 24.5167 25.8673 1.0384 FALSE
#> 4 25.16667 -34.91667 1993-01-04 25.36024 24.5528 25.9038 0.8074 FALSE
#> 5 25.16667 -34.91667 1993-01-05 25.50600 24.5878 25.9396 0.9182 FALSE
#> event_no category depth
#> 1 NA NA 0.494025
#> 2 NA NA 0.494025
#> 3 NA NA 0.494025
#> 4 NA NA 0.494025
#> 5 NA NA 0.494025
#>
#> Tail:
#> lon lat t temp seas thresh intensity event
#> 233756 25.25 -34.83333 2024-12-27 26.10294 24.0087 25.4949 2.0942 TRUE
#> 233757 25.25 -34.83333 2024-12-28 25.92349 24.0447 25.5349 1.8788 TRUE
#> 233758 25.25 -34.83333 2024-12-29 25.77407 24.0814 25.5727 1.6927 TRUE
#> 233759 25.25 -34.83333 2024-12-30 25.18079 24.1189 25.6097 1.0619 FALSE
#> 233760 25.25 -34.83333 2024-12-31 25.10389 24.1567 25.6499 0.9472 FALSE
#> event_no category depth
#> 233756 81 1 5.078224
#> 233757 81 1 5.078224
#> 233758 81 1 5.078224
#> 233759 NA NA 5.078224
#> 233760 NA NA 5.078224
#>
#> Summary:
#> dates: 1993-01-01 to 2024-12-31
#> event-days: 14739
#> category: 1=24861 2=148
#>
#> Examine with hw3_export("/tmp/Rtmp9X0FXX/mhw4d_events_daily.nc", n = 20)
#> or export with hw3_export("/tmp/Rtmp9X0FXX/mhw4d_events_daily.nc", file_out = "out.csv") (.csv/.rds/.parquet)
#> ------------------------------------------------------------------hw3_export() surfaces the same depth column
on this per-day product, and its streaming subset
(lon_range/lat_range/time_range/depth_range/n)
is depth-aware too, so a single pixel’s full depth profile over a short
date window reads cheaply without loading the whole file:
daily_df <- hw3_export(paste0(stem, "_events_daily.nc"),
lon_range = c(25.16, 25.17), lat_range = c(-34.92, -34.91),
time_range = c("1999-01-01", "2000-12-31"))
head(daily_df)#> lon lat t temp seas thresh intensity event
#> 1 25.16667 -34.91667 1999-01-01 25.52431 24.4421 25.7957 1.0822 FALSE
#> 2 25.16667 -34.91667 1999-01-02 24.80212 24.4798 25.8305 0.3223 FALSE
#> 3 25.16667 -34.91667 1999-01-03 25.17786 24.5167 25.8673 0.6612 FALSE
#> 4 25.16667 -34.91667 1999-01-04 26.36369 24.5528 25.9038 1.8109 FALSE
#> 5 25.16667 -34.91667 1999-01-05 26.41936 24.5878 25.9396 1.8316 FALSE
#> 6 25.16667 -34.91667 1999-01-06 26.12198 24.6215 25.9754 1.5005 FALSE
#> event_no category depth
#> 1 NA NA 0.494025
#> 2 NA NA 0.494025
#> 3 NA NA 0.494025
#> 4 NA 1 0.494025
#> 5 NA 1 0.494025
#> 6 NA 1 0.494025
geom_flame3() automatically folds a mapped
depth aesthetic into its row grouping – each depth level
gets its own exceedance runs instead of being treated as one continuous
series with depths interleaved – so one call plots every level:
ggplot(daily_df, aes(x = t, y = temp, y2 = thresh, depth = depth)) +
geom_flame3() +
geom_line(linewidth = 0.3) +
facet_wrap(~ depth, ncol = 1, labeller = label_both) +
labs(title = "Depth-resolved event-line plot", x = NULL,
y = expression("Temperature (" * degree * "C)")) +
theme_minimal(base_size = 11)
event_line3() also gained a depth argument,
for the classic single-pixel flame plot at one chosen level (matched to
the nearest depth actually present in the climatology, here 2.6 m):
event_line3(temp_file, paste0(stem, "_clim.nc"),
lon = 25.16667, lat = -34.91667, depth = 3,
event_file = paste0(stem, "_events.nc"))
geom_lolli3() needs no special handling for depth: each
lollipop is drawn from its own row independently of any grouping, so map
depth to colour (or facet) like any other column:
event_df_1px <- hw3_export(paste0(stem, "_events.nc"),
lon_range = c(25.16, 25.17), lat_range = c(-34.92, -34.91))
ggplot(event_df_1px, aes(x = date_peak, y = intensity_max, colour = factor(round(depth, 1)))) +
geom_lolli3() +
scale_colour_viridis_d(name = "depth (m)") +
labs(title = expression(I[max] ~ "by depth and peak date (single pixel)"),
x = NULL, y = expression(I[max] ~ "(degC)")) +
theme_minimal(base_size = 11)
