R/plot_TS.R

Defines functions plotArgoTS

Documented in plotArgoTS

# vim:textwidth=128:expandtab:shiftwidth=4:softtabstop=4

#' Plot a TS diagram for an argoFloats object
#'
#' Plot a TS diagram for an [argoFloats-class] object that was created with
#' [readProfiles()].  This function is called by [plot,argoFloats-method()],
#' but may also be called directly.
#'
#' @param x an argoFloats object that was created with [readProfiles()].
#'
#' @param xlim,ylim optional limits of salinity and temperature axes; if not provided,
#' the plot region will be large enough to show all the data.
#'
#' @param type character value indicating the of plot.  This has the same meaning
#' as for general R plots: `"p"` for points, `"l"` for lines, etc.  Note that
#' lines are joined up between cycles, unless the `TSControl` parameter indicates
#' otherwise.
#'
#' @param cex,col,pch,bg values that have the same meaning as for general R plots
#' if `TSControl$groupByCycle` is FALSE, except that if `col` is not
#' provided by the user and if `type` is `"l"`, then the points
#' are colour-coded to indicate the value of data-quality flags.
#' Black symbols indicate good data, i.e. data for which the
#' flags for pressure, salinity and temperature are all in the set
#' (1, 2, 5, 8).  Red is used for bad data, with any of these three
#' variables being flagged in the set (3, 4, 6, 7). And, finally
#' gray is used if data that have not been assessed for quality,
#' with the flags for all three of these variables being 0.
#' (For more on flags, see Reference Table 2 in Section 3.2 of
#' reference 1.)
#'
#' @param eos character value, either `"gsw"` (the default) for the Gibbs-Seawater
#' (TEOS-10) equation of state or `"unesco"` for the 1980s-era UNESCO equation of
#' state.
#'
#' @param TSControl an optional list that may have a logical element named `groupByCycle`,
#' meaning to group the data by cycle. If `TSControl` is not provided, it is set
#' to `list(groupByDefault=FALSE)`.  In grouped cases, the values of `cex`, `col`,
#' and `pch` are passed to [rep()] to achieve the same length as the number of
#' cycles in `x`.  This can be useful in distinguishing between cycles.
#'
#' @param debug an integer controlling how much information is to be printed
#' during operation. Use 0 for silent work, 1 for some information and 2 for
#' more information.  Note that [plot,argoFloats-method()] reduces its `debug`
#' value by 1 before passing to [plotArgoTS()].
#'
#' @param \dots extra arguments provided to [oce::plotTS()].
#'
#' @references
#'
#' 1. Argo Data Management. “Argo User’s Manual.” Ifremer, July 5, 2022.
#' https://doi.org/10.13155/29825.
#'
#' @export
#'
#' @author Dan Kelley and Jaimie Harbin
plotArgoTS <- function(x, xlim=NULL, ylim=NULL,
    type="p", cex=1, col=NULL, pch=1, bg="white", eos="gsw", TSControl=NULL,
    debug=0, ...)
{
    #message('debug=',debug)
    if (!inherits(x, "argoFloats"))
        stop("x must be an argo object")
    if ((x[["type"]] != "argos"))
        stop("x must be the result of a call to readProfiles()")
    if (!(eos %in% c("gsw", "unesco")))
        stop("eos must be \"gsw\" or \"unesco\", not \"", eos, "\"")
    argoFloatsDebug(debug, "plotArgoTS(x, ..., eos=\"", eos, "\", ...) {\n", sep="", unindent=1, style="bold")
    if (!(eos %in% c("gsw", "unesco")))
        stop("In plot,argoFloats-method(): eos must be \"gsw\" or \"unesco\", not \"", eos, "\"", call.=FALSE)
    colGiven <- !is.null(col)
    # compute cycle, in case we need that
    ncycles <- x[["length"]]
    cycleIndex <- unlist(lapply(seq_len(ncycles),
            function(icycle)
                rep(icycle, length(x@data$argos[[icycle]]@data$pressure))))
    salinity <- unlist(x[["salinity", debug=debug-1L]])
    temperature <- unlist(x[["temperature", debug=debug-1L]])
    pressure <- unlist(x[["pressure", debug=debug-1L]])
    ## Use byLevel to repeat the latitude and longitude values across
    ## the depths in each profile, so that the resultant vector
    ## will match the salinity, temperature and pressure vectors.
    latitude <- unlist(x[["latitude", "byLevel", debug=debug-1L]])
    longitude <- unlist(x[["longitude", "byLevel", debug=debug-1L]])
    # Interpolate across NA longitudes (required for traj data, to get TS plot)
    n <- length(longitude)
    if (any(is.na(longitude)))
        longitude <- approx(1:n, longitude, 1:n)$y
    if (any(is.na(latitude)))
        latitude <- approx(1:n, latitude, 1:n)$y
    ctd <- oce::as.ctd(salinity=salinity,
        temperature=temperature,
        pressure=pressure,
        latitude=latitude,
        longitude=longitude)
    ctd@data$cycleIndex <- cycleIndex
    if (is.null(TSControl)) {
        argoFloatsDebug(debug, "defaulting TSControl\n")
        TSControl <- list(groupByCycle=NULL)
    }
    #message("next is col:");print(col)
    #cat("next is cex inside call (spot 1):\n");cat(vectorShow(cex))
    if (is.null(TSControl$groupByCycle)) {
        argoFloatsDebug(debug, "TSControl does not contain groupByCycle\n")
        if (is.null(col)) {
            col <- "flags"
        }
    } else {
        #? argoFloatsDebug(debug, "TSControl contains groupByCycle\n")
        #? cycle <- unlist(x[["cycle", debug=debug-1L]])
        #? lengths <- sapply(x[["argos"]], function(cc) length(cc[["pressure"]]))
        #? # Increase the col length, so e.g. TSControl=list(groupByCycle=1:2) will alternate colours
        #? groupByCycle <- rep(TSControl$groupByCycle, length.out=length(cycle))
        #? col <- rep(col, length.out=ncycles)
        #? cex <- rep(cex, length.out=ncycles)
        #? #print(cex)
        #? pch <- rep(pch, length.out=ncycles)
        #? type <- rep(type, length.out=ncycles)
        #? #col <- unlist(lapply(seq_len(ncycles),
        #? #        function(i)
        #? #            rep(col[i], lengths[i])))
        #? #type <- rep(TSControl$type, length.out=ncycles)
    }
    #cat("next is cex inside call (spot 2):\n");cat(vectorShow(cex))
    # Calculate whether data are good
    pressureFlag <- unlist(x[["pressureFlag"]])
    salinityFlag <- unlist(x[["salinityFlag"]])
    temperatureFlag <- unlist(x[["temperatureFlag"]])
    # Consider these to be good: 1=good, 2=probably good, 5=changed, 8=estimated
    # Consider these to be bad: 3=bad data that are potentially correctable,
    # 4=bad data, 6=not used, 7=not used, 9=missing value.
    goodp <- pressureFlag %in% c(1, 2, 5, 8)
    goodT <- temperatureFlag %in% c(1, 2, 5, 8)
    goodS <- salinityFlag %in% c(1, 2, 5, 8)
    goodData <- goodp & goodS & goodT
    unassessedp <- pressureFlag == 0
    unassessedT <- temperatureFlag == 0
    unassessedS <- salinityFlag == 0
    unassessedData <- unassessedp & unassessedS & unassessedT
    # Colour-code by flag status (may be overruled by the user setting colors)
    if (identical(col[1], "flags")) {
        argoFloatsDebug(debug, "col is \"flags\"\n")
        col <- ifelse(goodData, 1, ifelse(unassessedData, "gray", 2))
        # FIXME: pch=21 does not work.  I think the new name might be pt.bg or something;
        # using bg colours field. Or is it 'fill'? Revisit this later.
        if (pch == 21) {
            bg <- ifelse(goodData, 1, ifelse(unassessedData, "gray", 2))
        }
    }
    argoFloatsDebug(debug, "about to set xlim and ylim\n")
    if (is.null(xlim)) {
        Slim <- if (eos == "gsw") range(ctd[["SA"]], na.rm=TRUE)
            else range(ctd[["salinity"]], na.rm=TRUE)
        argoFloatsDebug(debug, "inferred xlim=", paste(round(Slim, 5), collapse=" "), " from data\n", sep="")
    } else {
        Slim <- xlim
        argoFloatsDebug(debug, "using provided ylim=", paste(round(Slim, 5), collapse=" "), "\n", sep="")
    }
    if (is.null(ylim)) {
        Tlim <- if (eos == "gsw") range(ctd[["CT"]], na.rm=TRUE)
            else range(ctd[["theta"]], na.rm=TRUE)
        argoFloatsDebug(debug, "inferred ylim=", paste(round(Tlim, 5), collapse=" "), " from data\n", sep="")
    } else {
        Tlim <- ylim
        argoFloatsDebug(debug, "using provided ylim=", paste(round(Tlim, 5), collapse=" "), "\n", sep="")
    }
    if (isTRUE(TSControl$groupByCycle)) {
        argoFloatsDebug(debug, "colorizing by index\n")
        cycles <- unique(cycleIndex)
        ncycles <- length(cycles)
        argoFloatsDebug(debug, "Slim=c(", paste(Slim, collapse=","), ")\n", sep="")
        argoFloatsDebug(debug, "Tlim=c(", paste(Tlim, collapse=","), ")\n", sep="")
        if (length(longitude) != length(salinity))
            longitude <- rep(longitude[1], length(salinity))
        if (length(latitude) != length(salinity))
            latitude <- rep(latitude[1], length(salinity))
        if (length(cex) != ncycles)
            cex <- rep(cex, length.out=ncycles)
        if (length(col) != ncycles)
            col <- rep(col, length.out=ncycles)
        if (length(type) != ncycles)
            type <- rep(type, length.out=ncycles)
        if (length(pch) != ncycles)
            pch <- rep(pch, length.out=ncycles)
        argoFloatsDebug(debug, "cycle-by-cycle overlay, since groupByCycle is TRUE\n")
        message('debug=',debug)
        for (i in seq_len(ncycles)) {
            argoFloatsDebug(debug>1L, "  handling cycle ", i, " of ", ncycles, ", which has ",
                length(salinity[i==cycleIndex]), " points\n", sep="")
            look <- i == cycleIndex
            ctd <- oce::as.ctd(
                salinity=salinity[look],
                temperature=temperature[look],
                pressure=pressure[look],
                latitude=latitude[look],
                longitude=longitude[look])
            if (i == 1L) {
                plotTS(ctd, Slim=Slim, Tlim=Tlim,
                    cex=cex[i], col=col[i], pch=pch[i], type=type[i],
                    mar=par("mar"), mgp=par("mgp"), eos=eos, ...)
            } else {
                plotTS(ctd, add=TRUE,
                    cex=cex[i], col=col[i], pch=pch[i], type=type[i],
                    mar=par("mar"), mgp=par("mgp"), eos=eos, ...)
            }
        }
    } else {
        argoFloatsDebug(debug, "making single plotTS() call, since groupByCycle is FALSE\n")
        if (colGiven) {
            oce::plotTS(ctd, Slim=Slim, Tlim=Tlim, col=col, pch=pch, cex=cex, ...)
        } else {
            #print(table(col))
            ctdBad <- subset(ctd, !goodData)
            #DAN<<-list(ctd=ctd, ctdBad=ctdBad, goodData=goodData)
            oce::plotTS(ctd, Slim=Slim, Tlim=Tlim, col=col, pch=pch, cex=cex, ...)
            #?oce::plotTS(ctdBad, col=2, pch=pch, cex=cex, add=TRUE)
            #?oce::plotTS(ctd, cex=cex, bg=bg, col=col, pch=pch,
            #?    mar=par("mar"), mgp=par("mgp"), eos=eos,
            #?    type=if (is.null(type)) "p" else type[1], debug=debug-1L)
        }
    }
}
dankelley/argoFloats documentation built on April 18, 2024, 5:13 a.m.