1

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)

enter image description here

2
  • hi, for me the trick was to set. inherit.aes=FALSE in geom_text. I tried to figure out the WHY too, but I could not figure out a good answer to it. If you print the plot in each iteration, the plots are perfect. If you use your code in a lapply (instead of plots[[i]] just plots) it works too. So it seems like geom_text overrides all previous list elements in the for loop ... which seems odd. And even stranger that the rest of the plot is not affected ... if anybody has a good answer to the WHY, please share :) Commented Jun 27, 2020 at 13:02
  • You really need to consider using facets. Loops are not the best practice in R, most of the times specially when a vectorized solution is available. Commented Jun 30, 2020 at 16:14

3 Answers 3

2

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)

Sign up to request clarification or add additional context in comments.

Comments

1

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)

Comments

0

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
        
        

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.