Forest plots date back to 1970s and are most frequently seen in meta-analysis, but are in no way restricted to these. The forestplot
function of this package is a development of the ‘rmeta’-package’s forestplot
function.
Apart from generating a basic forest plot merging text with confidence lines and summary indicators, the forestplot
has a few additional capabilities:
expression(beta)
fontfamily
, fontface
, cex
, etc) for both summary and regular rows. This can be specified down to the each cell.unit
s‡ Features present int the original rmeta::forestplot
function.
Note: An important difference from the original forestplot
is that the current function interprets xlog as the x-axis being in log-format, i.e. you need to provide the data in the antilog/exp format.
A forest plot is closely connected to text and the ability to customize the text is central.
Below is a basic example from the original forestplot
function that shows how to use a table of text:
library(forestplot)
# Cochrane data from the 'rmeta'-package
cochrane_from_rmeta <-
structure(list(
mean = c(NA, NA, 0.578, 0.165, 0.246, 0.700, 0.348, 0.139, 1.017, NA, 0.531),
lower = c(NA, NA, 0.372, 0.018, 0.072, 0.333, 0.083, 0.016, 0.365, NA, 0.386),
upper = c(NA, NA, 0.898, 1.517, 0.833, 1.474, 1.455, 1.209, 2.831, NA, 0.731)),
.Names = c("mean", "lower", "upper"),
row.names = c(NA, -11L),
class = "data.frame")
tabletext<-cbind(
c("", "Study", "Auckland", "Block",
"Doran", "Gamsu", "Morrison", "Papageorgiou",
"Tauesch", NA, "Summary"),
c("Deaths", "(steroid)", "36", "1",
"4", "14", "3", "1",
"8", NA, NA),
c("Deaths", "(placebo)", "60", "5",
"11", "20", "7", "7",
"10", NA, NA),
c("", "OR", "0.58", "0.16",
"0.25", "0.70", "0.35", "0.14",
"1.02", NA, "0.53"))
forestplot(tabletext,
cochrane_from_rmeta,new_page = TRUE,
is.summary=c(TRUE,TRUE,rep(FALSE,8),TRUE),
clip=c(0.1,2.5),
xlog=TRUE,
col=fpColors(box="royalblue",line="darkblue", summary="royalblue"))
If we present a regression output it is sometimes convenient to have non-ascii letters. We will use my study comparing health related quality of life 1 year after total hip arthroplasties between Sweden and Denmark for this section:
data(HRQoL)
clrs <- fpColors(box="royalblue",line="darkblue", summary="royalblue")
tabletext <-
list(c(NA, rownames(HRQoL$Sweden)),
append(list(expression(beta)), sprintf("%.2f", HRQoL$Sweden[,"coef"])))
forestplot(tabletext, new_page = TRUE,
rbind(rep(NA, 3),
HRQoL$Sweden),
col=clrs,
xlab="EQ-5D index")
Altering fonts may give a completely different feel to the table:
tabletext <- cbind(rownames(HRQoL$Sweden),
sprintf("%.2f", HRQoL$Sweden[,"coef"]))
forestplot(tabletext,
txt_gp = fpTxtGp(label = gpar(fontfamily = "HersheyScript")),
rbind(HRQoL$Sweden),
col=clrs,
xlab="EQ-5D index")
There is also the possibility of being selective in gp-styles:
forestplot(tabletext,
txt_gp = fpTxtGp(label = list(gpar(fontfamily = "HersheyScript"),
gpar(fontfamily = "",
col = "#660000")),
ticks = gpar(fontfamily = "", cex=1),
xlab = gpar(fontfamily = "HersheySerif", cex = 1.5)),
rbind(HRQoL$Sweden),
col=clrs,
xlab="EQ-5D index")
Clipping the interval is convenient for uncertain estimates in order to retain the resolution for those of more interest. The clipping simply adds an arrow to the confidence interval, see the bottom estimate below:
forestplot(tabletext,
rbind(HRQoL$Sweden),
clip =c(-.1, Inf),
col=clrs,
xlab="EQ-5D index")
When combining similar outcomes for the same exposure I’ve found it useful to use multiple bands per row. This efficiently increases the data-ink ratio while making the comparison between the two bands trivial. The first time I’ve used this was in my article comparing Swedish with Danish patients 1 year after total hip arthroplasty. Here the clipping also becomes obvious as the Danish sample was much smaller, resulting in wider confidence intervals.
tabletext <- tabletext[,1]
forestplot(tabletext,
mean = cbind(HRQoL$Sweden[, "coef"], HRQoL$Denmark[, "coef"]),
lower = cbind(HRQoL$Sweden[, "lower"], HRQoL$Denmark[, "lower"]),
upper = cbind(HRQoL$Sweden[, "upper"], HRQoL$Denmark[, "upper"]),
clip =c(-.1, 0.075),
col=fpColors(box=c("blue", "darkred")),
xlab="EQ-5D index")
You can choose between a number of different estimate indicators. Using the example above we can set the Danish results to circles.
forestplot(tabletext,
fn.ci_norm = c(fpDrawNormalCI, fpDrawCircleCI),
boxsize = .25, # We set the box size to better visualize the type
line.margin = .1, # We need to add this to avoid crowding
mean = cbind(HRQoL$Sweden[, "coef"], HRQoL$Denmark[, "coef"]),
lower = cbind(HRQoL$Sweden[, "lower"], HRQoL$Denmark[, "lower"]),
upper = cbind(HRQoL$Sweden[, "upper"], HRQoL$Denmark[, "upper"]),
clip =c(-.125, 0.075),
col=fpColors(box=c("blue", "darkred")),
xlab="EQ-5D index")
The confidence interval/box drawing functions are fully customizeable. You can write your own function that accepts the parameters: lower_limit, estimate, upper_limit, size, y.offset, clr.line, clr.marker, and lwd.
Adding a basic legend is done through the legend
argument:
forestplot(tabletext,
legend = c("Sweden", "Denmark"),
fn.ci_norm = c(fpDrawNormalCI, fpDrawCircleCI),
boxsize = .25, # We set the box size to better visualize the type
line.margin = .1, # We need to add this to avoid crowding
mean = cbind(HRQoL$Sweden[, "coef"], HRQoL$Denmark[, "coef"]),
lower = cbind(HRQoL$Sweden[, "lower"], HRQoL$Denmark[, "lower"]),
upper = cbind(HRQoL$Sweden[, "upper"], HRQoL$Denmark[, "upper"]),
clip =c(-.125, 0.075),
col=fpColors(box=c("blue", "darkred")),
xlab="EQ-5D index")
This can be further customized by setting the legend_args
argument using the fpLegend
function:
forestplot(tabletext,
legend_args = fpLegend(pos = list(x=.85, y=0.25),
gp=gpar(col="#CCCCCC", fill="#F9F9F9")),
legend = c("Sweden", "Denmark"),
fn.ci_norm = c(fpDrawNormalCI, fpDrawCircleCI),
boxsize = .25, # We set the box size to better visualize the type
line.margin = .1, # We need to add this to avoid crowding
mean = cbind(HRQoL$Sweden[, "coef"], HRQoL$Denmark[, "coef"]),
lower = cbind(HRQoL$Sweden[, "lower"], HRQoL$Denmark[, "lower"]),
upper = cbind(HRQoL$Sweden[, "upper"], HRQoL$Denmark[, "upper"]),
clip =c(-.125, 0.075),
col=fpColors(box=c("blue", "darkred")),
xlab="EQ-5D index")
Ok, that’s it. I hope you find the additions to the original forestplot
useful.