Related
My example data is as follows:
df <- data.frame(study = c("Hodaie","Kerrigan","Lee","Andrade","Lim"), SR = c(0.5460, 0.2270, 0.7540, 0.6420, 0.5000), SE = c(12.30, 15.70, 12.80, 13.80, 9.00), Patients = c(5, 5, 3, 6, 4))
I want to conduct the meta-analysis with SR(single group percentage), SE (standard error that I can compute based on sample size and percentage), and patients(sample size for each study), and I hope I could get the following forest plot (I found this example in an article, and they also have one group percentage data, but I can't find which R statement or argument they used):
Could anyone tell me which R statement or argument that I could use to conduct the meta-analysis and generate the forest plot above? Thank you!
I am sure there are plenty of ways to do this using packages but it can be accomplished in base R (and there are likely more elegant solutions using base R). The way I do it is to first build a blank plot much larger than the needed graphing portion, then overlay the relevant elements on it. I find one has more control over it this way. A basic example that could get you started is below. If you are new to R (based on your name NewRUser), I suggest running it line-by-line to see how it all works. Again, this is only one way and there are likely better approaches. Good luck!
Sample Data
#### Sample Data (modified from OP)
df <- data.frame(Study = c("Hodaie","Kerrigan","Lee","Andrade","Lim"),
SR = c(0.5460, 0.2270, 0.7540, 0.6420, 0.5000),
SE = c(12.30, 15.70, 12.80, 13.80, 9.00),
Patients = c(5, 5, 3, 6, 4),
ci_lo = c(30, -8.0, 50, 37, 32),
ci_hi = c(78, 53, 100, 91, 67))
### Set up plotting elements
n.studies <- nrow(df)
yy <- n.studies:1
seqx <- seq(-100, 100, 50)
## blank plot much larger than needed
plot(range(-550, 200), range(0, n.studies), type = 'n', axes = F, xlab = '', ylab = '') #blank plot, much bigger than plotting portion needed
# Set up axes
axis(side = 1, at = seqx, labels = seqx, cex.axis = 1, mgp = c(2, 1.5, 1)) # add axis and label (bottom)
mtext(side = 1, at = 0, 'Seizure Reduction', line = 2.5, cex = 0.85, padj = 1)
axis(side = 3, at = seqx, labels = seqx, cex.axis = 1, mgp = c(2, 1.5, 1)) # add axis and label (top)
mtext(side = 3, at = 0, 'Seizure Reduction', line = 2.5, cex = 0.85, padj = -1)
## add lines and dots
segments(df[, "ci_lo"], yy, df[,"ci_hi"], yy) # add lines
points(df[,"SR"]*100, yy, pch = 19) # add points
segments(x0 = 0, y0 = max(yy), y1 = 0, lty = 3, lwd = 0.75) #vertical line # 0
### Add text information
par(xpd = TRUE)
text(x = -550, y = yy, df[,"Study"], pos = 4)
text(x = -450, y = yy, df[,"SR"]*100, pos = 4)
text(x = -350, y = yy, df[,"SE"], pos = 4)
text(x = -250, y = yy, df[,"Patients"], pos = 4)
text(x = 150, y = yy, paste0(df[,"ci_lo"], "-", df[,"ci_hi"]), pos = 4)
text(x = c(seq(-550, -250, 100), 150), y = max(yy)+0.75,
c(colnames(df)[1:4], "CI"), pos = 4, font = 2)
# Add legend
legend(x = 50, y = 0.5, c("Point estimate", "95% Confidence interval"),
pch = c(19, NA), lty = c(NA, 19), bty = "n", cex = 0.65)
I have written following code for comparing between to different variables over a period. The code works fine but only problem is when i output the file as "jpeg" the lines are not smooth and my arrow is not as smooth as i like it to be in other words the graph feels very low quality. But when i output it as "pdf" i get smooth lines and graph is of higher quality. But pdf files are high in file size and i need to insert these graphs in word file. I find it relatively easy to append jpeg into the word file. So is it possible to improve image quality while being in jpeg format. I tried using res argument in jpeg() but it doesnot output the graph as it is displayed in the rstudio.
I will appreciate the help. Thanks!
code:
library(shape)
library(Hmisc)
### samples ######
xaxs = seq(1,30,length=30)
precip = sample(200:800, 30)
ero = sample(0:10, 30, replace = T)
#########
svpth = getwd()
nm = "try.jpeg"
jpeg(paste0(svpth,"/",nm), width=950 , height =760, quality = 200, pointsize =15)
par(mar= c(5,4,2,4), oma=c(1,1,1,1))
plot(xaxs,precip, type = "p", pch=15, col="green", ylim = c(200,1000),
xlab = "Year" , ylab = "", cex.main=1.5, cex.axis=1.5, cex.lab=1.5)
lines(xaxs, precip,lty =1, col="green")
# xtick<-seq(0,30, by=1)
# axis(side = 1, at=xtick, labels = FALSE )
minor.tick(nx=5, ny=2, tick.ratio=0.5, x.args = list(), y.args = list())
mtext("Depth (mm)", side = 2, line = 2.7, cex = 1.5)
par(new=T)
plot(xaxs, (ero * 10), ylim = c(0,max(pretty(range((ero * 10))))+20), type = "p", pch=20, cex=1.5, col="red", axes = F, xlab = "", ylab = "")
lines(xaxs, (ero * 10),lty =2, col="red")
axis(side = 4, at=pretty(range((ero * 10))), cex.axis = 1.5)
# mtext("Erosion (t/ha/yr)", side = 4, line = 2.2, cex = 1.5)
mtext(expression(paste("Erosion (t ", ha^-1, yr^-1, ")")), side = 4, line = 2.7, cex = 1.5)
legend("topleft", legend = c("Precipitation","Erosion"), lty = c(1,2), pch = c(15,20), col = c("green","red"), cex = 1.6, bty = "n")
####arrow
Arrows(7, 85, 11, 90,lwd= 1.1)
Arrows(26, 85, 21, 90, lwd= 1.1)
txt = "High erosion rates in \nwheat-planting years"
xt = 16
yt = 85
text(xt, yt, labels = txt, family="serif", cex = 1.23)
sw = strwidth(txt)+1.4
sh = strheight(txt) +6
frsz = 0.38
rect(xt - sw/2 - frsz, yt - sh/2 - frsz, xt + sw/2 + frsz, yt + sh/2 + frsz-1)
# legend(15,80, legend = c("High erosion rates in \nwheat-planting years\n"),
# xjust = 0.5, yjust = 0.5)
dev.off()
It didn't use base R, but this makes an svg, which is smaller than a jpeg and will create some beautiful images. MS Word has no problems with svg, either.
The svg-- 18 kb; the jpeg-- 592 kb for the same image.
Use if it works, if not, well, perhaps someone else could use it? This won't show in the plot pane in RStudio, it will show in the viewer pane.
After the code, I have an image of saving the plot in the viewer pane in RStudio.
library(plotly)
df = data.frame("Year" = xaxs, "Depth" = precip, "Erosion" = ero *10)
p = plot_ly(df) %>%
add_trace(x = ~Year, y = ~Depth,
type = 'scatter', mode = 'lines', # to have both the points and lines use 'lines+markers'
name = "Depth",
line = list(shape = "spline", # smooth the curves in the lines (not that effective with lines+markers)
color = "green")) %>%
add_trace(x = ~Year, y = ~Erosion,
mode = 'lines',
name = "Erosion",
yaxis = "y2", # second y axis
line = list(dash = 'dash', # dash the lines
shape = "spline", # smooth the curves in the lines
color = "red")) %>% # without "lines+markers" spline will smooth out the points of the line
add_annotations(inherit = F, # add the arrows at the top of the plot
x = list(12, 18), # this is plot coordinates
y = list(800, 800),
ax = list(-60, 60), # this is pixels
ay = list(10, 10),
showarrow = T,
text = "") %>%
add_annotations(inherit = F, # add the textbox at the top of the plot
x = 15, y = 800,
ax = 0, ay = 0,
showarrow = F,
bordercolor = 'black',
text = "High erosion rates in\nwheat-planting years") %>%
layout(yaxis2 = list(overlaying = "y", side = "right", # add labels
title = paste0("Erosion (t ",
"ha<sup>-1</sup>",
"yr<sup>-1</sup>",
")")),
yaxis = list(title = "Depth (mm)"),
legend = list(x = .1, y = 1000),
margin = list(r = 80)) # right margin space for label
To save it, add the functionality. The icons at the top of the plot in the image at the end won't show until you hover over them. I think you may find that if you use this, the height/width specifications you have aren't the best fit anymore.
(p <- p %>% config( # save the plot; add a save function to the plot
toImageButtonOptions = list(
format = "svg",
filename = "try",
width = 950,
height = 760)) # end config
) # end () for print simo object assignment
The plot. The width and height in this image are 950 x 550.
I was wondering if it is possible to seperate two plots from eachother (both should be on the same plot, using double Y axis). So the double plot should be split into two but without actually plotting them seperate - par(mfrow(1,2)).
I was trying to imitate it with layout plot, or with latticeExtra, ggplot but no success.
I have two different dataset one for the exchange rate one for the logaritmic returns.
par(mar=c(4,4,3,4))
plot(rates$EURHUF~rates$Date, type="l", ylab="Rate", main="EUR/HUF", xlab="Time")
par(new=TRUE)
plot(reteslog$EURHUF~rateslog$Date, type="l", xaxt="n", yaxt="n", ylab="", xlab="", col="red")
axis(side=4)
mtext("Log return", side=4, line=3)
legend("topleft", c("EUR/HUF Rates","EUR/HUF Logreturns"), col=c("black", "red"), lty=c(1,1))
So far I am here, I just don't know how to seperate them or scale them (maybe using margin, or layout?)
Thank you very much guys for helping
I have a solution to this that isn't too outlandish, and is entirely in base, which is nice. For it to work, you just need to be able to force all of your data onto the same scale, which usually isn't a hassle.
The idea is that once your data is on the same scale, you can plot it all normally, and then add in custom axes that show the respective scales of the different data.
set.seed(1986)
d01 <- sample(x = 1:20,
size = 200,
replace = TRUE)
d02 <- sample(x = 31:45,
size = 200,
replace = TRUE)
# pdf(file = "<some/path/to/image.pdf>",
# width = 4L,
# height = 4L) # plot to a pdf
jpeg(file = "<some/path/to/image.jpeg>") # plot to a jpeg
par(mar=c(3.5, 3.5, 2, 3.5)) # parameters to make things prettier
par(mgp=c(2.2, 1, 0)) # parameters to make things prettier
plot(x = 0,
y = 0,
type = "n",
xlim = c(1, 200),
ylim = c(1, 50),
xlab = "Label 01!",
ylab = "Label 02!",
axes = FALSE,
frame.plot = TRUE)
points(d01,
pch = 1,
col = "blue") # data 01
points(d02,
pch = 2,
col = "red") # data 02
mtext("Label 03!",
side = 4,
line = 2) # your extra y axis label
xticks <- seq(from = 0,
to = 200,
by = 50) # tick mark labels
xtickpositions <- seq(from = 0,
to = 200,
by = 50) # tick mark positions on the x axis
axis(side = 1,
at = xtickpositions,
labels = xticks,
col.axis="black",
las = 2,
lwd = 0,
lwd.ticks = 1,
tck = -0.025) # add your tick marks
y01ticks <- seq(from = 0,
to = 1,
by = 0.1) # tick mark labels
y01tickpositions <- seq(from = 0,
to = 50,
by = 5) # tick mark positions on the y01 axis
axis(side = 2,
at = y01tickpositions,
labels = y01ticks,
las = 2,
lwd = 0,
lwd.ticks = 1,
tck = -0.025) # add your tick marks
y02ticks <- seq(from = 0,
to = 50,
by = 5L) # tick mark labels
y02tickpositions <- seq(from = 0,
to = 50,
by = 5) # tick mark positions on the y02 axis
axis(side = 4,
at = y02tickpositions,
labels = y02ticks,
las = 2,
lwd = 0,
lwd.ticks = 1,
tck = -0.025) # add your tick marks
dev.off() # close plotting device
A few notes:
Sizing for this plot was originally set for a pdf, which unfortunately cannot be uploaded here, however that device call is included as commented out code above. You can always play with parameters to find out what works best for you.
It can be advantageous to plot all of your axis labels with mtext().
Including simple example data in your original post is often much more helpful than the exact data you're working with. As of me writing this, I don't really know what your data looks like because I don't have access to those objects.
The following is a plotting frame for 28 plots:
par(mfcol = c(7, 4), mar = rep(.1, 4), oma = rep(7, 4))
invisible(lapply(1:28, plot, t = "n", xaxt = "n", yaxt = "n"))
To add labels to y-axis (side = 2) of the above plotting frame I do the following:
mid.y = seq(grconvertY(0 + (1 / 14), "nic"), grconvertY(1 - (1 / 14), "nic"), l = 7)
gap.y = sort(c(mid.y[-length(mid.y)] + diff(mid.y)[1L] / 2, grconvertY(0:1, "nic")))
l = c('1/10', '1/3', '1', '3', '10', '30', '100', '> 100000')
mtext(l, side = 2, at = gap.y, line = 22, cex = .9, font = 2, las = 1) # notice `line = 22
Question
The label positions are perfect. But if I drag the graphical device to the right or left the labels don't move with the plot? How can I fix the labels to move with plot (please see the following 2 pictures)?
This is a complex plotting case. Thus, for complete control use text() instead of mtext(). This way you don't need to rely on line = argument which causes the problem you describe in your question above.
Solution based on your R code above:
text(grconvertX(0, "nic"), gap.y, l, xpd = NA, adj = 1, cex = 1.3, font = 2)
I have a function that depends on distance and behaves different according to the direction (east or west) to where you evaluate it. Now I have two plots side by side, but I need to have them as one, where the labels of the axis are shared and the x axis label is centered. Here is an example of how the code looks right now:
x = (0:300)
par(mfrow=c(2,2))
Idriss70 = function(x){
exp(5.6315-0.4104*7-(2.9832-0.2339*7)*log(x+10)+0.00047*x+0.12)
}
plot(Idriss70(x), log = "x", type="l",xlim = c(300,1), xlab="Distancia [km]",ylab="PGA [g]", main="Aroma y Humayani extendida, Mw 7,0", col="green", panel.first = grid(equilogs = TRUE))
Idriss70 = function(x){
ifelse (x >= 0 & x<=3, exp(5.6315-0.4104*7-(2.9832-0.2339*7)*log(0+10)+0.00047*0+0.12),
exp(5.6315-0.4104*7-(2.9832-0.2339*7)*log(x+10)+0.00047*x+0.12))
}
plot(Idriss70(x), log = "x", type="l", xlab="Distancia [km]",ylab="PGA [g]", main="Aroma y Humayani extendida, Mw 7,0", col="green", panel.first = grid(equilogs = TRUE))
As you can see, the log scale of the plots don't allow "negative" values to be evaluated so I haven't been able to use only one plot.
How can I get this plot as one without using Illustrator or another graphics software, as I have to create lots of this ones for differente areas?
I haven't used ggplot in the past but I am willing to learn if necessary.
You can basically make one plot and mess around with fig so that you restrict the first plot to the left half of the device and the second to the right half
x <- 0:300
Idriss70 = function(x){
exp(5.6315-0.4104*7-(2.9832-0.2339*7)*log(x+10)+0.00047*x+0.12)
}
Idriss71 = function(x){
ifelse(x >= 0 & x<=3,
exp(5.6315-0.4104*7-(2.9832-0.2339*7)*log(0+10)+0.00047*0+0.12),
exp(5.6315-0.4104*7-(2.9832-0.2339*7)*log(x+10)+0.00047*x+0.12))
}
par(fig = c(0, .5, 0, 1), mar = c(5, 4, 4, 0), xaxs = 'i', ann = FALSE)
plot(Idriss70(x), log = "x", type="l", xlim = c(300,1),
col="green", axes = FALSE, panel.first = grid(equilogs = TRUE))
xx <- axis(1)
axis(2)
par(fig = c(.5, 1, 0, 1), new = TRUE, mar = c(5, 0, 4, 2))
plot(Idriss71(x), log = "x", type="l", col="green",
panel.first = grid(equilogs = TRUE), axes = FALSE)
axis(1, at = xx, labels = c('', xx[-1]))
title(xlab = "Distancia [km]", main = 'Aroma y Humayani extendida, Mw 7,0',
ylab = 'PGA [g]', outer = TRUE, line = -1.5)
good luck with ggplot. you'd probably have to summon #baptiste
well you could still use mfrow I suppose
graphics.off()
par(mfrow = c(1, 2), mar = c(5, 4, 4, 0), xaxs = 'i', ann = FALSE)
plot(Idriss70(x), log = "x", type="l", xlim = c(300,1),
col="green", axes = FALSE, panel.first = grid(equilogs = TRUE))
xx <- axis(1)
axis(2)
par(mar = c(5, 0, 4, 2))
plot(Idriss71(x), log = "x", type="l", col="green",
panel.first = grid(equilogs = TRUE), axes = FALSE)
axis(1, at = xx, labels = c('', xx[-1]))
title(xlab = "Distancia [km]", main = 'Aroma y Humayani extendida, Mw 7,0',
ylab = 'PGA [g]', outer = TRUE, line = -1.5)