#' Heat Plot
#'
#' @description
#' Produces a heat plot that contain point estimates of relative
#' effects for all possible pairs of treatments along with credible
#' intervals obtained with the quantile method.
#'
#' @param x An object created with \code{\link{crossnma}}.
#' @param median A logical indicating whether to use the median
#' (default) or mean to measure relative treatment effects.
#' @param backtransf A logical indicating whether results should be
#' back transformed. If \code{backtransf = TRUE}, results for
#' \code{sm = "OR"} are presented as odds ratios rather than log
#' odds ratios, for example.
#' @param seq A vector of treatment names (character) representing
#' the order in which to display these treatments.
#' @param low.colour A string indicating the colour of low relative
#' treatment effects for the heat plot (e.g odds ratio of ~0.5)
#' @param mid.colour A string indicating the colour of null relative
#' treatment effects for the heat plot (e.g odds ratio of ~1.0).
#' @param high.colour A string indicating the colour of high relative
#' treatment effects for the heat plot (e.g odds ratio of ~2.0).
#' @param cov1.value The participant covariate value of \code{cov1}
#' for which to report the results. Must be specified for network
#' meta-regression and when individual participant dataset is used
#' in the analysis. For dichotomous covariates, a character of the
#' level (used in the data) should be indicated.
#' @param cov2.value The participant covariate value of \code{cov2}
#' for which to report the results. Must be specified for network
#' meta-regression and when individual participant dataset is used
#' in the analysis. For dichotomous covariates, a character of the
#' level (used in the data) should be indicated.
#' @param cov3.value The participant covariate value of \code{cov3}
#' for which to report the results. Must be specified for network
#' meta-regression and when individual participant dataset is used
#' in the analysis. For dichotomous covariates, a character of the
#' level (used in the data) should be indicated.
#' @param size The size of cell entries with the relative treatment
#' effect and 95\% credible intervals.
#' @param size.trt The size of treatment names placed on the top and
#' left of the plot.
#' @param size.axis The size of labels on the top and left of the plot
#' @param digits The number of digits to be used when displaying the
#' results.
#' @param exp Deprecated argument (replaced by \code{backtransf}).
#' @param \dots Additional arguments (ignored at the moment).
#'
#' @return
#' League heat plot, where a color scale is used to represent the
#' values of relative treatment effects.
#'
#' @author Tasnim Hamza \email{hamza.a.tasnim@@gmail.com}
#'
#' @seealso \code{\link{crossnma}}
#'
#' @keywords hplot
#'
#' @examples
#' \dontrun{
#' # We conduct a network meta-analysis assuming a random-effects
#' # model. The data comes from randomized-controlled trials and
#' # non-randomized studies (combined naively)
#' head(ipddata) # participant-level data
#' stddata # study-level data
#'
#' # Create a JAGS model
#' mod <- crossnma.model(treat, id, relapse, n, design,
#' prt.data = ipddata, std.data = stddata,
#' reference = "A", trt.effect = "random", method.bias = "naive")
#'
#' # Fit JAGS model
#' set.seed(1909)
#' fit <- crossnma(mod)
#'
#' # Create a heat plot
#' heatplot(fit)
#' }
#'
#' @method heatplot crossnma
#' @export
heatplot.crossnma <- function(x,
median = TRUE,
backtransf = x$model$backtransf,
seq = NULL,
low.colour = "red",
mid.colour = "white",
high.colour = "springgreen4",
cov1.value = NULL,
cov2.value = NULL,
cov3.value = NULL,
size = 6,
size.trt = 20,
size.axis = 12,
digits = gs("digits.forest"),
exp = backtransf,
...) {
chkclass(x, "crossnma")
##
chklogical(median)
if (median)
central.tdcy <- "median"
else
central.tdcy <- "mean"
##
chknumeric(size, min = 0, length = 1)
chknumeric(size.trt, min = 0, length = 1)
chknumeric(size.trt, min = 0, length = 1)
##
chknumeric(digits, min = 0, length = 1)
##
missing.backtransf <- missing(backtransf)
backtransf <-
deprecated2(backtransf, missing.backtransf, exp, missing(exp))
chklogical(backtransf)
if (backtransf & x$model$sm %in% c("MD", "SMD")) {
if (!missing.backtransf)
warning("No back transformation of results for (standardised) ",
"mean differences (argument 'backtransf').")
backtransf <- FALSE
}
##
exp <- backtransf
quant <- x$model$quantiles
if (!is.null(x$model$covariate) & is.null(cov1.value))
stop("cov1.value must be specified for network meta-regression")
## Bind variables to function
trt <- Treatment <- Comparator <- cov.ref <- ct.stat <- lcl <- ucl <- NULL
dmat <-
do.call(rbind, x$samples) %>% data.frame() %>% select(starts_with("d."))
trt.names <- x$trt.key$trt.ini
colnames(dmat) <- trt.names
##
if (is.null(seq))
seq <- trt.names
else
seq <- setseq(seq, trt.names)
##
##
## In the case of network meta-regression
##
##
if (!is.null(x$model$covariate)) {
##
## (a) If IPD is available
##
if (x$model$data$ns.ipd != 0) {
bwmat.cov2 <- bwmat.cov3 <- 0
bbmat.cov2 <- bbmat.cov3 <- 0
bmat.cov2 <- bmat.cov3 <- 0
##
nc <- length(x$model$covariate)
nt <- length(trt.names)
##
labs <- x$model$dich.cov.labels
##
if (x$model$split.regcoef) {
## betaw
if (x$model$regw.effect == "independent") {
bwmat <- do.call(rbind, x$samples) %>% data.frame() %>%
select(starts_with("betaw.t_"))
## split bwmat by nt_column to generate bwmat.cov for each covariate
##
## For factor covariate, multiply by 0 or 1 depends on what
## value the user indicate in cov1.value
##
bwmat.cov1 <- bwmat[, 1:nt] *
if (is.numeric(cov1.value))
cov1.value - x$model$cov.ref[1]
else
as.numeric(labs[labs[, 1] == cov1.value, 2])
##
if (nc == 2)
bwmat.cov2 <-
bwmat[, (nt + 1):(nt * 2)] *
if (is.numeric(cov2.value))
cov2.value - x$model$cov.ref[2]
else
as.numeric(labs[labs[, 1] == cov2.value, 2])
##
if (nc == 3)
bwmat.cov3 <-
bwmat[, (nt * 2 + 1):(nt * 3)] *
if (is.numeric(cov3.value))
cov3.value - x$model$cov.ref[3]
else
as.numeric(labs[labs[, 1] == cov3.value, 2])
##
dmat <- dmat + bwmat.cov1 + bwmat.cov2 + bwmat.cov3
}
else {
bwmat <- do.call(rbind, x$samples) %>% data.frame() %>%
select(starts_with("bw_"))
bwmat.cov1 <-
sweep(cbind(bwmat[, 1]), MARGIN = 2,
if (is.numeric(cov1.value))
cov1.value - x$model$cov.ref[1]
else
as.numeric(labs[labs[, 1] == cov1.value, 2]),
'*')
## repeat the column for each trt to add it to dmat
bwmat.cov1 <-
matrix(unlist(rep(bwmat.cov1, each = nt)), ncol = nt, byrow = TRUE)
##
if (nc == 2) {
bwmat.cov2 <-
sweep(cbind(bwmat[, 2]), MARGIN = 2,
if (is.numeric(cov2.value))
cov2.value - x$model$cov.ref[2]
else
as.numeric(labs[labs[, 1] == cov2.value, 2]),
'*')
bwmat.cov2 <-
matrix(unlist(rep(bwmat.cov2, each = nt)),
ncol = nt, byrow = TRUE)
}
##
if (nc == 3) {
bwmat.cov3 <-
sweep(cbind(bwmat[, 3]), MARGIN = 2,
if (is.numeric(cov3.value))
cov3.value - x$model$cov.ref[3]
else
as.numeric(labs[labs[, 1] == cov3.value, 2]),
'*')
bwmat.cov3 <-
matrix(unlist(rep(bwmat.cov3, each = nt)),
ncol = nt, byrow = TRUE)
}
##
dmat <- dmat + bwmat.cov1 + bwmat.cov2 + bwmat.cov3
}
## betab
if (x$model$regb.effect == "independent") {
bbmat <- do.call(rbind, x$samples) %>% data.frame() %>%
select(starts_with("betab.t_"))
## split bbmat by nt_column to generate bbmat.cov for each
## covariate
stds.mean1 <-
mean(c(x$model$data$xm1.ad, x$model$data$xm1.ipd), na.rm = TRUE)
bbmat.cov1 <- bbmat[, 1:nt] *
if (is.numeric(cov1.value))
stds.mean1 - x$model$cov.ref[1]
else
stds.mean1
##
if (nc == 2) {
stds.mean2 <-
mean(c(x$model$data$xm2.ad, x$model$data$xm2.ipd), na.rm = TRUE)
bbmat.cov2 <- bbmat[, (nt + 1):(nt * 2)] *
if (is.numeric(cov2.value))
stds.mean2 - x$model$cov.ref[2]
else
stds.mean2
}
if (nc == 3) {
stds.mean3 <-
mean(c(x$model$data$xm3.ad, x$model$data$xm3.ipd), na.rm = TRUE)
bbmat.cov3 <- bbmat[, (nt * 2 + 1):(nt * 3)] *
if (is.numeric(cov3.value))
stds.mean3 - x$model$cov.ref[3]
else
stds.mean3
}
##
dmat <- dmat + bbmat.cov1 + bbmat.cov2 + bbmat.cov3
}
else {
stds.mean <-
c(mean(c(x$model$data$xm1.ad, x$model$data$xm1.ipd),na.rm = TRUE),
mean(c(x$model$data$xm2.ad, x$model$data$xm2.ipd),na.rm = TRUE),
mean(c(x$model$data$xm3.ad, x$model$data$xm3.ipd),na.rm = TRUE))
##
bbmat <- do.call(rbind, x$samples) %>% data.frame() %>%
select(starts_with("bb_"))
##
bbmat.cov1 <-
sweep(cbind(bbmat[, 1]), MARGIN = 2,
if (is.numeric(cov1.value))
stds.mean[1] - x$model$cov.ref[1]
else
stds.mean[1],
'*')
bbmat.cov1 <-
matrix(unlist(rep(bbmat.cov1, each = nt)), ncol = nt, byrow = TRUE)
##
if (nc == 2) {
bbmat.cov2 <-
sweep(cbind(bbmat[, 2]), MARGIN = 2,
if (is.numeric(cov2.value))
stds.mean[2] - x$model$cov.ref[2]
else
stds.mean[2],
'*')
bbmat.cov2 <-
matrix(unlist(rep(bbmat.cov2, each = nt)),
ncol = nt, byrow = TRUE)
}
##
if (nc == 3) {
bbmat.cov3 <-
sweep(cbind(bbmat[, 3]), MARGIN = 2,
if (is.numeric(cov3.value))
stds.mean[3] - x$model$cov.ref[3]
else
stds.mean[3],
'*')
bbmat.cov3 <-
matrix(unlist(rep(bbmat.cov3, each = nt)),
ncol = nt, byrow = TRUE)
}
##
dmat <- dmat + bbmat.cov1 + bbmat.cov2 + bbmat.cov3
}
}
else {
if (x$model$regb.effect == "independent" &&
x$model$regw.effect == "independent") {
bmat <- do.call(rbind, x$samples) %>% data.frame() %>%
select(starts_with("beta.t_"))
## For factor covariate, multiply by 0 or 1 depends on what
## value the user indicate in cov1.value
##
bmat.cov1 <-
bmat[, 1:nt] *
if (is.numeric(cov1.value))
cov1.value - x$model$cov.ref[1]
else
as.numeric(labs[labs[, 1] == cov1.value, 2])
##
if (nc == 2)
bmat.cov2 <-
bmat[, (nt + 1):(nt * 2)] *
if (is.numeric(cov2.value))
cov2.value - x$model$cov.ref[2]
else
as.numeric(labs[labs[, 1] == cov2.value, 2])
##
if (nc == 3)
bmat.cov3 <-
bmat[, (nt * 2 + 1):(nt * 3)] *
if (is.numeric(cov3.value))
cov3.value - x$model$cov.ref[3]
else
as.numeric(labs[labs[, 1] == cov3.value, 2])
##
dmat <- dmat + bmat.cov1 + bmat.cov2 + bmat.cov3
}
else {
bmat <- do.call(rbind, x$samples) %>% data.frame() %>%
select(starts_with("b_"))
bmat.cov1 <-
sweep(cbind(bmat[, 1]), MARGIN = 2,
if (is.numeric(cov1.value))
cov1.value - x$model$cov.ref[1]
else
as.numeric(labs[labs[, 1] == cov1.value, 2]),
'*')
## repeat the column for each trt to add it to dmat
bmat.cov1 <-
matrix(unlist(rep(bmat.cov1, each = nt)), ncol = nt, byrow = TRUE)
##
if (nc == 2) {
bmat.cov2 <-
sweep(cbind(bmat[, 2]), MARGIN = 2,
if (is.numeric(cov2.value))
cov2.value - x$model$cov.ref[2]
else
as.numeric(labs[labs[, 1] == cov2.value, 2]),
'*')
bmat.cov2 <-
matrix(unlist(rep(bmat.cov2, each = nt)),
ncol = nt, byrow = TRUE)
}
##
if (nc == 3) {
bmat.cov3 <-
sweep(cbind(bmat[, 3]), MARGIN = 2,
if (is.numeric(cov3.value))
cov3.value - x$model$cov.ref[3]
else
as.numeric(labs[labs[, 1] == cov3.value, 2]),
'*')
bmat.cov3 <-
matrix(unlist(rep(bmat.cov3, each = nt)),
ncol = nt, byrow = TRUE)
}
##
dmat + bmat.cov1 + bmat.cov2 + bmat.cov3
}
}
}
else {
##
## (b) if only AD is available (i.e., only betab)
##
bbmat.cov2 <- bbmat.cov3 <- 0
##
if (x$model$regb.effect == "independent") {
bbmat <- do.call(rbind, x$samples) %>% data.frame() %>%
select(starts_with("beta.t_"))
## split bbmat by nt_column to generate bbmat.cov for each
## covariate
stds.mean1 <- x$model$data$xm1.ad
bbmat.cov1 <- bbmat[, 1:nt] *
if (!is.na(cov.ref[1]))
stds.mean1 - x$model$cov.ref[1]
else
stds.mean1
##
if (nc == 2) {
stds.mean2 <- x$model$data$xm2.ad
bbmat.cov2 <-
bbmat[, (nt + 1):(nt * 2)] *
if (!is.na(cov.ref[2]))
stds.mean2 - x$model$cov.ref[2]
else
stds.mean2
}
##
if (nc == 3) {
stds.mean3 <- x$model$data$xm3.ad
bbmat.cov3 <- bbmat[, (nt * 2 + 1):(nt * 3)] *
if (!is.na(cov.ref[3]))
stds.mean3 - x$model$cov.ref[3]
else
stds.mean3
}
##
dmat <- dmat + bbmat.cov1 + bbmat.cov2 + bbmat.cov3
}
else {
stds.mean <-
c(x$model$data$xm1.ad, x$model$data$xm2.ad, x$model$data$xm3.ad)
bbmat <- do.call(rbind, x$samples) %>% data.frame() %>%
select(starts_with("b_"))
bbmat.cov1 <-
sweep(cbind(bbmat[, 1]), MARGIN = 2,
if (!is.na(cov.ref[1]))
stds.mean[1] - x$model$cov.ref[1]
else stds.mean[1],
'*')
bbmat.cov1 <-
matrix(unlist(rep(bbmat.cov1, each = nt)), ncol = nt, byrow = TRUE)
##
if (nc == 2) {
bbmat.cov2 <-
sweep(cbind(bbmat[, 2]), MARGIN = 2,
if (!is.na(cov.ref[2]))
stds.mean[2] - x$model$cov.ref[2]
else
stds.mean[2],
'*')
bbmat.cov2 <-
matrix(unlist(rep(bbmat.cov2, each = nt)), ncol = nt, byrow = TRUE)
}
##
if (nc == 3) {
bbmat.cov3 <-
sweep(cbind(bbmat[, 3]), MARGIN = 2,
if (!is.na(cov.ref[3]))
stds.mean[3] - x$model$cov.ref[3]
else
stds.mean[3],
'*')
bbmat.cov3 <-
matrix(unlist(rep(bbmat.cov3, each = nt)), ncol = nt, byrow = TRUE)
}
##
dmat <- dmat + bbmat.cov1 + bbmat.cov2 + bbmat.cov3
}
}
}
##
dmat %<>% select(seq)
trt.names <- seq
## Useful functions to compute some statistics
##
calc.report <- function(x, fct = "identity", arg = NULL,
trans = "identity") {
if (is.null(arg))
eval(call(fct,(call(trans, x))))
else
eval(call(fct,(call(trans, x)), arg))
}
##
exp.mean <- function(x)
calc.report(x, "mean", trans = "exp")
exp.median <- function(x)
calc.report(x, "median", trans = "exp")
exp.sd <- function(x)
calc.report(x, "sd", trans = "exp")
exp.lcl <- function(x)
calc.report(x, "quantile", arg = quant[1], trans = "exp")
exp.ucl <- function(x)
calc.report(x, "quantile", arg = quant[3], trans = "exp")
##
id.mean <- function(x)
calc.report(x, "mean", trans = "identity")
id.median <- function(x)
calc.report(x, "median", trans = "identity")
id.sd <- function(x)
calc.report(x, "sd", trans = "identity")
id.lcl <- function(x)
calc.report(x, "quantile", arg = quant[1], trans = "identity")
id.ucl <- function(x)
calc.report(x, "quantile", arg = quant[3], trans = "identity")
##
colvals <- function(dmat, b.col=1, paste = TRUE) {
## Bind variables to function
key <- value <- trt <- estimate <- lcl <- ucl <- result <- NULL
#base <- colnames(dmat)[b.col]
dmat2 <- dmat
new.vars <- paste0(colnames(dmat2), "-", b.col)
for (i in 1:ncol(dmat)) {
dmat2[[new.vars[i]]] <- dmat[, i] - dmat[, b.col]
}
dmat2 %<>% select(new.vars)
colnames(dmat2) <- trt.names
if (central.tdcy == "mean" & exp) {
tmp.estimate <- dmat2 %>%
summarise_all(list(estimate = exp.mean)) %>% gather() %>%
rename(trt = key, estimate = value) %>%
mutate(trt = sub("_estimate", "", trt))
}
else if (central.tdcy == "mean" & exp == FALSE) {
tmp.estimate <- dmat2 %>%
summarise_all(list(estimate = id.mean)) %>% gather() %>%
rename(trt = key, estimate = value) %>%
mutate(trt = sub("_estimate", "", trt))
}
##
if (central.tdcy == "median" & exp) {
tmp.estimate <- dmat2 %>%
summarise_all(list(estimate = exp.median))%>% gather() %>%
rename(trt = key, estimate = value) %>%
mutate(trt = sub("_estimate", "", trt))
}
else if (central.tdcy == "median" & exp == FALSE) {
tmp.estimate <- dmat2 %>%
summarise_all(list(estimate = id.median)) %>% gather() %>%
rename(trt = key, estimate = value) %>%
mutate(trt = sub("_estimate", "", trt))
}
##
if (exp) {
tmp.lcl <- dmat2 %>%
summarise_all(list(lcl = exp.lcl)) %>% gather() %>%
rename(trt = key, lcl = value) %>%
mutate(trt = sub("_lcl", "", trt))
##
tmp.ucl <- dmat2 %>%
summarise_all(list(ucl = exp.ucl)) %>% gather() %>%
rename(trt = key, ucl = value) %>%
mutate(trt = sub("_ucl", "", trt))
##
null.value <- 1
}
else {
tmp.lcl <- dmat2 %>%
summarise_all(list(lcl = id.lcl)) %>% gather() %>%
rename(trt = key, lcl = value) %>%
mutate(trt = sub("_lcl", "", trt))
##
tmp.ucl <- dmat2 %>%
summarise_all(list(ucl = id.ucl)) %>% gather() %>%
rename(trt = key, ucl = value) %>%
mutate(trt = sub("_ucl", "", trt))
##
null.value <- 0
}
## create C-style formatting string from the digits parameter
fmt <- paste0("%.", digits, "f")
if (paste) {
tmp1 <- left_join(tmp.estimate, tmp.lcl, by = "trt") %>%
left_join(tmp.ucl, by = "trt") %>%
mutate(result = paste(sprintf(fmt, estimate),
formatCI(round(lcl, digits),
round(ucl, digits)))) %>%
select(trt, result)
colnames(tmp1)[2] <-
as.character(tmp.estimate %>% filter(estimate == null.value) %>%
select(trt))
}
else {
tmp1 <- left_join(tmp.estimate, tmp.lcl, by = "trt") %>%
left_join(tmp.ucl, by = "trt")
colnames(tmp1)[2] <- central.tdcy
}
tmp1
}
## Long layout
##
tmp2.list <- list()
for (i in 1:ncol(dmat))
tmp2.list[[i]] <- colvals(dmat, b.col=i, paste = FALSE)
##
longtable <- tmp2.list %>%
bind_rows() %>%
mutate(Treatment = trt,
Comparator = rep(trt.names, each=length(trt.names))) %>%
select(Treatment, Comparator, everything(), -trt)
##
league.tmp <- longtable %>% filter(Treatment != Comparator)
## Rename central tendancy statistic to ct.stat
names(league.tmp)[names(league.tmp) == central.tdcy] <- "ct.stat"
## Create C-style formatting string from the digits parameter
fmt <- paste0("%.", digits, "f")
##
##
## Create heat plot
##
##
hplot <-
ggplot(data = league.tmp,
aes(x = Treatment, y = Comparator, fill = ct.stat)) +
geom_tile() +
geom_text(aes(label = paste0(sprintf(fmt, ct.stat), "\n",
formatCI(round(lcl, digits),
round(ucl, digits)))),
size = size)
hplot <- hplot +
scale_fill_gradient2(low = low.colour,
mid = mid.colour,
high = high.colour,
midpoint = 1 * exp) +
theme_dark() +
theme(panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
legend.position = "none", panel.border = element_blank(),
axis.ticks.x = element_blank(),
axis.ticks.y = element_blank(),
axis.text = element_text(size = size.trt),
axis.title = element_text(size = size.axis)) +
scale_x_discrete(limits = seq, expand = c(0, 0), position = "top") +
scale_y_discrete(limits = rev(seq), expand = c(0, 0))
return(hplot)
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.