aotearoa
aotearoa

Reputation: 315

Using loop for gpplot2 cause issue on displaying the legends

I have an R code that creates a linear regression. I am having some problems with the legends in a graph. I would like to use the dates specified in the trendDateRange as the legend with different colors. Since these dates are in YYYY-MM-DD format. I only need the YYYY-MM. So for example, the trendDateRage1 = c("2015-01-01", "2015-12-31") and I want to display "2015-01 - 2015-12" as a legend with a any colour. When I run this in a for loop, it's only displaying 1 legend which uses the last trendDateRange i.e trendDateRange3 which displays "2013-01 - 2013-12". It does not display the legend for the other 2 dates. I do not have any problem with graphs although they're using the same colour. I would like to see different colours for each legend even though they have different line types.

If I run the code below showing individual graphs, it's working with the proper legend. I get the legend for each graph.

Month_Names <- c("2010-11","2010-12",
     "2011-01","2011-02","2011-03","2011-04","2011-05","2011-06","2011-07","2011-08","2011-09","2011-10","2011-11","2011-12",
     "2012-01","2012-02","2012-03","2012-04","2012-05","2012-06","2012-07","2012-08","2012-09","2012-10","2012-11","2012-12",
     "2013-01","2013-02","2013-03","2013-04","2013-05","2013-06","2013-07","2013-08","2013-09","2013-10","2013-11","2013-12",
     "2014-01","2014-02","2014-03","2014-04","2014-05","2014-06","2014-07","2014-08","2014-09","2014-10","2014-11","2014-12",
     "2015-01","2015-02","2015-03","2015-04","2015-05","2015-06","2015-07","2015-08","2015-09","2015-10","2015-11","2015-12",
     "2016-01","2016-02","2016-03","2016-04","2016-05","2016-06","2016-07","2016-08","2016-09","2016-10","2016-11","2016-12",
     "2017-01")
Actual_volume <- c(54447,57156,
   52033,49547,58718,53109,56488,60095,54683,60863,56692,55283,55504,56633,
   53267,52587,54680,55569,60013,56985,59709,61281,54188,59832,56489,55819,
   59295,52692,56663,59698,61232,57694,63111,60473,58984,64050,54957,63238,
   59460,54430,58901,61088,60496,62984,66895,62720,65591,67815,58289,72002,
   61054,60329,69283,68002,63196,72267,71058,69539,71379,70925,68704,76956,
   65863,70494,77348,70214,74770,77480,69721,83034,76761,77927,79768,81836,
   75381)

df_data <- data.frame(Month_Names, Actual_volume) 

trendDateRange1 <- c("2010-11-01", "2017-01-31")
trendDateRange2 <- c("2012-01-01", "2012-12-31")
trendDateRange3 <- c("2013-01-01", "2013-12-31")
numoftrends <- 3

list_of_df <- list()

list_of_df<- lapply(1:numoftrends, function(j) {
           trend.period <- get(paste0("trendDateRange", j))
           trend1 <- substr(trend.period[1], 1, 7)
           trend2 <- substr(trend.period[2], 1, 7)

          TRx <- subset(df_data, as.character(Month_Names) >= trend1 & 
                      as.character(Month_Names) <= trend2)

})

i = 1
trend.period <- get(paste0("trendDateRange", i))
trend1 <- substr(trend.period[1], 1, 7)
trend2 <- substr(trend.period[2], 1, 7)
Trend.dates <- paste0(trend1, '-' ,trend2)
plot = ggplot() + 
    geom_line(data = list_of_df[[i]], 
              aes(x = Month_Names, y = Actual_volume, group = 1 , colour = Trend.dates), 
              lty = i + 1)
print(ggplotly(plot)) 

i = 2
trend.period <- get(paste0("trendDateRange", i))
trend1 <- substr(trend.period[1], 1, 7)
trend2 <- substr(trend.period[2], 1, 7)
Trend.dates <- paste0(trend1, '-' ,trend2)
plot = ggplot() + 
    geom_line(data = list_of_df[[i]], 
              aes(x=Month_Names, y = Actual_volume, group = 1 , colour = Trend.dates), 
              lty = i + 1)
print(ggplotly(plot)) 

i = 3
trend.period <- get(paste0("trendDateRange", i))
trend1 <- substr(trend.period[1], 1, 7)
trend2 <- substr(trend.period[2], 1, 7)
Trend.dates <- paste0(trend1, '-' ,trend2)
plot = ggplot() + 
    geom_line(data = list_of_df[[i]], 
              aes(x = Month_Names, y = Actual_volume, group = 1 , colour = Trend.dates), 
              lty = i+1)
print(ggplotly(plot)) 

But when I put this in the loop to make it one graph with each legend it does not work

plot = ggplot()
for (i in seq_along(list_of_df)) {
    trend.period = get(paste0("trendDateRange", i))
    trend1 = substr(trend.period[1], 1, 7)
    trend2 = substr(trend.period[2], 1, 7)
    Trend.dates = paste0(trend1, '-' ,trend2)
    plot = plot + geom_line(aes(x = Month_Names, y = Actual_volume, group = 1 , colour = Trend.dates), 
                            data = list_of_df[[i]], lty = i + 1)
}
print(ggplotly(plot))

Upvotes: 0

Views: 66

Answers (3)

Marco Sandri
Marco Sandri

Reputation: 24262

Here is a solution using ggplotly.

nrows <- unlist(lapply(list_of_df,nrow))
df <- data.frame(do.call(rbind,list_of_df), Grp = factor(rep(1:3, nrows)))

plot <- ggplot(aes(x=Month_Names, y=Actual_volume, group = Grp, 
        colour=Grp), data=df) + geom_line()
print(ggplotly(plot))

enter image description here

Upvotes: 1

alistaire
alistaire

Reputation: 43334

If you combine your list into a data.frame with an ID representing which element the observation came from and parse the dates, getting a decent plot is pretty simple:

library(dplyr)
library(ggplot2)

list_of_df %>% 
    bind_rows(.id = 'id') %>% 
    mutate(date = as.Date(paste0(Month_Names, '-01'))) %>% 
    ggplot(aes(date, Actual_volume, color = id)) + 
    geom_line()

split line plot

or without dplyr,

df <- do.call(rbind, 
              Map(function(df, i){df$id <- i; df}, 
                  df = list_of_df, 
                  i = as.character(seq_along(list_of_df))))

df$date <- as.Date(paste0(df$Month_Names, '-01'))

ggplot(df, aes(date, Actual_volume, color = id)) + geom_line()

which returns the same thing.

If you'd like more descriptive group labels, set the names of the list elements or define id as a string pasted together from the formatted minimums and maximums of the parsed dates.

Upvotes: 3

David Robinson
David Robinson

Reputation: 78610

You'll have a much easier time working with ggplot2 if you combine the three datasets into one with an aesthetic that separates them, rather than adding them together in a for loop.

There are a number of ways you could do this, but here's an example using the dplyr and tidyr packages. It would replace everything after your df_data <- line.

library(ggplot2)
library(dplyr)
library(tidyr)

trends <- data_frame(Start = c("2010-11", "2012-01", "2013-01"),
                     End = c("2017-01", "2012-12", "2013-12"))

combined_data <- df_data %>%
  crossing(trends) %>%
  mutate(Month_Names = as.character(Month_Names),
         TrendName = paste(Start, End, sep = "-")) %>%
  filter(Month_Names >= Start,
         Month_Names <= End)

# rotated x-axes to make plot slightly more readable
ggplot(combined_data, aes(Month_Names, y = Actual_volume,
                          group = TrendName,
                          color = TrendName)) +
  geom_line() +
  theme(axis.text.x = element_text(angle = 90, hjust = 1))

Upvotes: 3

Related Questions