##' A plot method to easily obtain a graphical representation of the data, with several options to
##' enable coding of some variables. For example, hauls can be colour coded, and weighting variables
##' used to control point size.
##'
##' A lot of the models used are hierarchical, with random effects on hauls. Therefore, to see the
##' variation in hauls graphically, you can pass \code{col = "haul"} and the proportions will be
##' coloured differently for each haul.
##'
##' The same idea is applied to plotting character (\code{pch}). To use a different plotting
##' character for each covariate (e.g., mesh size), simply pass \code{pch = mesh} into the
##' function. However, note that using \code{pch} and \code{col} will not be easy to see trends
##' unless they are very clear. It is recommended that you use both symbol and colour only if there
##' are individual points you wish to investigate, rather than for finding trends, which is best
##' done using multiple plots and colour.
##' @title Plot Method for bsmdata Object
##' @param x a \code{bsmdata} object
##' @param scale logical, if \code{TRUE}, the data is scaled by sampling fractions
##' @param col the color of points. This can also be used to colour points by a factor variable such
##' as \code{haul}. See details.
##' @param pch the plotting symbol. This can also be the name of a (factor) variable in the data set
##' @param legend logical, if \code{TRUE} then a legend is drawn if points are coloured by some
##' variable (eg. haul)
##' @param weight the weights that will decide bubble sizes. Can be a variable or a vector
##' @param leg.posx position of legend. This can be text such as "topleft", "bottomright" etc, or
##' specific \code{x}-coordinates
##' @param leg.posy if \code{leg.posx} is an x-value, then this is the y-value
##' @param leg.cex size of legend
##' @param leg.bty the box type for the legend. Defaults to \code{"n"} for no box
##' @param col.palette the color palette to use by default; can be \code{rainbow} or a vector of colors
##' @param xlim range of x-values
##' @param ... additional arguments that will be passed to the \code{plot.default} function
##' @return NULL
##' @author Tom Elliott
##' @export
plot.bsmdata <- function(x, scale = TRUE, col, pch, legend = FALSE, weight,
leg.posx = "topleft", leg.posy = NULL, leg.cex = 0.7, leg.bty = "n",
col.palette = "rainbow", xlim = range(x$length),
...) {
## grab some variables from x (bsmdata object)
paired <- attr(x, "paired")
length.unit <- attr(x, "length.unit")
nhaul <- attr(x, "nhaul")
dots <- list(...)
## look into the call and save the arguments+values
mc <- as.list(match.call()[-1])
## examine the `col` argument and decide if it is missing, a colour, or a variable to colour by
if (missing(col))
col <- "#000000"
else
col <- eval(mc$col, x)
if (length(col) == 1) {
bycol <- col %in% names(x)
if (bycol)
colid <- as.factor(x[[col]])
} else {
bycol <- length(col) == length(x$y1)
colid <- as.factor(col)
}
## examine the `pch` argument and do the same as for `col`
if (missing(pch))
pch <- 1
else
pch <- eval(mc$pch, x)
if (length(pch) == 1) {
bypch <- pch %in% names(x)
if (bypch)
pchid <- as.factor(x[[pch]])
} else {
bypch <- length(pch) == length(x$y1)
pchid <- as.factor(pch)
}
## figure out the name for the colour and pch variables
colname <- pchname <- ""
if (bycol)
colname <- names(x)[sapply(x, function(x) {
if (is.factor(x)) {
if (length(levels(x)) == length(levels(colid)))
if (all(levels(x) == levels(colid)))
all(x == as.factor(colid))
else
FALSE
else
FALSE
} else {
all(x == colid)
}
})]
if (bypch)
pchname <- names(x)[sapply(x, function(x) all(x == pchid))]
## implement appropriate scaling
Y1 <- with(x, if (scale) y1 / q1 else y1)
Y2 <- with(x, if (scale) y2 / q2 else y2)
N <- Y1 + Y2
## generate the colours and plotting symbols
if (bycol) {
ncol <- length(levels(colid))
if (length(col.palette == 1) & col.palette[1] == "rainbow")
cols <- rainbow(ncol, start = 0/6, end = 5/6,
s = 0.9, v = 0.9, alpha = 0.6)
else
cols <- rep(col.palette, ncol)
} else {
cols <- col
colid <- 1
}
if (bypch) {
pchs <-
if (bycol & length(levels(pchid)) <= 4) c(19, 17, 15, 18)
else 1:length(levels(pchid))
} else {
pchs <- if (bycol & pch == 1) 19 else pch
pchid <- 1
}
npch <- length(unique(pchs))
## figure out point sizes
if (missing(weight)) {
size <- 1
} else {
w <- eval(mc$weight, x)
## if specifying N as the weighting variable, sum over lengths
if (all(w == N))
w <- (tapply(N, x$haul, sum))[x$haul]
size <- 4 * (w - min(w)) / diff(range(w)) + 0.5
if (length(pchs == 1))
if (pchs == 1)
pchs <- 19
}
if ("cex" %in% names(dots))
size <- size * dots$cex
## draw the plot
with(x, plot(length, Y1 / N,
xlab = paste0("Length",
ifelse(is.null(length.unit), "", paste0(" (", length.unit, ")"))),
ylab = paste0(
ifelse(scale, "Scaled p", "P"),
"roportion caught in ",
ifelse(paired, "experimental trawl", "codend")
),
xlim = xlim,
ylim = 0:1,
col = cols[as.numeric(colid)],
pch = pchs[as.numeric(pchid)],
cex = size))
## draw the legend if it's asked for
if (legend && (bycol | bypch)) {
LEG <- COL <- character()
PCH <- numeric()
if (bycol) {
LEG <- c(LEG, paste(colname, levels(colid)))
COL <- c(COL, cols)
PCH <- c(PCH, rep(19, ncol))
}
if (bypch) {
LEG <- c(LEG, paste(pchname, levels(pchid)))
COL <- c(COL, rep("#000000", npch))
PCH <- c(PCH, pchs)
}
legend(leg.posx, leg.posy, LEG, pch = PCH, col = COL,
bty = leg.bty, cex = leg.cex)
}
return(invisible(NULL))
}
##' Various types of plots of the fitted BSM object
##'
##' Lots ??
##' @title Plot a BSM Fit
##' @param x a bsmfit object
##' @param which which plot to draw, c("posterior", "curve")
##' @param parameters if \code{which = "posterior"}, \code{"pairs"}, then these parameters are used
##' @param estimate "mean" or "median", the estimate to be used when drawing the curve
##' @param cred.int logical, if \code{TRUE}, then a credible interval is calcualted from the
##' posterior samples of L50 and SR (and delta)
##' @param cred.alpha the significance level for the credible interval, default is 0.95
##' @param cred.col the colour of the credible interval
##' @param new logical, if \code{TRUE}, then a new plot of the data is drawn, otherwise the curve is
##' plot over any existing one
##' @param col colour of lines
##' @param lty line type
##' @param lwd line width
##' @param legend.order order of variables for legend purposes (color, line type, line width)
##' @param predict.values extra values to predict
##' @param n.posterior.rows the number of rows in the posterior plot
##' @param leg.posx x-position of legend, can be "topleft" etc
##' @param leg.posy NULL, or y-position of legend
##' @param leg.cex size of legend
##' @param leg.bty box type of legend
##' @param chain.cols colours of lines for traceplots and density plots, NOTE: not used for pairs
##' and curve
##' @param interactive logical, if \code{TRUE}, use clicking on the plot to navigate through plots
##' @param trace.samples numeric, the (approximate) number of samples to plot in the traceplots (obtained by thinning appropriately)
##' @param ... additional parameters to \code{plot}
##' @return NULL
##' @author Tom Elliott
##' @export
plot.bsmfit <- function(x, which = "posterior", parameters = NULL,
estimate = "mean", cred.int = FALSE, cred.alpha = 0.95, cred.col = "#99999950",
new = TRUE, col = NULL, lty = 1, lwd = 2, legend.order = NULL,
predict.values = NULL, n.posterior.rows = 3,
leg.posx = "topleft", leg.posy = NULL, leg.cex = 0.7, leg.bty = "n",
chain.cols = rainbow(x$fit$BUGSoutput$n.chains + 1, s = 0.8, v = 0.8),
interactive = FALSE, trace.samples = 1000,
...) {
if (length(which) > 1)
warning("`which` can only be a single value, only the first being used")
if (is.null(parameters)) {
all.par <- c("mu_L50", "sig2_L50", "mu_SR", "sig2_SR",
"mu_phi", "sig2_phi", "mu_delta", "sig2_delta")
parameters <- all.par[all.par %in% (ap <- x$fit$BUGSoutput$root.short)]
mn <- colnames(x$fit$BUGSoutput$sims.matrix)
for (coef in c("beta", "gamma", "omega", "zeta"))
if (coef %in% ap)
parameters <- c(parameters, mn[grep(coef, mn)])
if (x$check.od)
parameters <- c(parameters, "od_exp", "od_obs")
if (x$od)
parameters <- c(parameters, "sig2_od")
parameters <- c(parameters, "deviance")
## parameters <- x$all.parameters
}
dots <- list(...)
switch(which,
"posterior" = {
m <- coda::as.mcmc(x$fit)[, parameters]
nr <- np <- length(parameters)
Nit <- x$fit$BUGSoutput$n.keep
if (np > n.posterior.rows & !interactive)
devAskNewPage(TRUE)
nr <- n.posterior.rows
op <- par(mfrow = c(nr, 2))
theplot <- function(i) {
mi <- m[, i]
if (trace.samples < length(mi[[1]])) {
nthin <- round(length(mi[[1]]) / trace.samples)
} else {
nthin <- 1
}
ss <- seq(nthin, length(mi[[1]]), by = nthin)
mt <- as.mcmc.list(lapply(mi, function(x) {
mcmc(x[ss], start = summary(x)$start, end = summary(x)$end, thin = nthin * summary(x)$thin)
}))
coda::traceplot(mt, col = chain.cols,
main = paste0("Trace of ", parameters[i]))
dens <- lapply(mi, density)
plot.new()
plot.window(ylim = c(0, max(sapply(dens, function(x) max(x$y)))),
xlim = range(sapply(dens, function(x) range(x$x))))
box(); axis(1); axis(2)
for (j in 1:length(dens))
lines(dens[[j]], col = chain.cols[j])
title(main = paste0("Density of ", parameters[i]),
xlab = paste0("N = ", Nit),
ylab = "Density")
}
if (interactive) {
cat("\n")
cat(" Click top-right for next and top-left for previous.\n",
" Right-click to exit, or click the bottom of the graphics window.\n\n", sep = "")
I <- 1
while (I > 0) {
ow <- par(mfrow = c(nr, 2))
ii <- 3 * (I - 1) + (1:3)
for (i in ii[ii <= np]) {
dev.hold()
theplot(i)
dev.flush()
}
ou <- par(usr = c(0, 1, 0, 1))
xy <- locator(1)
if (is.null(xy))
I <- 0
else if (xy$y < 0.2)
I <- 0
else if (xy$x > 0.7)
I <- ifelse(I == ceiling(np / 3), I, I + 1)
else if (xy$x < 0.3)
I <- ifelse(I == 1, I, I - 1)
par(ow)
}
} else {
for (i in 1:np)
theplot(i)
}
par(op)
devAskNewPage(FALSE)
},
"pairs" = {
s <- x$fit$BUGSoutput$sims.matrix
s <- s[, parameters]# %in% colnames(s)]
pairs(s, panel = function(x, y, ...) points(x, y, col = "#0055bb30", pch = 19))
},
"curve" = {
if (new)
plot(x$object)
if (estimate == "median") estimate <- "50%"
s <- x$fit$BUGSoutput$summary[, estimate]
s <- s[names(s) %in% c("mu_L50", "mu_SR", "mu_delta", "mu_phi")]
predmat <- predict(x, predict.values = predict.values,
sort = legend.order[legend.order != "null"])
if (nrow(predmat) == 1) {
## If they ask for a confidence interval:
if (cred.int) {
if (cred.alpha < 0 | cred.alpha > 1) {
warning("cred.alpha must be between 0 and 1. Using default = 0.95")
cred.alpha <- 0.95
}
post <- x$fit$BUGSoutput$sims.matrix[, names(s)]
if (!"mu_delta" %in% (cc <- colnames(post))) {
post <- cbind(post, 1)
colnames(post) <- c(cc, "mu_delta")
}
if (!"mu_phi" %in% (cc <- colnames(post))) {
post <- cbind(post, 100)
colnames(post) <- c(cc, "mu_phi")
}
xl <- par()$usr[1:2]
xx <- seq(xl[1], xl[2], length = length(x$data$x) * 2)
curves <- apply(post, 1, function(par) {
eta <- richards(xx, par["mu_L50"], par["mu_SR"], par["mu_delta"])
yy <- (1 / (1 + exp(-eta))) ^ (1 / par["mu_delta"])
yy * ilogit(par["mu_phi"])
})
ci <- 0.5 + cred.alpha / 2 * c(-1, 1)
qx <- apply(curves, 1, quantile, probs = ci)
polygon(c(xx, rev(xx)), c(qx[1, ], rev(qx[2, ])),
col = cred.col, lty = 3)
}
names(s) <- gsub("mu_", "", names(s))
if (is.null(col))
col <- "black"
bsmCurve(s, col = col, lwd = lwd, lty = lty, ...)
} else {
p <- c("L50", "SR", "delta", "phi")
resp <- p[p %in% colnames(predmat)]
expl <- colnames(predmat)[!colnames(predmat) %in% resp]
if (!is.null(legend.order))
expl <- legend.order
nr <- nrow(predmat)
LEG.LAB = character()
LEG.COL = character()
LEG.LTY = numeric()
LEG.LWD = numeric()
COLS <- rep(ifelse(is.null(col), "#000000", col[1]), nr)
if (length(expl) > 0) {
if (expl[1] != "null") {
v1 <- as.integer(as.factor(predmat[[expl[1]]]))
if (is.null(col) | length(col) < length(unique(v1))) {
COL <- rainbow(length(unique(v1)), start = 0/6, end = 5/6,
s = 0.8, v = 0.8)
LEG.LAB <- c(LEG.LAB, paste(expl[1], "=",
levels(as.factor(predmat[[expl[1]]]))))
LEG.COL <- c(LEG.COL, COL)
LEG.LTY <- c(LEG.LTY, rep(1, length(COL)))
LEG.LWD <- c(LEG.LWD, rep(2, length(COL)))
} else {
COL <- col
}
COLS <- COL[v1]
}
}
if (length(expl) > 1) {
v2 <- as.integer(as.factor(predmat[[expl[2]]]))
LTY <- v2
LEG.LAB <- c(LEG.LAB, paste(expl[2], "=",
levels(as.factor(predmat[[expl[2]]]))))
LEG.COL <- c(LEG.COL, rep("#000000", length(unique(LTY))))
LEG.LTY <- c(LEG.LTY, unique(LTY))
LEG.LWD <- c(LEG.LWD, rep(1, length(unique(LTY))))
} else {
LTY <- rep(lty[1], nr)
}
if (length(expl) > 2) {
v3 <- as.integer(as.factor(predmat[[expl[3]]]))
LWD <- v3
LEG.LAB <- c(LEG.LAB, paste(expl[3], "=",
levels(as.factor(predmat[[expl[3]]]))))
LEG.COL <- c(LEG.COL, rep("#000000", length(unique(LWD))))
LEG.LTY <- c(LEG.LTY, rep(1, length(unique(LWD))))
LEG.LWD <- c(LEG.LWD, unique(LWD))
} else {
LWD <- rep(lwd[1], nr)
}
for (i in 1:nr) {
c <- as.numeric(predmat[i, resp])
names(c) <- resp
bsmCurve(c, col = COLS[i], lty = LTY[i], lwd = LWD[i], ...)
}
if (length(LEG.LAB) > 0)
legend(leg.posx, leg.posy, LEG.LAB, col = LEG.COL, lty = LEG.LTY, lwd = LEG.LWD,
bty = leg.bty, cex = leg.cex)
}
})
return(invisible(NULL))
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.