Michael Schmitz
Michael Schmitz

Reputation: 55

forest plot point size

In the documentation of the metafor library it says, that if the optional argument psize is unspecified, the point sizes are drawn proportional to the precision of the estimates. As far as I know, precision is the reciprocal of the variance.

  1. How does the metafor library calculate the point size from the confidence interval?

  2. How can I enlarge only the point size? cex also affects the text size.

example

library(metafor)
model_data <- read.table(dec = ",", text="
                                          OR        lower       upper
                         age              0,9678479 0,9326182   1,002493
                         sex              1,0679667 0,4987457   2,280504
                         ApacheeII        0,9288701 0,8728417   0,984529",
                         header=T)

forest(x=model_data$OR, 
       ci.lb=model_data$lower, 
       ci.ub=model_data$upper, 
       annotate=TRUE, 
       cex=1.2, 
       at=seq(0,6,1),
       refline=1, 
       digits=c(3,1), 
       xlim=c(-1,2),
       xlab="OR",
       slab=rownames(model_data))

Upvotes: 1

Views: 1591

Answers (2)

Michael Schmitz
Michael Schmitz

Reputation: 55

Thanks for your help!

With your hints and the source code of the function I finally managed to give a factor to the point size alone:

library(metafor)
model_data <- read.table(dec = ",", text="
                                          OR        lower       upper
                         age              0,9678479 0,9326182   1,002493
                         sex              1,0679667 0,4987457   2,280504
                         ApacheeII        0,9288701 0,8728417   0,984529",
                         header=T)

dat <- log(model_data)
ci.lb = dat$lower
ci.ub = dat$upper

#taken from forest.default source code
level = 95
alpha <- ifelse(level > 1, (100 - level)/100, 1 - level)
vi <- ((ci.ub - ci.lb)/(2 * qnorm(alpha/2, lower.tail = FALSE)))^2
wi <- 1/sqrt(vi)
psize <- wi/sum(wi, na.rm = TRUE)
psize <- (psize - min(psize, na.rm = TRUE))/(max(psize, 
                                                 na.rm = TRUE) - min(psize, na.rm = TRUE))
psize <- (psize * 1) + 0.5

forest(x=dat$OR, 
       ci.lb = ci.lb,
       ci.ub = ci.ub,
       cex = 1.5,
       annotate=FALSE, 
       at=seq(-1,1,1),
       xlim=c(-1.1,1.1),
       xlab="OR",
       slab=rownames(dat),
       psize=psize*.7,
       atransf=exp
)

Upvotes: 1

Wolfgang
Wolfgang

Reputation: 3395

As for 1:

The relevant line of code in forest.default() is:

vi <- ((ci.ub - ci.lb) / (2*qnorm(alpha/2, lower.tail=FALSE)))^2

So, the function assumes you are supplying the bounds of a symmetric Wald-tye confidence interval (CI) to the function and then back-calculates the variance based on that. This would be appropriate for log odds ratios and the corresponding CI bounds on the log scale, but you are apparently directly applying the ORs and CI bounds on the raw scale to the function. Then this makes less sense. Usually, CIs for odds ratios are actually first calculated on the log scale (and are then exponentiated). This also appears to the case for these data:

round(with(model_data, log(upper) - log(OR)), 2)
round(with(model_data, log(OR) - log(lower)), 2)

This shows that on the log scale, the CI bounds are symmetric (around log(OR)). So, these CI bounds are very likely Wald-type CIs on the log scale. So, it would make more sense to do this:

dat <- log(model_data)

forest(x=dat$OR, ci.lb=dat$lower, ci.ub=dat$upper,
       annotate=TRUE, cex=1.2, at=seq(-2,2,1), digits=c(3,1),
       xlim=c(-5,7), xlab="OR", slab=rownames(dat), atransf=exp)

So, supply log(OR) and the corresponding CI bounds to the function and then use the atransf argument for the back-transformation. In essence, this puts the x-axis on the log-scale.

As for 2:

You will have to compute the point sizes yourself and then supply them to the function via the psize argument.

Upvotes: 2

Related Questions