Flip x axis in r for forestplot - r

I've made a foresplot in r using the metafor package with the following code:
res <- metafor::rma(cohens_d, variance, data = my_data)
par(mar=c(3.4,0,0,0))
par(cex=2.5, font=4)
metafor::forest.rma(res, alim=c(-3.75, 3.75), xlab = "Cohen's D with 95% CI",
slab = my_data$Paper)
which gives me the image:
I'd like to flip the x axis, meaning have the negative on the right. Any ideas on how to do this?
Thank you!

Okay, this is a really ridiculous hack, but it works. Basically, you have to draw the plot twice, once to add the points (with reversed signs) and once to add the annotations (without the reversed signs).
library(metafor)
dat <- get(data(dat.bcg))
dat <- escalc(measure="RR", ai=tpos, bi=tneg, ci=cpos, di=cneg, data=dat.bcg)
res <- rma(yi, vi, data=dat)
### default plot
forest(res, xlim=c(-8,8))
### trick into reverse x-axis
forest(res, xaxt="n", transf=function(x) -1*x, annotate=FALSE, xlim=c(-8,8), xlab="Log Relative Risk")
axis(side=1, at=seq(-3, 3, 1), labels=seq(3,-3,-1))
par(new=TRUE)
forest(res, xaxt="n", xlim=c(-8,8), col="white", border="white", pch=NA, lty="blank", efac=NA, xlab="", slab=NA, mlab=NA)
par(new=FALSE)

I would simply just flip the estimated coefficients of the model (b component of the rma class) prior to plotting:
res <- metafor::rma(cohens_d, variance, data = my_data)
res$b <- -res$b

Related

How to plot regression transformed back on original scale with colored confidence interval bands?

I would like to plot the line and the 95% confidence interval from a linear model where the response has been logit transformed back on the original scale of the data. So the result should be a curved line including the confidence intervals on the original scale, where it would be a straight line on the logit transformed scale. See code:
# Data
dat <- data.frame(c(45,75,14,45,45,55,65,15,3,85),
c(.37, .45, .24, .16, .46, .89, .16, .24, .23, .49))
colnames(dat) <- c("age", "bil.")
# Logit transformation
dat$bb_logit <- log(dat$bil./(1-dat$bil.))
# Model
modelbb <- lm(bb_logit ~ age + I(age^2), data=dat)
summary(modelbb)
# Backtranform
dat$bb_back <- exp(predict.lm(modelbb))/ (1 + exp(predict.lm(modelbb)))
# Plot
plot(dat$age, dat$bb_back)
abline(modelbb)
What do I try here is to plot the curved regression line and add the confidence interval. Within ggplot2 there is the geom_smooth function where the the linear model can be specified, but I could not find a way of plotting the predictions from the predict.lm(my model).
I would also like to know how to add a coloured polygon which will represent the confidence interval as in the image below. I know I have to use function polygon and coordinates but I do not know how.
You may use predict on an age range say 1:100, specify interval= option for the CIs. Plotting with type="l" will smooth a nice curve. Confidence intervals then can be added using lines.
p <- predict(modelbb, data.frame(age=1:100), interval="confidence")
# Backtransform
p.tr <- exp(p) / (1 + exp(p))
plot(1:100, p.tr[,1], type="l", ylim=range(p.tr), xlab="age", ylab="bil.")
sapply(2:3, function(i) lines(1:100, p.tr[,i], lty=2))
legend("topleft", legend=c("fit", "95%-CI"), lty=1:2)
Yields
Edit
To get shaded confidence bands use polygon. Since you want two confidence levels you probably need to make one prediction for each. The line will get covered by the polygons, so it's better to make an empty plot first using type="n" and draw the lines at the end. (Note that I'll also show you some hints for custom axis labeling.) The trick for the polygons is to express the values back and forth using rev.
p.95 <- predict(modelbb, data.frame(age=1:100), interval="confidence", level=.95)
p.99 <- predict(modelbb, data.frame(age=1:100), interval="confidence", level=.99)
# Backtransform
p.95.tr <- exp(p.95) / (1 + exp(p.95))
p.99.tr <- exp(p.99) / (1 + exp(p.99))
plot(1:100, p.99.tr[,1], type="n", ylim=range(p.99.tr), xlab="Age", ylab="",
main="", yaxt="n")
mtext("Tree biomass production", 3, .5)
mtext("a", 2, 2, at=1.17, xpd=TRUE, las=2, cex=3)
axis(2, (1:5)*.2, labels=FALSE)
mtext((1:5)*2, 2, 1, at=(1:5)*.2, las=2)
mtext(bquote(Production ~(kg~m^-2~year^-1)), 2, 2)
# CIs
polygon(c(1:100, 100:1), c(p.99.tr[,2], rev(p.99.tr[,3])), col=rgb(.5, 1, .2),
border=NA)
polygon(c(1:100, 100:1), c(p.95.tr[,2], rev(p.95.tr[,3])), col=rgb(0, .8, .5),
border=NA)
# fit
lines(1:100, p.99.tr[,1], ylim=range(p.99.tr), lwd=2)
#legend
legend("topleft", legend=c("fit", "99%-CI", "95%-CI"), lty=c(1, NA, NA), lwd=2,
pch=c(NA, 15, 15), bty="n",
col=c("#000000", rgb(.5, 1, .2), rgb(0, .8, .5)))
Yields

Reducing the space between the `xlab` and with the x-axis in a forest plot (metafor package) in R

I'm trying to reduce the space between the xlab (titled: "Log Risk Ratio") and the x-axis (see picture below) in the forest plot generated by the metafor package in R with no success.
Is there any way to achive this?
library(metafor)
dat <- escalc(measure="RR", ai=tpos, bi=tneg, ci=cpos, di=cneg, data=dat.bcg)
forest(dat$yi, dat$vi, mgp = c(2, .3, 0)) # Tried setting `mgp` without success!
forest calls base R plot function, so you set the xlab to be "" first, and use mtext to manually add the text. Increasing padj will move your label away from the axis.
forest(dat$yi, dat$vi, mgp = c(2, .3, 0),xlab="")
mtext(side=1,"Log Risk Ratio",padj=2)

2 Y axis histogram (normal frequency vs relative frequency)

I would like your help, please.
I have this 2 plots, separately. One is normal frequency and the other one, with exactly the same data, is for relative frequency.
Can you tell me how can i join them in a single plot with 2 y axis ( frequency and relative frequency?)
x<- AAA$starch
h<-hist(x, breaks=40, col="lightblue", xlab="Starch ~ Corn",
main="Histogram with Normal Curve", xlim=c(58,70),ylim = c(0,2500),axes=TRUE)
xfit<-seq(min(x),max(x),length=40)
yfit<-dnorm(xfit,mean=mean(x),sd=sd(x))
yfit <- yfit*diff(h$mids[1:2])*length(x)
lines(xfit, yfit, col="blue", lwd=3)
library(HistogramTools)
x<- AAA$starch
c <- hist(x,breaks=10, ylab="Relative Frequency", main="Histogram with Normal Curve",ylim=c(0,2500), xlim=c(58,70), axes=TRUE)
PlotRelativeFrequency((c))
Thank you!!
EDIT:
This is just an example image of what I want...
I use doubleYScale from package latticeExtra.
Here is an example (I am not sure about relative frequency calculation) :
library(latticeExtra)
set.seed(42)
firstSet <- rnorm(500,4)
breaks = 0:10
#Cut data into sections
firstSet.cut = cut(firstSet, breaks, right=FALSE)
firstSet.freq = table(firstSet.cut)
#Calculate relative frequency
firstSet.relfreq = firstSet.freq / length(firstSet)
#Parse to a list to use xyplot later and assigning x values
firstSet.list <- list(x = 1:10, y = as.vector(firstSet.relfreq))
#Build histogram and relative frequency curve
hist1 <- histogram(firstSet, breaks = 10, freq = TRUE, col='skyblue', xlab="Starch ~ Corn", ylab="Frequency", main="Histogram with Normal Curve", ylim=c(0,40), xlim=c(0,10), plot=FALSE)
relFreqCurve <- xyplot(y ~ x, firstSet.list, type="l", ylab = "Relative frequency", ylim=c(0,1))
#Build double objects plot
doubleYScale(hist1, relFreqCurve, add.ylab2 = TRUE)
And here is the result with two y axis with different scales :

How to plot a nice Lorenz Curve for factors in R (ggplot ?)

I need a nice plot for my thesis on the different distributions of different factors. Only the standard approach seemed with the package(ineq) was flexible enough.
However, it doesn't let me to put dots (see comment below) at the classes. It is important to see them, ideally to name them individually. Is this possible?
Distr1 <- c( A=137, B=499, C=311, D=173, E=219, F=81)
Distr2 <- c( G=123, H=400, I=250, J=16)
Distr3 <- c( K=145, L=600, M=120)
library(ineq)
Distr1 <- Lc(Distr1, n = rep(1,length(Distr1)), plot =F)
Distr2 <- Lc(Distr2, n = rep(1,length(Distr2)), plot =F)
Distr3 <- Lc(Distr3, n = rep(1,length(Distr3)), plot =F)
plot(Distr1,
col="black",
#type="b", # !is not working
lty=1,
lwd=3,
main="Lorenz Curve for My Distributions"
)
lines(Distr2, lty=2, lwd=3)
lines(Distr3, lty=3, lwd=3)
legend("topleft",
c("Distr1", "Distr2", "Distr3"),
lty=c(1,2,3),
lwd=3)
This is how it looks now
In case you really want to use ggplot, here is a simple solution
# Compute the Lorenz curve Lc{ineq}
library(ineq)
Distr1 <- c( A=100, B=900, C=230, D=160, E=190, F=40, G=5,H=30,J=60, K=500)
Distr1 <- Lc(Distr1, n = rep(1,length(Distr1)), plot =F)
# create data.frame from LC
p <- Distr1[1]
L <- Distr1[2]
Distr1_df <- data.frame(p,L)
# plot
ggplot(data=Distr1_df) +
geom_point(aes(x=p, y=L)) +
geom_line(aes(x=p, y=L), color="#990000") +
scale_x_continuous(name="Cumulative share of X", limits=c(0,1)) +
scale_y_continuous(name="Cumulative share of Y", limits=c(0,1)) +
geom_abline()
To show the problem, only Distr1 is needed; it' good to strip down before posting.
library(ineq)
Distr1 <- c( A=137, B=499, C=311, D=173, E=219, F=81)
Distr1 <- Lc(Distr1, n = rep(1,length(Distr1)), plot =F)
plot(Distr1$p,Distr1$L,
col="black",
type="b", # it should be "b"
lty=1,
lwd=3,
main="Lorenz Curve for My Distributions"
)
As there is a package (gglorenz) handling Lorenz Curves automatically for ggplot, I add this:
library(ggplot2)
library(gglorenz)
Distr1 <- c( A=137, B=499, C=311, D=173, E=219, F=81)
x <- data.frame(Distr1)
ggplot(x, aes(Distr1)) +
stat_lorenz() +
geom_abline(color = "grey")

Plot a gridded surface plot in R

I'm a beginner to R and I am trying to plot a surface plot on a specific grid. Basically I have a data-set of points from across the UK containing the longitude, latitude and amount of rainfall for a particular day. Using the following code I can plot this data onto a UK map:
dat <- read.table("~jan1.csv", header=T, sep=",")
names(dat) <- c("gauge", "date", "station", "mm", "lat", "lon", "location", "county", "days")
library(fields)
quilt.plot(cbind(dat$lon,dat$lat),dat$mm)
world(add=TRUE)
So far so good. I can also perform a thin plate spline interpolation (TPS) using:
fit <- Tps(cbind(dat$lon, dat$lat), dat$mm, scale.type="unscaled")
and then I can do a surface plot at a grid scale of my choice e.g.:
surface (fit, nx=100, ny=100)
This effectively gives me a gridded data plot at the resolution of 100*100.
Following help from another user I can now extract this data in a grid by using:
xvals <- seq(-10, 4, len=20)
yvals <- seq(49, 63, len=20)
griddf <- expand.grid(xvals, yvals)
griddg <- predict(fit, x=as.matrix(griddf) )
What I would like to do now is plot the surface plot again using the same grid as the predict function (i.e. same as xvals and yvals) as above? Do you know how I can do this?
Thanks for any help
Once you have predicted your new values in griddg, you can technically re-interpolate with Tps and then proceed with the surface plot and map as before:
Example:
xvals <- seq(-10, 4, len=20)
yvals <- seq(49, 63, len=20)
griddf <- expand.grid(lon=xvals, lat=yvals)
griddg <- predict(fit, x=as.matrix(griddf) )
dat2 <- cbind(griddf, mm=griddg)
head(dat2)
fit <- Tps(cbind(dat2$lon, dat2$lat), dat2$mm, scale.type="unscaled")
surface (fit, nx=100, ny=100)
world(add=TRUE)
For more control over your maps, you could also plot your new grid directly - This is probably more correct in that the above method essentially fits your interpolation Tps twice. This method requires some external functions, but you will have more flexibility in your mapping.
#option 2
source("matrix.poly.r") #http://menugget.blogspot.de/2012/04/create-polygons-from-matrix.html
source("val2col.R") # http://menugget.blogspot.de/2011/09/converting-values-to-color-levels.html
source("image.scale.R") # http://menugget.blogspot.de/2011/08/adding-scale-to-image-plot.html
#new grid and predition
xvals <- seq(-10, 4, len=100)
yvals <- seq(49, 63, len=100)
griddf <- expand.grid(lon=xvals, lat=yvals)
griddg <- predict(fit, x=as.matrix(griddf) )
#make polygons for new grid, calculate color levels
mat <- matrix(griddg, nrow=length(xvals), ncol=length(yvals))
poly <- matrix.poly(xvals, yvals, z=mat, n=seq(mat))
pal <- colorRampPalette(c("blue", "cyan", "yellow", "red"))
COL <- val2col(mat, col=pal(100))
#required packages
library(maps)
library(mapproj)
#plot
png("tmp.png", width=5, height=4, res=400, units="in")
layout(matrix(1:2, nrow=1, ncol=2), widths=c(4,1), heights=4)
par(mar=c(1,1,1,1))
map("world", proj="stereographic", orient=c(mean(yvals),mean(xvals),0), par=NULL, t="n", xlim=range(xvals), ylim=range(yvals))
for(i in seq(poly)){
polygon(mapproject(poly[[i]]), col=COL[i], border=COL[i], lwd=0.3)
}
map("world", proj="stereographic", orient=c(mean(yvals),mean(xvals),0), par=NULL, add=T)
map.grid(col=rgb(0,0,0,0.5), labels=F)
box()
par(mar=c(5,0,5,4))
image.scale(mat, col=pal(100), horiz=FALSE, axes=FALSE, xlab="", ylab="")
axis(4)
mtext("mm", side=4, line=2.5)
box()
dev.off()

Resources