问题
I would like to put vertical lines and labels for the vertical lines for each graph in a loop. the position of the line is saved in a dataframe "grid".
Although the position of the line seems correct the label value and its position is off. My question is why.
library(ggplot2)
library(grid)
library(gridExtra)
plots <- list()
grid <- data.frame(x=seq(4), y=c(200, 400, 600, 800))
for (i in 1:4) {
V1 <- rnorm(1000)
V2 <- seq(1000)
df <- data.frame(V1, V2)
plots[[i]] <- ggplot(df, aes(x= V2, y=V1)) +
geom_point() +
geom_vline(xintercept = grid[i,2], color="red")+
geom_text(aes(x=grid[i,2], label=grid[i,2], y=3))
}
grid.arrange(grobs=plots, nrow=2)
回答1:
Ideally you should use annotate instead. The following code works as expected.
library(ggplot2)
library(grid)
library(gridExtra)
plots <- list()
grid <- data.frame(x=seq(4), y=c(200, 400, 600, 800))
for (i in 1:4) {
V1 <- rnorm(1000)
V2 <- seq(1000)
df <- data.frame(V1, V2)
plots[[i]] <- ggplot(df, aes(x= V2, y=V1)) +
geom_point() +
geom_vline(xintercept = grid[i,2], color="red")+
annotate("text", x=grid[i,2], label=grid[i,2], y=3)
}
grid.arrange(grobs=plots, nrow=2)

Created on 2020-06-26 by the reprex package (v0.3.0)
回答2:
I'd take a different approach, using facets.
I'd also probably calculate the sample outside the facet/loop (second option)
library(ggplot2)
grid_df<- data.frame(x=1:4, y=c(200, 400, 600, 800))
ggplot(grid_df) +
geom_vline(aes(xintercept = y), color="red") +
geom_text(aes(label = y, x = y, y = Inf), vjust = 1) +
stat_function(
inherit.aes = FALSE,
fun = rnorm,
n = 600,
alpha = 0.2,
geom = "point"
)+
facet_wrap(~x, nrow = 2)

## or, if you want always the same sample in each facet:
set.seed(42)
df_rnorm <- data.frame(V1 = rep(rnorm(1000), 4), V2 = rep(seq(1000), 4), x = rep(1:4, each = 1000))
ggplot(grid_df) +
geom_vline(aes(xintercept = y), color="red") +
geom_text(aes(label = y, x = y, y = Inf), vjust = 1) +
geom_point(data = df_rnorm, aes(V2, V1), alpha = 0.2)+
facet_wrap(~ x, nrow = 2)

Created on 2020-06-26 by the reprex package (v0.3.0)
回答3:
I had to experiment a little bit to adress the why part of your question. And probably someone else could enrich my explaination with a little bit more expert knowledge and facts (I am just answering based on my gut feeling :D)
As there seems to be no problem, if you print the plots inside the loop or if you print them outside the loop (within another loop that iterates 1:4), I think plot[[i]] only stores the syntax to produce the plots. If you execute plot[[i]] outside of the loop, it uses grid[i,2] to assign label and position of the geom_text part. Outside of the loop i is 4 and thats why all the plots use the same position/label (800).
But I don't really understand why geom_vline does not behave the same way or why aes.inherit or the use of lapply fixes the problem ... If anyone else could shed some light on this, I would appreciate it :)
library(ggplot2)
library(grid)
library(gridExtra)
plots <- list()
grid <- data.frame(x=seq(4), y=c(200, 400, 600, 800))
for (i in 1:4) {
V1 <- rnorm(1000)
V2 <- seq(1000)
df <- data.frame(V1, V2)
plots[[i]] <- ggplot(df, aes(x= V2, y=V1)) +
geom_point() +
geom_text(aes(x=grid[i,2], label=grid[i,2], y=3)) +
geom_vline(xintercept = grid[i,2], color="red")
print(plots[[i]]) # not part of the original syntax
}
# leads to wrong position of geom_text
plots
# leads to wrong position of geom_text
grid.arrange(grobs=plots, nrow=2)
# correct position of geom_text
for (i in 1:4){
print(plots[[i]])
}
# new grid values also affect plots
grid <- data.frame(x=seq(4), y=c(2000, 4000, 6000, 8000))
# leads to wrong position of geom_text
plots
来源:https://stackoverflow.com/questions/62594080/ggplot2-labeling-graphs-in-a-loop