One object and five axes
oceancube represents rectilinear ocean products with the
canonical order longitude, latitude, depth, time, and variable. The
logical contract is always five-dimensional, including surface fields,
which use a singleton depth axis.
library(oceancube)
lon <- c(-80, -79)
lat <- c(-12, -11)
depth <- c(5, 15)
time <- as.Date(c("2020-01-01", "2020-02-01", "2021-01-01", "2021-02-01"))
values <- array(seq_len(2 * 2 * 2 * 4), c(2, 2, 2, 4, 1))
x <- ocean_cube(
lon, lat, time, values, depth = depth,
vars = "temperature", units = "degC", source = "offline example"
)
x
#> <ocean_cube>
#> backend : memory
#> source : offline example
#> dimensions : 2 x 2 x 2 x 4 x 1 [lon x lat x depth x time x var]
#> lon : -80 to -79 (n = 2)
#> lat : -12 to -11 (n = 2)
#> depth : 5 to 15 (n = 2)
#> time : 2020-01-01 to 2021-02-01 (n = 4)
#> variables : temperature
summary(x)
#> field n min max
#> 1 longitude 2 -80 -79
#> 2 latitude 2 -12 -11
#> 3 depth 2 5 15
#> 4 time 4 2020-01-01 2021-02-01
#> 5 variable 1 <NA> <NA>
validation <- cube_validate(x)
inspection <- cube_inspect(x, missing = "none")
stopifnot(nrow(validation) > 0L)
stopifnot(inherits(inspection, "ocean_cube_inspection"))Memory cubes contain their values. Local NetCDF products can be
materialized with read_nc(). The package also has an
internal, serializable, read-only NetCDF descriptor backend;
cube_collect() turns that representation into an
independent memory cube. No network connection is needed for these
workflows.
Selection and extraction
Slices select stored positions or coordinates, while crops use closed ranges. Nearest matching is discrete and never interpolates.
slice <- cube_slice(x, longitude = -79, latitude = -11, by = "value")
crop <- cube_crop(x, longitude = c(-80, -79), depth = c(5, 15))
point <- cube_extract(
x, longitude = -79, latitude = -11, depth = 5,
time = time[1], variable = "temperature", by = "value"
)
profile <- cube_extract(
x, longitude = -79, latitude = -11, time = time[1],
variable = "temperature", by = "value", mode = "profile"
)
series <- cube_extract(
x, longitude = -79, latitude = -11, depth = 5,
variable = "temperature", by = "value", mode = "series"
)
dim(slice$data)
#> [1] 1 1 2 4 1
nrow(cube_extract(crop))
#> [1] 32
point
#> longitude latitude depth time variable unit value
#> 1 -79 -11 5 2020-01-01 temperature degC 4
profile
#> longitude latitude depth time variable unit value
#> 1 -79 -11 5 2020-01-01 temperature degC 4
#> 2 -79 -11 15 2020-01-01 temperature degC 8
series
#> longitude latitude depth time variable unit value
#> 1 -79 -11 5 2020-01-01 temperature degC 4
#> 2 -79 -11 5 2020-02-01 temperature degC 12
#> 3 -79 -11 5 2021-01-01 temperature degC 20
#> 4 -79 -11 5 2021-02-01 temperature degC 28cube_transect() extracts ordered path-depth
combinations. Name important arguments so matching, tolerance, mode, and
distance semantics remain explicit.
path <- data.frame(station = c("A", "B"), lon = lon, lat = lat)
cube_transect(
x, path, lon_col = "lon", lat_col = "lat", id_col = "station",
depth = 5, time = time[1], variable = "temperature", by = "value"
)
#> Warning: `cube_transect()` preserved its legacy implicit nearest matching.
#> Specify `match = "exact"` or `match = "nearest"` explicitly.
#> point_id point_order longitude_requested latitude_requested longitude
#> 1 A 1 -80 -12 -80
#> 2 B 2 -79 -11 -79
#> latitude match_distance_km requested_distance_km matched_distance_km depth
#> 1 -12 0 0.000 0.000 5
#> 2 -11 0 155.682 155.682 5
#> time variable unit value
#> 1 2020-01-01 temperature degC 1
#> 2 2020-01-01 temperature degC 4Static visualization
The six visualization functions return ggplot objects
and preserve the scientific cube. They select stored cells without
interpolation, smoothing, or imputation. Specialized D3 visualizations
are not part of this release.
plots <- list(
map = viz.map(x, "temperature", time = time[1], depth = 5),
section = viz.section(
x, "temperature", time = time[1], latitude = lat[1]
),
profile = viz.profile(
x, "temperature", longitude = lon[1], latitude = lat[1], time = time[1]
),
transect = viz.transect(
x, path, "temperature", time = time[1], depth = 5,
lon_col = "lon", lat_col = "lat", id_col = "station"
),
timeseries = viz.timeseries(
x, "temperature", longitude = lon[1], latitude = lat[1], depth = 5
),
hovmoller = viz.hovmoller(
x, "temperature", axis = "depth", longitude = lon[1], latitude = lat[1]
)
)
stopifnot(all(vapply(plots, inherits, logical(1), what = "ggplot")))Masks, climatologies, anomalies, and geometry
cube_mask() classifies horizontal cell centres against
polygons and requires the optional sf package.
cube_aggregate_time() performs time-only calendar
aggregation with equal observation weights and selective NetCDF reads.
cube_climatology() describes recurrent day, month, or
meteorological-season baselines through equally weighted period-year
replicates and bounded NetCDF reads. Its data contains the
climatological mean and climatology$sd contains aligned
sample SD. clim_month() and clim_day() remain
compatibility wrappers. New workflows use the canonical climatology
directly with cube_anomaly(); legacy anomaly wrappers
delegate to the same engine. cube_trend() adds descriptive
per-cell OLS slopes against actual elapsed historical time. It accepts
raw, aggregated, and anomaly cubes, but rejects recurrent climatology
pseudo-time.
monthly <- cube_aggregate_time(x, by = "month")
#> Warning: Temporal aggregation uses equal observation weighting; irregular or
#> gapped sampling can make observation-weighted summaries differ from
#> duration-weighted temporal summaries.
clim_cube <- suppressWarnings(cube_climatology(x, by = "month"))
clim <- suppressWarnings(clim_month(x))
difference <- cube_anomaly(x, clim_cube, type = "difference")
standardized <- cube_anomaly(x, clim_cube, type = "z")
legacy_difference <- anom_diff(x, clim)
#> Warning: `anom_diff()` is deprecated as of oceancube 0.3.0. Use
#> `cube_anomaly(x, climatology, type = "difference")` instead.
clim_cube
#> <ocean_cube>
#> backend : memory
#> source : offline example
#> dimensions : 2 x 2 x 2 x 12 x 1 [lon x lat x depth x time x var]
#> lon : -80 to -79 (n = 2)
#> lat : -12 to -11 (n = 2)
#> depth : 5 to 15 (n = 2)
#> time : 2001-01-01 to 2001-12-01 (n = 12)
#> variables : temperature
clim
#> <ocean_clim> month climatology
#> period : 2020-01-01 to 2021-02-01
#> variables : temperature
#> dimensions: 2 x 2 x 2 x 12 x 1 [lon x lat x depth x month x var]
dim(monthly$data)
#> [1] 2 2 2 14 1
dim(difference$data)
#> [1] 2 2 2 4 1
dim(standardized$data)
#> [1] 2 2 2 4 1
trend <- cube_trend(x, time_unit = "year")
dim(trend$data)
#> [1] 2 2 2 1 1Geometry functions provide cell areas, vertical thicknesses, volumes,
and polygon weights without calculating indicators. See the geometry
vignette for the optional-sf workflow.
Responsibility and limitations
oceancube owns representation, local reading, selection,
extraction, transects, masks, climatologies, anomalies, descriptive
per-cell temporal slopes, geometry, and weights. Spatial indicators,
trend inference, change points, and regimes belong to downstream
analysis such as spatind.
The current core is limited to local rectilinear data. It does not write NetCDF, read OPeNDAP or THREDDS, interpolate, regrid, process curvilinear meshes, perform Sen/Mann–Kendall inference, detect breakpoints or regimes, or provide general antimeridian support.