0

I have a forest plot (using metafor) whose number of rows will change depending on the input conditions. My code saves the plot after each run using:

dev.copy(png,'myplot.png')
dev.off()

Depending on the number of rows in the plot, the data can be squashed. Anymore than about 30 rows and the data becomes unreadable, see below examples. The first chart is readable, however the second chart is useless and it only gets worse as I want to include more data.

Is there a way to save the charts so that the height will automatically update to fit in the rows correctly? There is no specific need for the chart to be square, in fact I envisage that it will be rectangular to fit in the data. Chart code is included at the base of the question for reference.

enter image description here

enter image description here

forest(x = final$AvgPts, ci.lb = final$min, ci.ub = final$max, slab = final$Players,
ilab = final$value, ilab.xpos = max(final$max)+10,ilab.pos =4, alim = c(min(final$min)-5,
max(final$max)+5), xlim = c(min(final$min)-170, 2*(max(final$max)+5)), 
xlab = "Moneyball Points Spread", efac = 1, cex = 0.75, mgp = c(1, 1, 0),
refline=mean(final$AvgPts),digits=1,col="dark blue",pch = 19,
main=paste("2016 Moneyball Summary (position =",pos,"and min average >",points,")"))
Morts81
  • 419
  • 3
  • 13

1 Answers1

2

Instead of using dev.copy(), do this:

  1. Determine k (number of studies = number of rows) that will be included in the forest plot.
  2. Open up a plotting device with png() where the height attribute is some appropriate function of k (the larger k, the larger the value for height).
  3. Draw the forest plot.
  4. Close the plotting device with dev.off().
  5. Profit!

Step 2. is actually a bit tricky. With some trial and error, I found that height = 200 + 40*k^.85 seems to work alright. In forest(), you also want to use cex=1 so that the character/symbol expansion factor stays constant and yaxs="i" as otherwise the 4% padding will start to look strange when k is large. But then you also want to adjust ylim so that there is a bit more space between the x-axis and the first row. And finally, you will also have to make efac some appropriate decreasing function of k. Again, after some trial and error, I found that efac=30/(k+10) seems to work.

Here is some code to test this out:

library(metafor)

ks <- c(5, 10, 20, 40, 80, 160, 320)

for (k in ks) {

   vi <- runif(k, .05, 1)
   yi <- rnorm(k, 0, sqrt(vi))

   png(paste0("forest_k=", formatC(k, format="f", flag="0", width=3, digits=0), ".png"), height = 200 + 40*k^.85)
   forest(yi, vi, xlim=c(-10,10), alim=c(-4,4), efac=30/(k+10), cex=1, yaxs="i", ylim=c(0,k+3))
   text(-10, k+2, "Study", pos=4)
   text( 10, k+2, "Estimate [95% CI]", pos=2)
   dev.off()

}

Okay, in the end, this is a bit of a hackish solution, but it appears to work.

There is also https://stackoverflow.com/a/28239750/2615367 which may be more elegant but you will have to check yourself how to make this work.

Community
  • 1
  • 1
Wolfgang
  • 2,810
  • 2
  • 15
  • 29