user213544
user213544

Reputation: 2126

Generate plots from for loop with non-standard evaluation

I am trying to generate plots from a for-loop using ggplot in R.

Let's create a dataset:

# Libraries
library(tidyverse)

# Set seed
set.seed(123)

# Create data frame
df <- data.frame(
  time = c( rep(1,20), rep(2, 20), rep(3, 20) ), 
  value_a =c(rnorm(n = 60, mean = 50, sd = 10)),
  value_b =c(rnorm(n = 60, mean = 50, sd = 10)),
  value_c =c(rnorm(n = 60, mean = 50, sd = 10))
)

I can generate a plot using ggplot.

ggplot(data = df) +
  geom_jitter(aes(x = time, y = value_a), position = position_jitter(width = 0.1)) + 
  scale_y_continuous(limits = c(0, 100))

enter image description here

Next, I would like to generate these plots for every column of the data frame (with time on the x-axis and value_n on the y-axis). I thought a for loop would do the trick:

for(i in colnames(df)[-1]){
  print(
    ggplot(df_a, aes(x= time, y = i)) +
      geom_jitter(position=position_jitter(width=0.1)) +
      scale_y_continuous(limits = c(0,100))
  )
}

It provides the following error:

Error: Discrete value supplied to continuous scale

The error arises because the i from the for loop is seen as a character vector, and I can (logically) not provide a continuous scale to a discrete value.

Reproduction of the error outside the for-loop:

ggplot(df_a, aes(x= time, y = "value_a")) + # value_a is provided as character vector
  geom_jitter(position=position_jitter(width=0.1)) +
  scale_y_continuous(limits = c(0,100))

Question

Is there a way to prevent 'value_a' to be interpreted as a character vector, so that I will be able to control the scale in the loop? Or is there another way to conveniently generate plots from different columns in dataframe?

Upvotes: 1

Views: 61

Answers (1)

tjebo
tjebo

Reputation: 23757

I agree with PoGibas's comment - reshaping to long format and using facet is likely the better way to go. However, If you need it for creating different plots/images etc, use eval(sym(i)) instead, like so:

library(tidyverse)

# Set seed
set.seed(123)

# Create data frame
df <- data.frame(
  time = c( rep(1,20), rep(2, 20), rep(3, 20) ), 
  value_a =c(rnorm(n = 60, mean = 50, sd = 10)),
  value_b =c(rnorm(n = 60, mean = 50, sd = 10)),
  value_c =c(rnorm(n = 60, mean = 50, sd = 10))
)

for(i in colnames(df)[-1]){
  print(
    ggplot(df, mapping = aes(x= time, y = eval(sym(i)))) +
      geom_jitter(position=position_jitter(width=0.1)) +
      scale_y_continuous(limits = c(0,100)) +
      labs(y = i) #added automatic y-label 

  )
}

Created on 2019-11-29 by the reprex package (v0.3.0)

Upvotes: 1

Related Questions