Nothing
#' Caterpillar plot
#' @description Caterpillar plot of the posterior densities of a vector of parameter nodes,
#' in which the sequential order of nodes might not be important, such as vector of random effects.
#'
#' This produces a set of overlayed interval bars (default values are 50 percent and 95 percent),
#' with overlayed median markings, for each of a vector of parameter nodes.
#' @param df Output object returned from `jagsUI::jags()`; or alternately,
#' two-dimensional `data.frame` or matrix in which parameter node element is
#' given by column and MCMC iteration is given by row. A vector may also be used,
#' that expresses MCMC iterations of a single parameter node.
#' @param p Parameter name, if input to `df` is a `jagsUI` output object.
#' @param x Vector of X-coordinates for plotting.
#' @param na.rm Whether to exclude NA columns. Defaults to TRUE.
#' @param row Row to subset, in the case of a 2-d matrix of parameter nodes in-model.
#' @param column Column to subset, in the case of a 2-d matrix of parameter nodes in-model.
#' @param median Whether to include medians
#' @param mean Whether to include means
#' @param ci Vector of intervals to overlay. Defaults to 50 percent and 95 percent.
#' @param col Color for plotting
#' @param add Whether to add to existing plot
#' @param lwd Base line width for plotting. Defaults to 1.
#' @param xlab X-axis label
#' @param ylab Y-axis label
#' @param main Plot title. If the default (`NULL`) is accepted and argument `p` is used, `p` will be used for the title.
#' @param xlim X-axis limits. If the default (`NULL`) is accepted, the limits will be determined automatically.
#' @param ylim Y-axis limits. If the default (`NULL`) is accepted, the limits will be determined automatically.
#' @param xlim_add Additional X-axis limit. Defaults to `NULL`. May be useful in having a axis start at 0.
#' @param ylim_add Additional Y-axis limit. Defaults to `NULL`. May be useful in having a axis start at 0.
#' @param xax Vector of possible x-axis tick labels. Defaults to the `data.frame` column names.
#' @param xorder Whether to draw interval bars in order of posterior median. Defaults to FALSE.
#' @param horizontal Whether to produce a horizontal plot, that is, with intervals on the x-axis. Defaults to FALSE.
#' @param transform Should the y-axis be (back)transformed? Options are `"exp"`,
#' indicating exponential, or `"expit"`, indicating inverse-logit. Defaults to
#' `"none"`, indicating no transformation. Note: if `transform="exp"`is used, consider
#' adding additional plotting argument `log="y"`.
#' @param medlwd Line width of median line
#' @param medwd Relative width of median line. Defaults to 1, and acts as a multiplicative adjustment.
#' @param padwd Relative width of padding beyond the median line. Defaults to 1, and acts as a multiplicative adjustment.
#' @param all_ticks Whether to force plotting of all axis tick labels. Defaults to `FALSE`.
#' @param ... additional plotting arguments
#' @return `NULL`
#' @seealso \link{envelope}, \link{crossplot}
#' @author Matt Tyers
#' @examples
#' ## usage with input data.frame
#' a <- jags_df(asdf_jags_out, p="a")
#'
#' caterpillar(a)
#' caterpillar(a, ci=seq(.1,.9,by=.1))
#' caterpillar(a, lwd=2)
#' caterpillar(a, xax=c("effect 1", "effect 2", "effect 3"))
#'
#' caterpillar(a, xax=c("effect 1", "effect 2", "effect 3"),
#' horizontal = TRUE, las=1)
#'
#'
#' ## usage with input as jagsUI object
#' caterpillar(asdf_jags_out, p="a")
#' caterpillar(SS_out, p="rate")
#'
#' ## usage with a 2-d parameter matrix
#' caterpillar(SS_out, p="cycle_s", column=1)
#' caterpillar(SS_out, p="cycle_s", column=2)
#'
#' ## usage with an exponential transformation
#' caterpillar(SS_out, p="trend", transform="exp", ylab="exp transform")
#' caterpillar(SS_out, p="trend", transform="exp", ylab="exp transform", log="y")
#' caterpillar(SS_out, p="trend", transform="expit", ylab="expit (inv logit) transform")
#' @export
caterpillar <- function(df,
p=NULL,
x=NA,
na.rm=TRUE, # think about why this would't be
row=NULL, column=NULL,
median=TRUE, mean=FALSE,
ci=c(0.5,0.95),
lwd=1, col=4, add=FALSE,
xlab="", ylab="", main=NULL,
xlim=NULL, ylim=NULL,
xlim_add=NULL, ylim_add=NULL,
xax=NA,
xorder = FALSE, horizontal=FALSE,
transform=c("none", "exp", "expit"),
medlwd=lwd, medwd=1, padwd=1,
all_ticks=FALSE, ...) {
# ci <- rev(sort(ci))
# loq <- apply(df, 2, quantile, p=(1-ci)/2, na.rm=T)
# hiq <- apply(df, 2, quantile, p=1-(1-ci)/2, na.rm=T)
# if(length(ci)==1) {
# loq <- t(as.matrix(loq))
# hiq <- t(as.matrix(hiq))
# }
# med <- apply(df, 2, median, na.rm=T)
# if(all(is.na(x))) x <- 1:ncol(df)
# d <- diff(x[1:2])
# nn <- ncol(df)
# if(all(is.na(xax))) xax<-names(df)
# lwds <- (1+2*(1:length(ci)-1))*lwd
# if(!add) {
# plot(NA, type='l', ylim=range(loq,hiq,na.rm=T), xlim=range(x-(.2*d),x+(.2*d)), xlab=xlab, ylab=ylab, main=main, xaxt="n", ...=...)
# axis(1,x,labels=xax)
# }
# if(median) {
# segments(x0=x-.2*d*medwd,x1=x+.2*d*medwd,y0=med,y1=med,col=col,lwd=medlwd, lend=1)
# }
# if(mean) points(x,colMeans(df, na.rm=T), pch=16, col=col)
# for(i in 1:length(ci)) segments(x0=x,x1=x,y0=loq[i,],y1=hiq[i,],col=col,lwd=lwds[i],lend=1)
if(!inherits(df,"jagsUI") & !inherits(df,c("matrix","data.frame","numeric","integer"))) { ## put matrix in here
stop("Input must be a data.frame or output from jagsUI::jags() plus parameter name")
}
if(inherits(df,"jagsUI") & length(p)!=1) stop("Need single parameter name in p= argument") ###
if(class(df)[1]=="jagsUI" & !is.null(p)) {
simslist <- df$sims.list
if(all(names(simslist)!=p)) stop("No parameters with matching names") ###
theparm <- simslist[names(simslist)==p][[1]]
if(is.null(row) & is.null(column)) {
df <- theparm
} else {
theparm <- simslist[names(simslist)==p][[1]]
if(!is.null(row)) df <- theparm[,row,]
if(!is.null(column)) df <- theparm[,,column]
}
if(is.null(main) & length(p)==1) {
if(is.null(row) & is.null(column)) {
main <- p
} else {
if(!is.null(row)) main <- paste0(p,"[",row,",]")
if(!is.null(column)) main <- paste0(p,"[,",column,"]")
}
}
}
if(is.null(main)) main <- ""
df <- as.matrix(df) ################
if(na.rm) {
keep <- which(!is.na(colMeans(df)))
# df <- as.matrix(df[, keep]) ################
df <- df[, keep, drop=FALSE]
if(!all(is.na(x))) {
x <- x[keep]
}
if(!all(is.na(xax))) {
xax <- xax[keep]
}
if(length(col) > 1) {
col <- col[keep]
}
}
### new
dots <- list(...) # probably a more efficient way to do this
xaxlog <- FALSE
if(!is.null(dots$log)) {
if(!horizontal & dots$log %in% c("x","xy")) {
xaxlog <- TRUE
}
if(horizontal & dots$log %in% c("y","xy")) {
xaxlog <- TRUE
}
}
if(add & par("xlog")) {
xaxlog <- TRUE
}
### new
### new
if(any(is.na(x)) & !all(is.na(x))) {
# df <- df[, !is.na(x)]
df <- df[, which(!is.na(x) & seq_along(x) %in% 1:ncol(df)),
drop=FALSE]
if(any(!is.na(xax))) {
xax <- xax[!is.na(x)]
}
if(length(col) > 1) {
col <- col[!is.na(x)]
}
x <- x[!is.na(x)]
}
### new
transform <- match.arg(transform)
if(transform == "exp") df <- exp(df)
if(transform == "expit") df <- expit(df)
ci <- rev(sort(ci))
loq <- apply(df, 2, quantile, p=(1-ci)/2, na.rm=T)
hiq <- apply(df, 2, quantile, p=1-(1-ci)/2, na.rm=T)
if(length(ci)==1) {
loq <- t(as.matrix(loq))
hiq <- t(as.matrix(hiq))
}
med <- apply(df, 2, median, na.rm=T)
# if(all(is.na(x))) x <- 1:ncol(df)
## new
xorig <- x
xaxorig <- xax
if (all(is.na(x))) {
x <- 1:ncol(df)
}
if(xorder) {
x <- rank(med, na.last=TRUE,ties.method="first")
}
## new
### this was smarterized, make sure it doesn't break other code!!!
# d <- ifelse(length(x)>1, diff(x[1:2]), 1) #########
# d <- ifelse(length(x)>1, diff(range(x, na.rm=TRUE))/length(x), 1) #########
## new
maxl <- min(length(x), 20)
if(xaxlog) {
d <- ifelse(length(x) > 1, diff(range(log(x), na.rm = TRUE))/maxl, 1)
} else {
d <- ifelse(length(x) > 1, diff(range(x, na.rm = TRUE))/maxl, 1)
}
# halfwidth <- 0.2*d ## is the old way
# mextra <- 0.3*d ## is the old way
halfwidth <- 0.2*d*(1 - 0.05*(length(x)^(-2)))
mextra <- padwd*halfwidth#d*length(x)^(-2)
## new
nn <- ncol(df)
if(all(is.na(xax))) xax<-names(df)
lwds <- (1+2*(1:length(ci)-1))*lwd
if(!add) {
# if(is.null(ylim)) ylim <- range(loq,hiq,na.rm=T)
ci_lim <- range(loq, hiq, na.rm=TRUE)
# xlims <- range(x-(.5*d*(1+(length(x)==1))),x+(.5*d*(1+(length(x)==1))))
## new
if(xaxlog) {
# xlims <- exp(range(log(x) - ((halfwidth+mextra)* (1 + (length(x) == 1))),
# log(x) + ((halfwidth+mextra) * (1 + (length(x) == 1)))))
### was xlims
cat_lim <- exp(c(min(log(x)) - ((halfwidth+mextra)* (1 + (length(x) == 1))),
max(log(x)) + ((halfwidth+mextra) * (1 + (length(x) == 1)))))
} else {
# xlims <- range(x - ((halfwidth+mextra) * (1 + (length(x) == 1))),
# x + ((halfwidth+mextra) * (1 + (length(x) == 1))))
cat_lim <- c(min(x) - ((halfwidth+mextra) * (1 + (length(x) == 1))),
max(x) + ((halfwidth+mextra) * (1 + (length(x) == 1))))
}
if(!horizontal) {
if(!is.null(xlim)) {
cat_lim <- xlim
}
if(!is.null(ylim)) {
ci_lim <- ylim
}
cat_lim <- range(cat_lim, xlim_add)
ci_lim <- range(ci_lim, ylim_add)
} else {
if(!is.null(xlim)) {
ci_lim <- xlim
}
if(!is.null(ylim)) {
cat_lim <- ylim
}
cat_lim <- range(cat_lim, ylim_add)
ci_lim <- range(ci_lim, xlim_add)
}
## new
# plot(NA, type='l', xlim=xlims, xlab=xlab, ylab=ylab, main=main, ylim=ylim, xaxt="n", ...=...)
# axis(1,x,labels=xax, las=list(...)$las)
## new
if(!horizontal) {
if(all(is.na(xorig)) | !all(is.na(xaxorig))) {
plot(NA, type = "l", xlim = cat_lim, xlab = xlab, ylab = ylab,
main = main, ylim = ci_lim, xaxt = "n", ... = ...)
smashaxis(side=1, at=x,
labels = xax[seq_along(x)],
las = list(...)$las,
cex.axis = list(...)$cex.axis,
smashall = all_ticks)
} else {
plot(NA, type = "l", xlim = cat_lim, xlab = xlab, ylab = ylab,
main = main, ylim = ci_lim, ... = ...)
}
} else {
if(all(is.na(xorig)) | !all(is.na(xaxorig))) {
plot(NA, type = "l", ylim = rev(cat_lim), xlab = xlab, ylab = ylab,
main = main, xlim = ci_lim, yaxt = "n", ... = ...)
smashaxis(side=2, at=x,
labels = xax[seq_along(x)],
las = list(...)$las,
cex.axis = list(...)$cex.axis,
smashall = all_ticks)
} else {
plot(NA, type = "l", ylim = cat_lim, xlab = xlab, ylab = ylab,
main = main, xlim = ci_lim, ... = ...) # ylim = rev(xlims)
}
}
## new
}
if(median) {
# segments(x0=x-.2*d*medwd,x1=x+.2*d*medwd,y0=med,y1=med,col=col,lwd=medlwd, lend=1)
## new
if(!horizontal) {
if(xaxlog) {
segments(x0 = exp(log(x) - halfwidth * medwd),
x1 = exp(log(x) + halfwidth * medwd),
y0 = med, y1 = med, col = col, lwd = medlwd,
lend = 1)
} else {
segments(x0 = x - halfwidth * medwd,
x1 = x + halfwidth * medwd,
y0 = med, y1 = med, col = col, lwd = medlwd,
lend = 1)
}
} else {
if(xaxlog) {
segments(y0 = exp(log(x) - halfwidth * medwd),
y1 = exp(log(x) + halfwidth * medwd),
x0 = med, x1 = med, col = col, lwd = medlwd,
lend = 1)
} else {
segments(y0 = x - halfwidth * medwd,
y1 = x + halfwidth * medwd,
x0 = med, x1 = med, col = col, lwd = medlwd,
lend = 1)
}
}
## new
}
# if(mean) points(x,colMeans(df, na.rm=T), pch=16, col=col)
# for(i in 1:length(ci)) segments(x0=x,x1=x,y0=loq[i,],y1=hiq[i,],col=col,lwd=lwds[i],lend=1)
## new
if(!horizontal) {
if (mean) {
points(x=x, y=colMeans(df, na.rm = T), pch = 16, col = col)
}
for (i in 1:length(ci)) {
segments(x0 = x, x1 = x,
y0 = loq[i, ], y1 = hiq[i, ],
col = col, lwd = lwds[i], lend = 1)
}
} else {
if (mean) {
points(y=x, x=colMeans(df, na.rm = T), pch = 16, col = col)
}
for (i in 1:length(ci)) {
segments(y0 = x, y1 = x,
x0 = loq[i, ], x1 = hiq[i, ],
col = col, lwd = lwds[i], lend = 1)
}
}
## new
}
# a helper function to smash all axis labels together and
# force all to print
smashaxis <- function(side, at=NULL, labels=TRUE,
smash=FALSE, smashall=FALSE, ...) {
if(!is.null(at) & length(labels) <= 1) {
labels <- at
}
if(!is.null(at) & (length(at) == length(labels)) & smash) {
at1 <- at[seq(from=1, by=2, to=length(at))]
at2 <- at[seq(from=2, by=2, to=length(at))]
labels1 <- labels[seq(from=1, by=2, to=length(at))]
labels2 <- labels[seq(from=2, by=2, to=length(at))]
axis(side=side, at=at1, labels=labels1, ...=...)
axis(side=side, at=at2, labels=labels2, ...=...)
}
if(!is.null(at) & (length(at) == length(labels)) & smashall) {
for(iax in seq_along(at)) {
axis(side=side, at=at[iax], labels=labels[iax], ...=...)
}
}
if(!smash & !smashall) {
axis(side=side, at=at, labels=labels, ...=...)
}
# axis(side=side, at=at, labels=labels, ...=...)
}
# plot(1:10, yaxt='n')
# axis(2, cex.axis=.8)
# smashaxis(side=2, at=1:10, labels=letters[1:10],
# las=1, cex.axis=1.8)
# SS_df <- jags_df(SS_out)
# trend <- pull_post(SS_df, "trend")
# rate <- pull_post(SS_df, "rate")
# caterpillar(rate)
# caterpillar(rate, all_ticks=TRUE)
# caterpillar(rate, all_ticks=TRUE, las=2)
# caterpillar(rate, all_ticks=TRUE, las=2, horizontal=TRUE)
# caterpillar(rate, all_ticks=TRUE, las=2, horizontal=TRUE,
# cex.axis=.2)
# caterpillar(rate, all_ticks=TRUE, las=2, horizontal=FALSE,
# cex.axis=.2)
# caterpillar(rate, all_ticks=TRUE, las=2, horizontal=FALSE,
# cex.axis=.2, xlab="xlab", ylab="ylab")
# caterpillar(rate, all_ticks=TRUE, las=2, horizontal=FALSE,
# cex.axis=.2, xlab="xlab", ylab="ylab", cex.lab=.4)
#' Compare Caterpillar Plots
#' @description Interleaved caterpillar plots for all parameters (or a specified subset) from a list of `jagsUI`
#' output objects or `data.frame`s. The intent of this function is easy comparison of inferences from multiple comparable models.
#'
#' Here a \link{caterpillar} plot is defined as a set of overlayed interval bars (default values are 50 percent and 95 percent),
#' with overlayed median markings, for each of a vector of parameter nodes.
#' @param x List of output objects returned from `jagsUI` or `data.frame`s
#' @param p Optional vector of parameters to subset. All parameters with names matching the beginning of the
#' string supplied will be returned. If the default (`NULL`) is accepted, all parameters will be plotted.
#' @param ci Credible intervals widths to plot. Defaults to 50% and 95%.
#' @param ylim Y-axis limits for plotting. If the default (`NULL`) is accepted, limits will be automatically determined.
#' @param col Vector of colors for plotting. If the default (`NULL`) is accepted, colors will be automatically drawn.
#' @param xlab X-axis label
#' @param ylab Y-axis label
#' @param transform Should the y-axis be (back)transformed? Options are `"exp"`,
#' indicating exponential, or `"expit"`, indicating inverse-logit. Defaults to
#' `"none"`, indicating no transformation. Note: if `transform="exp"`is used, consider
#' adding additional plotting argument `log="y"`.
#' @param ... additional plotting arguments
#' @return `NULL`
#' @seealso \link{caterpillar}, \link{crossplot}, \link{comparedens}, \link{comparepriors}
#' @author Matt Tyers
#' @examples
#' ## This is the same output object three times, but shows functionality.
#' comparecat(x=list(asdf_jags_out, asdf_jags_out, asdf_jags_out),
#' p=c("a","b","sig"))
#'
#' ## Transformed
#' comparecat(x=list(asdf_jags_out, asdf_jags_out, asdf_jags_out),
#' p=c("sig"), transform="exp")
#' comparecat(x=list(asdf_jags_out, asdf_jags_out, asdf_jags_out),
#' p=c("sig"), transform="exp", log="y")
#' @export
comparecat <- function(x, p=NULL, ci=c(0.5,0.95), ylim=NULL, col=NULL, xlab="", ylab="",
transform=c("none", "exp", "expit"), ...) {
if(!inherits(x,"list")) stop("Input must be a (single) list of outputs from jagsUI::jags() or data.frames.")
xdf <- list()
for(i in 1:length(x)) {
if(!inherits(x[[i]], "jagsUI") & !inherits(x[[i]], "data.frame") & !inherits(x[[i]], "matrix")) {
stop("Each input element must be an output from jagsUI::jags() or data.frame.")
}
if(inherits(x[[i]],"jagsUI")) {
xdf[[i]] <- jags_df(x[[i]])
}
if(inherits(x[[i]],"matrix")) {
xdf[[i]] <- as.data.frame(x[[i]])
}
if(inherits(x[[i]],"data.frame")) {
xdf[[i]] <- x[[i]]
}
}
# xdf <- lapply(x, jags_df)
parmx <- list()
# for(i in 1:length(x)) parmx[[i]] <- cbind(pull_post(xdf[[i]],"sig"), phi=pull_post(xdf[[i]],"phi"))
transform <- match.arg(transform)
for(i in 1:length(x)) {
parmx[[i]] <- pull_post(xdf[[i]], p=p)
# parmx[[i]] <- as.matrix(parmx[[i]])
if(transform == "exp") {
for(j in seq_along(parmx[[i]])) { # hopefully seq_along() goes along columns
parmx[[i]][,j] <- exp(parmx[[i]][,j])
}
}
if(transform == "expit") {
for(j in seq_along(parmx[[i]])) { # hopefully seq_along() goes along columns
parmx[[i]][,j] <- expit(parmx[[i]][,j])
}
}
}
# # allparms <- sort(unique(unlist(lapply(parmx,names))))
# allparms <- unique(unlist(lapply(parmx,names)))
allparms <- unique(unlist(lapply(parmx, colnames)))
cilo <- sort(1-ci)/2
cihi <- 1-cilo
lwds <- seq(from=1,by=2,length.out=length(ci))
if(!is.null(ylim)) {
ylims <- ylim
} else {
ylims <- c(min(unlist(sapply(parmx, function(x) apply(x,2,quantile,p=min(cilo),na.rm=T)))),
max(unlist(sapply(parmx, function(x) apply(x,2,quantile,p=max(cihi),na.rm=T)))))
}
plot(NA,xlim=c(0,length(allparms)+1), ylim=ylims, ylab=ylab, xlab=xlab, xaxt="n", ...=...)
axis(1,at=1:length(allparms),labels=allparms,las=2)
# abline(v=1:length(allparms),lty=3)
if(is.null(col)) {
cols <- c(4,2,3,rcolors(100))[1:length(x)]
} else {
cols <- rep(col, 100)
}
for(i in 1:length(allparms)) {
for(ii in 1:length(x)) {
if(allparms[i] %in% names(parmx[[ii]])) {
xplot <- i+(seq(-.3,.3,length.out=length(x)))[ii]
vec <- parmx[[ii]][,which(names(parmx[[ii]])==allparms[i])]
segments(x0=rep(xplot,2), y0=quantile(vec,p=cilo), y1=quantile(vec,p=cihi),
lwd=lwds, lend=1, col=cols[ii]) #col=ii+1
points(xplot,median(vec),pch=16,col=cols[ii]) #col=ii+1
}
}
}
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.