Add title to ggplots stored in a list

Hi, I am using the prophet package from Facebook to investigate time series forecasting.

I have a list (p2) that contains two ggplot objects which I can plot by using the map function as so:

map(p2, print)

This plots the 2 objects in separate viewers but I wish to add titles to the plots to provide context.

I have tried the following code but both plots show the same name, unsurprisingly the name of the first object in the list.

map(p2, ~ print(.x) + ggtitle(names(p2)))

How can I add AAPL and AMZN to each of the plot titles using map syntax?

My full code looks as follows:

# LOAD LIBRARIES
pacman::p_load(tidyquant,tidyverse,prophet,purrr,tidymodel,modeltime)

# SPECIFY STOCKS TO PULL
tickers = c("AAPL","AMZN")

# GET STOCK PRICE INFO
getSymbols(tickers, 
           from = today() - years(7),
           to = today(),
           warnings = FALSE,
           auto.assign = TRUE)

# MAP DATAFRAMES TO A LIST
dfList <- mget(tickers) %>%
  map(~ fortify.zoo(.x) %>% 
        select(1,5) %>% 
  rename(ds = 1,
         y = 2))

# SPECIFY NFL IMPORTANT DATES
playoffs <- tibble(
  holiday = 'playoff',
  ds = as.Date(c('2008-01-13', '2009-01-03', '2010-01-16',
                 '2010-01-24', '2010-02-07', '2011-01-08',
                 '2013-01-12', '2014-01-12', '2014-01-19',
                 '2014-02-02', '2015-01-11', '2016-01-17',
                 '2016-01-24', '2016-02-07')),
  lower_window = 0,
  upper_window = 1
)
superbowls <- tibble(
  holiday = 'superbowl',
  ds = as.Date(c('2010-02-07','2011-02-06','2012-02-05','2013-02-03','2014-02-02','2015-02-01','2016-02-07','2017-02-05','2018-02-04','2019-02-03','2020-02-02')),
  lower_window = 0,
  upper_window = 1
)

holidays <- bind_rows(playoffs, superbowls) %>% 
  filter(ds >= min(dfList$AAPL$ds) & ds <= max(dfList$AAPL$ds))

# CALL THE PROPHET FUNCTION TO FIT THE MODEL
model_list <- map(dfList,
                  ~ {
                    m <- prophet(holidays = holidays, daily.seasonality = FALSE)
                    m <- add_country_holidays(m, country_name = 'US')
                    m <- fit.prophet(m, .x)
                    return(m)
                  })

# TAKES THE MODEL ABOVE AND THE SPECIFIED FORECAST PERIOD TO PRODUCE A SUITABLE 
# DATA FRAME
future_list <- map(model_list,
                   make_future_dataframe,
                   periods = 365)

# USE THE GENERIC PREDICT FUNCTION TO GET OUR FORECAST
forecast_list <- map2(model_list,
                      future_list,
                      predict)

pdf("prophet.pdf") 
p1 <- map2(model_list, forecast_list, prophet_plot_components)
dev.off()


p2 <- map2(model_list, forecast_list, ~ plot(.x, .y) + 
             add_changepoints_to_plot(.x))

What you need is:

map2(p2, tickers, ~ .x + ggtitle(.y))

or even simpler:

imap(p2, ~ .x + ggtitle(.y))

1 Like

@gueyenono thank you very much for the answer, I am very grateful for your help.

Can you please explain how the imap function above works, from the help file I see it's equivalent to map2 with seq_along when using names of the list.

From your answer above there is no print function to plot the ggplot objects stored in p2 which is confusing me. The only reference to plotting is the ggtitle, is this what triggers the plotting of each time series? In the imap example what is .y in this example?

The print() function in R

@jgarrigan I may be wrong, but I suspect you have experience in at least one other programming language.

In R, there are only a few cases (that I know of) in which the explicit call to the print() function is required. Here is a quick example:

name <- "John"
name # no need to use print()

[1] "John"

So, in my answer, when I add titles to your plots, I do not need to explicitly use the print() function.

The imap() function

The i in imap stands for "index". You're already familiar with the map() function. imap()simply lets you loop through the elements of a list and also gives you access to each element's index. In case the list is named, it gives you access to each element's name instead:

unnamed_list <- list(10, 15, 30)
purrr::imap(unnamed_list, ~ paste("Value:", .x, "Index:", .y))

[[1]]
[1] "Value: 10 Index: 1"

[[2]]
[1] "Value: 15 Index: 2"

[[3]]
[1] "Value: 30 Index: 3"

named_list <- list(a = 10, b = 15, c = 30)
purrr::imap(named_list, ~ paste("Value:", .x, "Index:", .y))

$a
[1] "Value: 10 Index: a"

$b
[1] "Value: 15 Index: b"

$c
[1] "Value: 30 Index: c"
2 Likes

@gueyenono thanks for the detailed explanation, this makes sense to me know.

I've struggled to understand lists up until now, thank you once again for your help.

Consider marking my answer as the solution of it helped you. Also don't hesitate to ask your list-related questions and tag me if you want.

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.