简体   繁体   中英

How can I loop through variables containing ggplot2 code to plot them on the same graph in R?

I am trying to plot multiple lines in one ggplot in R using for loops. Currently, I don't believe I can use the melt() command to transition my data to long format due to some additional functionality I plan to add to the graphic down the road (filters, user inputs, etc. in a shiny dashboard - this will be my first dashboard, so please let me know if I am incorrect). I currently have the following code (see below) set up to assign a geom_line() command to a dynamic variable (produces x1 and x2). Next, I produce a vector of strings that tie to the dynamic variables created. The variable m is assigned as my ggplot() command. How do I create a plot that is the equivalent of m + x1 + x2 + scale_color_manual("red", "green") using the vector of strings to call the x# variables? Please note, this is for a QC process and over 200 variables need to be plotted in various graphs, so the solution needs to be scalable and not require me to explicitly type out each x# variable.

# Create mock data - need to run the timeStamp() function on it's own first
timeStamp <- function(){
  start <- readline("Enter Start Date (YYYY-MM-DD): ")  
  end <- readline("Enter End Date (YYYY-MM-DD): ")
  
  start <- as.POSIXct(start)
  end <- as.POSIXct(end)
  end <- end + as.difftime(1, unit = "days")
  interval <- 60
  
  Date <- seq(from=start, by = interval*60, to=end)
  
  Date <- as.data.frame(Date)
  n <- nrow(Date)
  
  Date <- Date[-1, ]
  
  Date <- as.data.frame(Date)
  
  assign("Date", Date, envir = .GlobalEnv)
  
}

timeStamp()

# Run timestamp function for any leap year use format 2028-01-01 to 2028-12-31 as inputs

# Creates remaining mock data
mock1 <- rep(c(1), times = 87840)
mock2 <- rep(c(2), times = 87840)
mock3 <- runif(87840, min=-100, max=100)
mock4 <- runif(87840, min=-10, max=10)
mock5 <- runif(87840, min=-150, max=150)
newDate <- rbind(Date, Date, Date, Date, Date,
                 Date, Date, Date, Date, Date)
# Inputs to for loop
dataFinal <- as.data.frame(cbind(newDate, mock1, mock2, mock5, mock4, mock3))
name <- list(names(dataFinal))
price <- names(dataFinal[ ,c(4,6)])


m <- ggplot(dataFinal)
for (i in seq_along(price)) { 
  dynamVar <- paste0("x", i)
  dynamCol <- paste0("col", i)
  assign(dynamVar, geom_line(aes_string(x = "Date", y = price[i], colour = as.factor(assign(dynamCol, price[i])))))
}
xPlot <- sprintf("x%s",seq(1:length(price)))

# This line of code produces a mock graphic that I am wanting to recreate, but instead of specifying x1 and x2, I want to produce the graph dynamically
m+x1+x2+scale_colour_manual(values=c("red", "green"))

There's two ways to go about this. First, the additive way, which is most directly related to what you asked. Instead of a for loop, I would use purrr::reduce

purrr::reduce(
  price, .init = m, 
  ~ .x + geom_line(aes_string(x = "Date", y = .y, color = as.factor(.y))), 
)

Method 2 is to use the group aesthetic of geom_line . You just need to pivot the data first.

dataFinal %>% 
  dplyr::select(c(1,4,6)) %>% 
  dplyr::sample_n(1e3) %>% 
  tidyr::pivot_longer(-Date) %>% 
  ggplot(aes(x = Date, y = value)) + 
  geom_line(aes(group = name, colour = as.factor(name)))

I sampled the data because otherwise mock5 masks mock3 (even though it is plotted)

As a side note, as R is largely a functional programming language, it's typically considered ill-advised to have a function (such as timeStamp ) modify the global environment. Instead have it return the data such that a user can assign a symbol of his/her choice ( myData <- timeStamp() ). Additionally, it may also be confusing to call a variable in the global environment 'Date' as this collides with the name of the base class .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM