# [R-meta] Question on Forest Plot by subgroups

Viechtbauer, Wolfgang (NP) wo||g@ng@v|echtb@uer @end|ng |rom m@@@tr|chtun|ver@|ty@n|
Fri Jun 23 16:13:29 CEST 2023

```Dear Gabriel,

I did not look at the details of your code as it is a bit much to digest on a Friday afternoon.

However, if you have a model that contains moderators and you want to add polygons to a forest plot based on such a model, you need to use predict() with 'newmods' set in such a way that you get the desired predicted values. The results can then fed into addpoly(). Here is a simpler example to illustrate this:

library(metafor)

dat <- escalc(measure="RR", ai=tpos, bi=tneg, ci=cpos, di=cneg,
data=dat.bcg, slab=paste0(author, ", ", year))

# standard random-effects model
res <- rma(yi, vi, data=dat)
res

# set up the forest plot

# meta-regression model using 'alloc' as a moderator
res <- rma(yi, vi, mods = ~ 0 + alloc, data=dat)

# obtain the predicted effects for each level of 'alloc'
pred <- predict(res, newmods=diag(3))

# add these predicted effects as polygons to the plot

abline(h=-2)

Hopefully, this gives you an idea how you can do something analogous in your example.

Best,
Wolfgang

>-----Original Message-----
>From: Gabriel Cotlier [mailto:gabiklm01 using gmail.com]
>Sent: Friday, 23 June, 2023 15:15
>To: Viechtbauer, Wolfgang (NP)
>Cc: R Special Interest Group for Meta-Analysis
>Subject: Re: [R-meta] Question on Forest Plot by subgroups
>
>Hello all,
>
>I think I solve partially the problem since I can plot the forest graph with the
>subgroup size effect in it together with the model size effect of the complete
>dataset however it is missing  to plot the diamond corresponding to the size
>effect of the groups for both moderartor generated groups in resSep using
>addpoly() funcion that gives the following error:
>
>Error in addpoly.rma(resSep, row = 16, mlab = "", efac = 0.5, col = "blue") :
>  Fitted model should not contain moderators.
>
>Error in addpoly.rma(resSep, row = 1, mlab = "", efac = 0.5, col = "green") :
>  Fitted model should not contain moderators.
>
>Does anyone know how the diamonds polygon for the size effect could be plotted ?
>Thanks a lot.
>Regards,
>Gabriel
>
>#########################################-- code for graph--
>######################################
>png(filename="ForestComputerSimulationPositiveAndNegatives.png",
>    res=95, width=1300, height=880, type="cairo")
>
>mlabfun <- function(text, res) {
>  list(bquote(paste(.(text),
>                    " (Q = ", .(formatC(res\$QE, digits=2, format="f")),
>                    ", df = ", .(res\$k - res\$p),
>                    ", p ", .(metafor:::.pval(res\$QEp, digits=2, showeq=TRUE,
>sep=" ")), "; ",
>                    I^2, " = ", .(formatC(I_TOT, digits=1, format="f")), "%, ",
>                    paste(sigma^2,sep = "_", "1"), " = ",
>.(formatC(res\$sigma2[1], digits=3, format="f")), " ",
>                    paste(sigma^2,sep = "_", "2"), " = ",
>.(formatC(res\$sigma2[2], digits=3, format="f")),")")))}
>
>
>mlabfun1 <- function(text, resSep) {
>  list(bquote(paste(.(text),
>                    " (Q = ", .(formatC(resSep\$QE, digits=2, format="f")),
>                    ", df = ", .(resSep\$k - resSep\$p),
>                    ", p ", .(metafor:::.pval(resSep\$QEp, digits=2, showeq=TRUE,
>sep=" ")), "; ",
>                 #   I^2, " = ", .(formatC(I_TOT, digits=1, format="f")), "%, ",
>                    paste(sigma^2,sep = "_", "1"), " = ",
>.(formatC(resSep\$sigma2[1], digits=3, format="f")), " ",
>                    paste(sigma^2,sep = "_", "2"), " = ",
>.(formatC(resSep\$sigma2[2], digits=3, format="f")),")")))}
>
>forest(res,
>       top = 2,
>       # xlim=c(-8, 6),
>       # alim = c(-3.36077, 5.181815),
>       alim = c(-2, 6),
>       # at=log(c(0.05, 0.25, 1, 4)),
>       # atransf=exp,
>       # width = 4,
>       showweights = TRUE,
>       ilab=cbind(ni),  # content of extra columns of informaiton
>       ilab.xpos=c(-4.6), # position of extra columns od information
>       cex=1,
>       ylim=c(-1, 22.5), # rows in the y-axis from min-row to max-row with text.
>       slab = paste(dat\$Authors, dat\$Year, sep = ", "),
>       order=alloc_char,
>       rows=c(2:13,17:18), # this devide by groups the studeies (3 groups)
>=ageregar 4 esopacios entre lineas
>       mlab=mlabfun("RE Model", res),
>       # mlab="",
>       # psize= 1 ,
>       efac = 0.5, # size of the polygon (the diamond)
>)
># abline(h=res\$k+8, lwd=2, col="white")
>
>### set font expansion factor (as in forest() above) and use a bold font
>op <- par(cex=0.75, font=2)
>
>text(c(-10.8), res\$k+6,  c("Author(s) and Year"), cex = 1.4, font = 2)
>text(c(-4.6), res\$k+6,  c("Samples size"), cex = 1.4, font = 2)
>text(c(8.3),  res\$k+6,  c("Weight"),cex = 1.4, font=2)
>text(c(8.3),  res\$k+5.3, c("%"),cex = 1.4, font=2)
>text(c(10.8),  res\$k+6,  c("Fisher's zr [95% CI]"),cex = 1.4, font=2)
>text(c(res\$k+9), c("Computer Simulation Dataset"), cex = 2, font = 2)
>
>
>### switch to bold italic font
>par(font=4)
>
>### add text for the subgroups
>text(-12.3, c(14,19), pos=4, c("Positive",
>                               "Negative"), cex = 1.4)
>
>### set par back to the original settings
>par(op)
>
>### add summary polygons for the three subgroups
>addpoly(resSep, row= 16, mlab="" , efac = 0.5, col='blue')
>addpoly(resSep, row= 1,  mlab="", efac = 0.5, col='green')
>
># text(x=-1, y=-2:80, labels=c(-2:80), col = "red" )
>
>text(-12.5, 1, pos = 4, cex = 0.90, bquote(paste("RE Model (Q = ",
>.(formatC(resSep\$QE, digits=2, format="f")),
>                                                 ", df = ", .(resSep\$k -
>resSep\$p),
>                                                 ", p = ",
>.(metafor:::.pval(resSep\$QEp, digits=2, showeq=TRUE, sep=" ")), "; ",
>                                                 # I^2, " = ", .(formatC(I_NEG,
>digits=1, format="f")), "%, ",
>                                                 paste(sigma^2,sep = "_", "1"), "
>= ", .(formatC(resSep\$sigma2[1], digits=3, format="f")), " ",
>                                                 paste(sigma^2,sep = "_", "2"), "
>= ", .(formatC(resSep\$sigma2[2], digits=3, format="f"))
>)))
>
>
>text(-12.5, 16, pos = 4, cex = 0.90, bquote(paste("RE Model (Q = ",
>.(formatC(resSep\$QE, digits=2, format="f")),
>                                                  ", df = ", .(resSep\$k -
>resSep\$p),
>                                                  ", p = ",
>.(metafor:::.pval(resSep\$QEp, digits=2, showeq=TRUE, sep=" ")), "; ",
>                                                  # I^2, " = ", .(formatC(I_POS,
>digits=1, format="f")), "%, ",
>                                                  paste(sigma^2,sep = "_", "1"),
>" = ", .(formatC(resSep\$sigma2[1], digits=3, format="f")), " ",
>                                                  paste(sigma^2,sep = "_", "2"),
>" = ", .(formatC(resSep\$sigma2[2], digits=3, format="f"))
>)))
>
>text(10.8, 1, pos = 4, cex = 0.90, round(coef(resSep)[[1]],3))
>text(10.8, 16, pos = 4, cex = 0.90, round(coef(resSep)[[2]],3))
>
>dev.off()
```