# vim:textwidth=80:expandtab:shiftwidth=4:softtabstop=4
#' Class to Store XBT (Expendable Bathythermograph) Data
#'
#' This class stores expendable bathythermograph (XBT) data, e.g. from a Sippican
#' device. Reference 1 gives some information on Sippican
#' devices, and reference 2 is a useful introduction to the
#' modern literature on XBTs in general.
#'
#' @references
#' 1. Sippican, Inc. "Bathythermograph Data Acquisition System: Installation, Operation and Maintenance
#' Manual (P/N 308195, Rev. A)," 2003.
#' https://pages.uoregon.edu/drt/MGL0910_Science_Report/attachments/MK21_ISA_Manual_Rev_A.pdf.
#'
#' 2. Cheng, Lijing, John Abraham, Gustavo Goni, Timothy Boyer, Susan Wijffels, Rebecca
#' Cowley, Viktor Gouretski, et al. "XBT Science: Assessment of Instrumental Biases and Errors."
#' Bulletin of the American Meteorological Society 97, no. 6 (June 2016): 924-33.
#' \code{10.1175/BAMS-D-15-00031.1}
#'
#' @templateVar class xbt
#'
# nolint start (long lines)
#' @templateVar dataExample The key items stored in this slot are `depth` (or `z`) and `temperature`, although some datasets also have `soundSpeed`. Note that `depth` and `z` are inferred from time in water, using an empirical formula for instrument descent rate, and that `soundSpeed` is #' calculated using a fixed practical salinity of 35. Note that the `[[` accessor will compute any of `depth`, `z` or `pressure`, based on whatever is in the data object. Similarly, `soundspeed` will compute sound speed (assuming a practical salinity of 35), if that that item is present in the `data` slot.
# nolint end(long lines)
#'
#' @templateVar metadataExample {}
#'
#' @template slot_summary
#'
#' @template slot_put
#'
#' @template slot_get
#'
#' @family things related to xbt data
#' @family classes provided by oce
#'
#' @author Dan Kelley
setClass("xbt", contains = "oce")
#' Sample xbt Data
#'
#' An [xbt-class] object created by using [read.xbt()] on a Sippican file created by extracting the near-surface
#' fraction of the sample provided in Section 5.5.6 of reference 1.
#'
#' @name xbt
#'
#' @docType data
#'
#' @usage data(xbt)
#'
#' @examples
#' library(oce)
#' data(xbt)
#' summary(xbt)
#' plot(xbt)
#'
#' @references
#' 1. Sippican, Inc. "Bathythermograph Data Acquisition System: Installation, Operation and Maintenance
#' Manual (P/N 308195, Rev. A)," 2003.
#' https://pages.uoregon.edu/drt/MGL0910_Science_Report/attachments/MK21_ISA_Manual_Rev_A.pdf.
#'
#' @family datasets provided with oce
#' @family things related to xbt data
NULL
#' Extract Something From an xbt Object
#'
#' @param x an [xbt-class] object.
#'
#' @section Details of the Specialized Method:
#'
#' * If `i` is `"?"`, then the return value is a list
#' containing four items, each of which is a character vector
#' holding the names of things that can be accessed with `[[`.
#' The `data` and `metadata` items hold the names of
#' entries in the object's data and metadata
#' slots, respectively. The `dataDerived`
#' and `metadataDerived` items are each NULL, because
#' no derived values are defined by `cm` objects.
#'
#' @template sub_subTemplate
#'
#' @author Dan Kelley
#'
#' @family things related to xbt data
setMethod(
f = "[[",
signature(x = "xbt", i = "ANY", j = "ANY"),
definition = function(x, i, j, ...) {
dataNames <- names(x@data)
S0 <- 35
metadataDerived <- NULL
dataDerived <- c("z", "pressure")
if (i == "?") {
return(list(
metadata = sort(names(x@metadata)),
metadataDerived = sort(metadataDerived),
data = sort(names(x@data)),
dataDerived = sort(dataDerived)
))
}
if (i == "depth") {
if ("depth" %in% dataNames) {
x@data$depth
} else if ("z" %in% dataNames) {
-x@data$depth
} else if ("pressure" %in% dataNames) {
swDepth(x@data$pressure, latitude = x@metadata$latitude)
}
} else if (i == "z") {
if ("depth" %in% dataNames) {
-x@data$depth
} else if ("z" %in% dataNames) {
x@data$z
} else if ("pressure" %in% dataNames) {
-swDepth(x@data$pressure, latitude = x@metadata$latitude)
}
} else if (i == "pressure") {
if ("depth" %in% dataNames) {
swPressure(depth = x@data$depth, latitude = x[["latitude"]])
} else if ("z" %in% dataNames) {
swPressure(depth = -x@data$z, latitude = x[["latitude"]])
} else if ("pressure" %in% dataNames) {
x@data$pressure
}
} else if (i == "soundSpeed") {
if ("soundSpeed" %in% dataNames) {
x@data$soundSpeed
} else {
swSoundSpeed(S0, x[["temperature"]], x[["pressure"]])
}
} else {
callNextMethod()
}
}
)
#' Replace Parts of an xbt Object
#'
#' @param x an [xbt-class] object.
#'
#' @template sub_subsetTemplate
#'
#' @family things related to xbt data
setMethod(
f = "[[<-",
signature(x = "xbt", i = "ANY", j = "ANY"),
definition = function(x, i, j, ..., value) {
callNextMethod(x = x, i = i, j = j, ... = ..., value = value) # [[<-
}
)
setMethod(
f = "initialize",
signature = "xbt",
# the only thing we know for sure is that temperature will be given
definition = function(.Object, z = NULL, depth = NULL, temperature = NULL, units, ...) {
.Object <- callNextMethod(.Object, ...)
if (!is.null(depth) && !is.null(z)) {
stop("cannot initialize XBT with both depth and z")
}
if (missing(units)) {
if (!is.null(temperature)) {
.Object@metadata$units$temperature <- list(unit = expression(degree * C), scale = "ITS-90")
}
if (!is.null(z)) {
.Object@metadata$units$z <- list(unit = expression(m), scale = "")
} else if (!is.null(depth)) {
.Object@metadata$units$depth <- list(unit = expression(m), scale = "")
}
} else {
.Object@metadata$units <- units # CAUTION: we are being quite trusting here
}
if (!is.null(depth)) {
.Object@data$depth <- depth
}
if (!is.null(z)) {
.Object@data$z <- z
}
if (!is.null(temperature)) {
.Object@data$temperature <- temperature
}
.Object@processingLog$time <- presentTime()
.Object@processingLog$value <- "create 'xbt' object"
return(.Object)
}
)
#' Summarize an xbt Object
#'
#' Summarizes some of the data in a `xbt` object.
#'
#' @param object A [xbt-class] object.
#'
#' @param ... Further arguments passed to or from other methods.
#'
#' @seealso The documentation for the [xbt-class] class explains the structure
#' of `xbt` objects, and also outlines the other functions dealing with them.
#'
#' @family things related to xbt data
#'
#' @author Dan Kelley
setMethod(
f = "summary",
signature = "xbt",
definition = function(object, ...) {
cat("xbt summary\n-----------\n\n", ...)
showMetadataItem(object, "filename", "File source: ", quote = TRUE)
showMetadataItem(object, "type", "Instrument type: ")
showMetadataItem(object, "model", "Instrument model: ")
showMetadataItem(object, "serialNumber", "Serial Number: ")
showMetadataItem(object, "longitude", "Longitude: ")
showMetadataItem(object, "latitude", "Latitude: ")
showMetadataItem(object, "time", "Time: ")
invisible(callNextMethod()) # summary
}
)
#' Subset an xbt Object
#'
#' This function is somewhat analogous to [subset.data.frame()].
#'
#' @param x an [xbt-class] object.
#'
#' @param subset a condition to be applied to the `data` portion of `x`.
#' See \dQuote{Details}.
#'
#' @param ... ignored.
#'
#' @return A new `xbt` object.
#'
#' @examples
#' library(oce)
#' data(xbt)
#' plot(xbt)
#' plot(subset(xbt, depth < mean(range(xbt[["depth"]]))))
#'
#' @family things related to xbt data
#' @family functions that subset oce objects
#'
#' @author Dan Kelley
setMethod(
f = "subset",
signature = "xbt",
definition = function(x, subset, ...) {
subsetString <- paste(deparse(substitute(expr = subset, env = environment())), collapse = " ")
res <- x
dots <- list(...)
debug <- getOption("oceDebug")
if (length(dots) && ("debug" %in% names(dots))) {
debug <- dots$debug
}
if (missing(subset)) {
stop("must give 'subset'")
}
if (length(grep("depth", subsetString))) {
oceDebug(debug, "subsetting an xbt by depth\n")
keep <- eval(expr = substitute(expr = subset, env = environment()), envir = x@data, enclos = parent.frame(2))
names <- names(x@data)
oceDebug(debug, vectorShow(keep, "keeping bins:"))
res <- x
for (name in names(x@data)) {
res@data[[name]] <- x@data[[name]][keep]
}
}
res@processingLog <- processingLogAppend(res@processingLog, paste("subset.xbt(x, subset=", subsetString, ")", sep = ""))
res
}
)
#' Create an xbt Object
#'
#' @param z numeric vector giving vertical coordinates of measurements. This is the negative of
#' depth, i.e. `z` is 0 at the air-sea interface, and negative within the water column.
#'
#' @param temperature numeric vector giving in-situ temperatures at the `z` values.
#'
#' @param longitude,latitude location in degE and degN.
#'
#' @param filename character value naming source file.
#'
#' @param sequenceNumber numerical value of the sequence number of the XBT drop.
#'
#' @param serialNumber character value holding the serial number of the XBT.
#'
#' @return An [xbt-class] object.
#'
#' @family things related to xbt data
#'
#' @author Dan Kelley
as.xbt <- function(
z, temperature, longitude = NA, latitude = NA, filename = "", sequenceNumber = NA,
serialNumber = "") {
if (missing(z)) {
stop("must provide z")
}
if (missing(temperature)) {
stop("must provide temperture")
}
if (length(z) != length(temperature)) {
stop("length of z (", length(z), ") does not match length of temperature (", length(temperature), ")")
}
res <- new("xbt", z = z, temperature = temperature)
# res@data$z <- z
# res@metadata$units$z <- list(unit=expression(m), scale="")
# res@metadata$units$temperature <- list(unit=expression(degree*C), scale="ITS-90")
# res@data$temperature <- temperature
res@metadata$dataNamesOriginal <- list(z = "", temperature = "")
res@metadata$longitude <- longitude
res@metadata$latitude <- longitude
res@metadata$header <- ""
res@metadata$filename <- filename
res@metadata$sequenceNumber <- sequenceNumber
res@metadata$serialNumber <- serialNumber
res
}
#' Read an xbt file
#'
#' Two file types are handled: (1) the `"sippican"` format, used
#' for Sippican XBT files, handled with [read.xbt.edf()], and (2)
#' the `"noaa1"` format, handled with [read.xbt.noaa1()]. The first of
#' these is recognized by [read.oce()], but the second must be called
#' directly with [read.xbt.noaa1()].
#'
#' @param file a connection or a character string giving the name of the file to
#' load.
#'
#' @param type character string indicating type of file, with valid choices being
#' `"sippican"` and `"noaa1"`.
#'
#' @param longitude,latitude optional signed numbers indicating the longitude in degrees
#' East and latitude in degrees North. These values are used if `type="sippican"`,
#' but ignored if `type="noaa1"`, because those files contain location information.
#'
#' @template encodingTemplate
#'
#' @param debug a flag that turns on debugging. The value indicates the depth
#' within the call stack to which debugging applies.
#'
#' @param processingLog if provided, the action item to be stored in the log. This
#' parameter is typically only provided for internal calls; the default that it
#' provides is better for normal calls by a user.
#'
#' @return An [xbt-class] object.
#'
#' @examples
#' library(oce)
#' xbt <- read.oce(system.file("extdata", "xbt.edf", package = "oce"))
#' summary(xbt)
#' plot(xbt)
#'
#' @family things related to xbt data
#'
#' @references
#' 1. Sippican, Inc. "Bathythermograph Data Acquisition System: Installation, Operation and Maintenance
#' Manual (P/N 308195, Rev. A)," 2003.
#' https://pages.uoregon.edu/drt/MGL0910_Science_Report/attachments/MK21_ISA_Manual_Rev_A.pdf.
#'
#' @author Dan Kelley
read.xbt <- function(
file,
type = "sippican",
longitude = NA,
latitude = NA,
encoding = "latin1",
debug = getOption("oceDebug"),
processingLog) {
if (missing(file)) {
stop("must supply 'file'")
}
if (is.character(file)) {
if (!file.exists(file)) {
stop("cannot find file \"", file, "\"")
}
if (0L == file.info(file)$size) {
stop("empty file \"", file, "\"")
}
}
oceDebug(debug, "read.xbt(file=\"", file, "\", type=\"",
type, "\", longitude=", longitude, ", latitude=", latitude, "...) START\n",
sep = "", unindent = 1
)
if (is.character(file) && "http://" != substr(file, 1, 7) && 0 == file.info(file)$size) {
stop("empty file (read.xbt)")
}
type <- match.arg(type)
res <- if (type == "sippican") {
read.xbt.edf(
file = file, longitude = longitude, latitude = latitude,
encoding = encoding, debug = debug - 1, processingLog = processingLog
)
} else if (type == "noaa1") {
if (!is.null(longitude)) {
warning("longitude argument is ignored for type=\"noaa1\"\n")
}
if (!is.null(latitude)) {
warning("latitude argument is ignored for type=\"noaa1\"\n")
}
read.xbt.noaa1(file = file, encoding = encoding, debug = debug - 1, processingLog = processingLog)
} else {
stop("unknown type of current meter")
}
oceDebug(debug, "END read.xbt()\n", sep = "", unindent = 1)
res
}
#' Read an xbt File in Sippican Format
#'
#'
#' The function was written by inspection of a particular file, and might
#' be wrong for other files; see \dQuote{Details} for a note on character
#' translation.
#'
#' The header is converted to ASCII format prior to storage in
#' the `metadata` slot, so that e.g. a degree sign in the original file will
#' become a `?` character in the `header`. This is to prevent problems
#' with submission of `oce` to the CRAN system, which produces NOTEs
#' about UTF-8 strings in data (on some build machines, evidently depending
#' on the locale on those machines). This character substitution
#' is at odds with the `oce` philosophy of leaving data intact, so
#' it will be reverted, if CRAN policy changes or if the developers
#' can find a way to otherwise silence the NOTE.
#'
#' @param file a connection or a character string giving the name of the file to
#' load.
#'
#' @param longitude optional signed number indicating the longitude in degrees
#' East.
#'
#' @param latitude optional signed number indicating the latitude in degrees North.
#'
#' @template encodingTemplate
#'
#' @param debug a flag that turns on debugging. The value indicates the depth
#' within the call stack to which debugging applies.
#'
#' @param processingLog if provided, the action item to be stored in the log. This
#' parameter is typically only provided for internal calls; the default that it
#' provides is better for normal calls by a user.
#'
#' @return An [xbt-class] object.
#'
#' @examples
#' library(oce)
#' xbt <- read.oce(system.file("extdata", "xbt.edf", package = "oce"))
#' summary(xbt)
#' plot(xbt)
#'
#' @author Dan Kelley
read.xbt.edf <- function(
file, longitude = NA, latitude = NA, encoding = "latin1",
debug = getOption("oceDebug"), processingLog) {
getHeaderItem <- function(l, name) {
res <- l[grep(name, l)]
gsub(paste(name, "[ ]*:[ ]*", sep = ""), "", res)
}
if (missing(file)) {
stop("must supply 'file'")
}
if (is.character(file)) {
if (!file.exists(file)) {
stop("cannot find file \"", file, "\"")
}
if (0L == file.info(file)$size) {
stop("empty file \"", file, "\"")
}
}
if (is.character(file) && "http://" != substr(file, 1, 7) && 0 == file.info(file)$size) {
stop("empty file (read.xbt.edf)")
}
oceDebug(debug, "read.xbt(file=\"", file, "\", longitude=", longitude, ", latitude=", latitude, "...) START\n",
sep = "", unindent = 1
)
filename <- ""
if (is.character(file)) {
filename <- fullFilename(file)
file <- file(file, "r", encoding = encoding)
on.exit(close(file))
}
if (!inherits(file, "connection")) {
stop("argument `file' must be a character string or connection")
}
if (!isOpen(file)) {
open(file, "r", encoding = encoding)
on.exit(close(file))
}
l <- readLines(file, 200) # don't read whole file
pushBack(l, file)
# FIXME: is this detection of the end of the header robust?
headerEnd <- grep("^Depth \\(", l)
if (0 == length(headerEnd)) {
stop("programming error: increase #lines read for header")
}
res <- new("xbt")
# Convert from latin1 to UTF-8, so a degree sign does not cause problems
# res@metadata$header <- l[1:headerEnd]
res@metadata$header <- iconv(l[1:headerEnd], from = encoding, to = "ASCII", sub = "?")
date <- getHeaderItem(l, "Date of Launch")
hms <- getHeaderItem(l, "Time of Launch")
res@metadata$time <- as.POSIXct(paste(date, hms, sep = " "),
format = "%m/%d/%Y %H:%M:%S", tz = "UTC"
)
res@metadata$serialNumber <- getHeaderItem(l, "Serial #")
res@metadata$sequenceNumber <- as.integer(getHeaderItem(l, "Sequence #"))
res@metadata$dataNamesOriginal <- list(depth = "Depth", temperature = "Temperature", soundSpeed = "Sound Velocity")
# Some steps needed for hemispheres.
lat <- getHeaderItem(l, "Latitude")
lats <- strsplit(lat, " ")[[1]]
latdeg <- as.numeric(lats[1])
latmin <- as.numeric(gsub("[NSns]", "", lats[2]))
res@metadata$latitude <- (latdeg + latmin / 60) * ifelse(length(grep("S", lats[2])), -1, 1)
lon <- getHeaderItem(l, "Longitude")
lons <- strsplit(lon, " ")[[1]]
londeg <- as.numeric(lons[1])
lonmin <- as.numeric(gsub("[EWew]", "", lons[2]))
res@metadata$longitude <- (londeg + lonmin / 60) * ifelse(length(grep("W", lons[2])), -1, 1)
res@metadata$probeType <- getHeaderItem(l, "Probe Type")
res@metadata$terminalDepth <- as.numeric(gsub("[ ]*m$", "", getHeaderItem(l, "Terminal Depth"))) # FIXME: assumes metric
res@data <- as.list(read.table(file, skip = headerEnd + 1, col.names = c("depth", "temperature", "soundSpeed"), encoding = encoding))
res@metadata$filename <- filename
res@metadata$units$depth <- list(unit = expression(m), scale = "")
res@metadata$units$temperature <- list(unit = expression(degree * C), scale = "ITS-90")
res@metadata$units$soundSpeed <- list(unit = expression(m / s), scale = "")
res@processingLog <- processingLogAppend(res@processingLog, paste(deparse(match.call()), sep = "", collapse = ""))
oceDebug(debug, "END read.xbt.edf()\n", unindent = 1)
res
}
#' Read an xbt File in NOAA Format
#'
#'
#' This file format, described at \code{https://www.aoml.noaa.gov/phod/dhos/axbt.php}, contains a header
#' line, followed by data lines. For example, a particular file at this site has first
#' three lines as follows.
#' ```
#' 181.589 20100709 140820 -85.336 25.290 N42RF GL10 14 2010-190-15:49:18
#' -0.0 27.52 -9.99
#' -1.5 27.52 -9.99
#' ```
#' where the items on the header line are (1) a year-day (ignored here), (2)
#' YYYYMMDD, (3) HHMMSS, (4) longitude, (5) latitude, (6) aircraft wing
#' number, (7) project name, (8) AXBT channel and (9) AXBT ID. The other lines hold vertical
#' coordinate in metres, temperature and temperature error; -9.99 is a missing-value
#' code. (This formatting information is extracted from a file named `readme.axbt` that
#' is provided with the data.)
#'
#' @param file character value naming a file, or a file connection, containing the data.
#'
#' @param debug a flag that turns on debugging. The value indicates the depth
#' within the call stack to which debugging applies.
#'
#' @param missingValue numerical value that is to be interpreted as `NA`
#'
#' @template encodingTemplate
#'
#' @param processingLog if provided, the action item to be stored in the log. This
#' parameter is typically only provided for internal calls; the default that it
#' provides is better for normal calls by a user.
#'
#' @return An [xbt-class] object.
#'
#' @family things related to xbt data
#'
#' @author Dan Kelley
read.xbt.noaa1 <- function(
file, debug = getOption("oceDebug"), missingValue = -9.99,
encoding = "latin1", processingLog) {
if (missing(file)) {
stop("must supply 'file'")
}
if (is.character(file)) {
if (!file.exists(file)) {
stop("cannot find file \"", file, "\"")
}
if (0L == file.info(file)$size) {
stop("empty file \"", file, "\"")
}
}
oceDebug(debug, "read.xbt(file=\"", file, "\", type=\"", "...) START\n", sep = "", unindent = 1)
filename <- "?"
if (is.character(file)) {
filename <- fullFilename(file)
file <- file(file, "r", encoding = encoding)
on.exit(close(file))
}
if (!inherits(file, "connection")) {
stop("argument `file' must be a character string or connection")
}
if (!isOpen(file)) {
open(file, "r", encoding = encoding)
on.exit(close(file))
}
res <- new("xbt")
header <- readLines(file, 1) # first line is a header
res@metadata$header <- header
res@metadata$filename <- filename
headerTokens <- strsplit(header, "[ \t]+")[[1]]
res@metadata$time <- ISOdatetime(
substr(headerTokens[2], 1, 4), # year
substr(headerTokens[2], 5, 6), # month
substr(headerTokens[2], 7, 8), # day
substr(headerTokens[3], 1, 2), # hour
substr(headerTokens[3], 3, 4), # minute
substr(headerTokens[3], 5, 6)
) # second
res@metadata$longitude <- as.numeric(headerTokens[4])
res@metadata$latitude <- as.numeric(headerTokens[5])
res@metadata$aircraft <- headerTokens[6]
res@metadata$project <- headerTokens[7]
res@metadata$axbtChannel <- headerTokens[8]
res@metadata$axbtId <- headerTokens[9]
data <- read.table(file, skip = 1, header = FALSE, col.names = c("z", "temperature", "temperatureError"), encoding = encoding)
res@metadata$header <- header
res@metadata$units$z <- list(unit = expression(m), scale = "")
res@data <- as.list(data)
if (!is.null(missingValue)) {
for (name in names(res@data)) {
res@data[[name]][res@data[[name]] == missingValue] <- NA
}
}
res@processingLog <- processingLogAppend(res@processingLog, paste(deparse(match.call()), sep = "", collapse = ""))
oceDebug(debug, "END read.xbt.noaa1()\n", sep = "", unindent = 1)
res
}
#' Plot an xbt Object
#'
#' Plots data contained in an [xbt-class] object.
#'
#' The panels are controlled by the `which` argument, with choices as follows.
#' * `which=1` for a temperature profile as a function of depth.
#' * `which=2` for a soundSpeed profile as a function of depth.
#'
#' @param x an [xbt-class] object.
#'
#' @param which list of desired plot types; see \dQuote{Details} for the meanings of various
#' values of `which`.
#'
#' @param type type of plot, as for [plot()].
#'
#' @param mgp 3-element numerical vector to use for `par(mgp)`, and also for
#' `par(mar)`, computed from this. The default is tighter than the R default,
#' in order to use more space for the data and less for the axes.
#'
#' @param mar value to be used with [`par`]`("mar")`.
#'
#' @param debug a flag that turns on debugging. Set to 1 to get a moderate amount
#' of debugging information, or to 2 to get more.
#'
#' @param ... optional arguments passed to plotting functions.
#'
#' @examples
#' library(oce)
#' data(xbt)
#' summary(xbt)
#' plot(xbt)
#'
#' @family functions that plot oce data
#' @family things related to xbt data
#'
#' @aliases plot.xbt
#'
#' @author Dan Kelley
setMethod(
f = "plot",
signature = signature("xbt"),
definition = function(x, which = 1, type = "l", mgp = getOption("oceMgp"), mar,
debug = getOption("oceDebug"), ...) {
oceDebug(debug, "plot.xbt() START\n", unindent = 1)
if (missing(mar)) {
mar <- c(1, mgp[1] + 1.5, mgp[1] + 1.5, mgp[1])
}
opar <- par(no.readonly = TRUE)
lw <- length(which)
oceDebug(debug, "length(which) =", lw, "\n")
if (lw > 1) {
on.exit(par(opar))
}
par(mgp = mgp, mar = mar)
oceDebug(debug, "which: c(", paste(which, collapse = ", "), ")\n")
if (lw > 1) {
par(mfrow = c(1, lw))
oceDebug(debug, "calling par(mfrow=c(", lw, ", 1)\n")
}
z <- x[["z"]]
temperature <- x[["temperature"]]
soundSpeed <- x[["soundSpeed"]]
for (w in 1:lw) {
oceDebug(debug, "which[", w, "]=", which[w], "\n")
if (which[w] == 1) {
plot(temperature, z, xlab = "", ylab = resizableLabel("z"), type = type, axes = FALSE, ...)
axis(2)
box()
axis(3)
mtext(resizableLabel("temperature"), side = 3, line = mgp[1])
} else if (which[w] == 2) {
plot(soundSpeed, z, xlab = "", ylab = resizableLabel("z"), type = type, axes = FALSE, ...)
axis(2)
box()
axis(3)
mtext(resizableLabel("sound speed"), side = 3, line = mgp[1])
} else {
stop("which values are limited to 1 and 2")
}
}
oceDebug(debug, "END plot.xbt()\n", unindent = 1)
invisible(NULL)
}
)
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.