Prophet: Use dygraphs for plotting

Created on 25 Feb 2017  路  26Comments  路  Source: facebook/prophet

dygraphs makes some great interactive plots. You can zoom in, hover, etc. I coded it to be the generic plot method but replacing ggplot2 is a bit extreme. So maybe the generic plot should call either the ggplot2 or dygraphs functions depending on an argument flag, like plot(m, forecast, dygraphs=TRUE)?

In terms of compatibility it can be used from the console and in rmarkdown documents for rendering to HTML or pdf docs (pdf requires the latest versions of knitr and webshot).

#' Plot the prophet forecast.
#'
#' @param x Prophet object.
#' @param fcst Data frame returned by predict(m, df).
#' @param uncertainty Boolean indicating if the uncertainty interval for yhat
#'  should be plotted. Must be present in fcst as yhat_lower and yhat_upper.
#' @param actual.color Color of points for actual data
#' @param forecast.color Color of forecast line
#' @param forecast.label Text for legend
#' @param actual.label Text for legend
#' @param forecast.pattern Type of line for forecast. Must be one of c("dashed", "dotted", "dotdash", "solid").
#' @param actual.size Size of points for actual data
#' @param forecast.size Thickness of line for forecast data
#' @param legend.width Width of legend
#' @param group Group to associate this plot with. The x-axis zoom level of plots within a group is automatically synchronized.
#' @param ... additional arguments
#' @importFrom magrittr "%>%"
#' @return A dygraph plot.
#'
#' @examples
#' \dontrun{
#' history <- data.frame(ds = seq(as.Date('2015-01-01'), as.Date('2016-01-01'), by = 'd'),
#'                       y = sin(1:366/200) + rnorm(366)/10)
#' m <- prophet(history)
#' future <- make_future_dataframe(m, periods = 365)
#' forecast <- predict(m, future)
#' plot(m, forecast)
#' }
#'
#' @export
plot.prophet <- function(x, fcst, uncertainty=TRUE, 
                         actual.color='black', forecast.color='#0072B2',
                         forecast.label='Predicted', actual.label='Actual',
                         forecast.pattern=c("dashed", "dotted", "dotdash", "solid"),
                         actual.size=2, forecast.size=1,
                         legend.width=400,
                         ...) 
{
    forecast.pattern <- match.arg(forecast.pattern)

    # create data.frame for plotting
    df <- df_for_plotting(x, fcst)

    # build variables to include, or not, the uncertainty data
    if(uncertainty && exists("yhat_lower", where = df))
    {
        colsToKeep <- c('y', 'yhat', 'yhat_lower', 'yhat_upper')
        forecastCols <- c('yhat_lower', 'yhat', 'yhat_upper')
    } else
    {
        colsToKeep <- c('y', 'yhat')
        forecastCols <- c('yhat')
    }

    # convert to xts for easier date handling by dygraph
    # haven't dealt with cap yet
    dfTS <- xts(dplyr::select_(df, .dots=colsToKeep), order.by=df$ds)

    # base plot
    dyBase <- dygraphs::dygraph(dfTS, group=group)

    dyBase %>% 
        # plot forecast and ribbon
        dygraphs::dySeries(forecastCols, label=forecast.label, 
                           color=forecast.color, strokePattern=forecast.pattern, 
                           strokeWidth=forecast.size) %>% 
        # plot actual values
        dygraphs::dySeries('y', label=actual.label, drawPoints=TRUE, 
                           pointSize=actual.size, strokeWidth=0, 
                           color=actual.color) %>% 
        # allow zooming
        dygraphs::dyRangeSelector() %>% 
        # make unzoom button
        dygraphs::dyUnzoom() %>% 
        # control legend width
        dygraphs::dyLegend(width=legend.width)
}
ready

Most helpful comment

@lgaliano Familiar with plotly. Good for quickly converting ggplot2 to JavaScript. For a built-in function like this it might as well be written natively in a JavaScript format.

All 26 comments

I hadn't seen dygraphs! Looks neat. Let's get this into the 0.2 release.

It's a really cool package. All of these htmlwidgets packages do some great stuff and really extend our viz capabilities.

I also find it very useful to add shaded regions for the holidays.
This can be accomplished with this code:

for (i in 1:nrow(holidays)) {
     dyBase <- dyBase %>% dyShading(from = holidays$ds[i] + holidays$lower_window[i], 
                                        to = holidays$ds[i] + holidays$upper_window[i]) 
     dyBase <- dyBase %>% presAnnotation(holidays$ds[i], text = holidays$holiday[i])
   }

@seanjtaylor Adding dygraphs would be great, looking forward to it in 0.2. Thanks!

@wjhrdy We can also use dyEvent for marking change points.

@jaredlander , @seanjtaylor Not sure if you noticed, but plot(m, forecast) works directly with plotly, so you could also do ggplotly(plot(m, forecast)) if you were looking for interactivity (but prophet_plot_components(m, forecast) won't work without a few changes to generate the components with facet_grid())

@lgaliano Familiar with plotly. Good for quickly converting ggplot2 to JavaScript. For a built-in function like this it might as well be written natively in a JavaScript format.

Plotly is also a great alternative for interactive graphs, and is both available in R and Python...

To produce interactive forecasts, I have been working on Prophetly to integrate Prophet with Plotly.

It's currently in development phase, but I would be happy to have some feedback and discussion. :octocat:

df_for_plotting 锛燂紵

@GanJianhao that's an internal prophet function.

The v0.2 release is coming up soon, and this will need a PR to make it in. Anyone interested?

I think we'd want to pull the ggplot / dygraphs / plotly / ... code out of prophet.R into their own files so as to not clutter prophet.R with a dozen different plotting functions (almost there as is).

I'll make a pull request. I think this is a really useful way to explore regressors and features in your data.

Great! Be sure to make it on the v0.2 branch.

Sorry I didn't make it into v0.2 here is the pull request: #320

Thanks to @wjhrdy for the PR! This is now in the v0.3 branch and can be used like

dyplot.prophet(m, forecast)

With time we can add component plots in dygraphs also, so I'll leave this issue open for that.

The dygraphs plot of the forecast is now available in v0.3, so I'll go ahead and close this and we can open a new issue if we want to expand dygraph plotting to components plots in the future.

Is dyplot.prophet(m,forecast) supported in R only? I tried this in python and it doesn't work for me.

It is in R only, I didn't realize there was a python interface to dygraphs. Re-opening, if anyone would like to translate what was done in R (https://github.com/facebook/prophet/blob/master/R/R/plot.R#L391) into Python that would be extremely helpful.

For Python, I would expect Plotly to be the best choice for interactive plots. I did a plot of the forecast here: https://nbviewer.jupyter.org/gist/Olof-Hojvall/d5cbbfdab8f69ce26e11a46750104158 I tried to follow the design of the existing forecast plots.

Would this be an interesting solution @bletham ? If so I could make a PR for it.

@Olof-Hojvall that sounds great, I've been using plotly for some other stuff and it's been working very nicely there. I'd definitely merge that.

Documented in 4e5e223e4f9079a1f2de395914e68d05ced0a2c7

Hi - apologies if this question doesn't fit in here - I am just wondering if there is a way to share the interactive dygraph (after saving it as an local html file) to someone else (with no R or Python on their machines) in the organisation?

Thanks,
Seeker

Hi - apologies if this question doesn't fit in here - I am just wondering if there is a way to share the interactive dygraph (after saving it as an local html file) to someone else (with no R or Python on their machines) in the organisation?

Thanks,
Seeker

@seekerknow It should be a self-contained HTML file so you could share the file with anyone who has a modern browser.

Hi I'm following the quick start guide for R:

library('prophet')

# First we read in the data and create the outcome variable. As in the Python API, this is a dataframe with columns ds and y, containing the date and numeric value respectively. The ds column should be YYYY-MM-DD for a date, or YYYY-MM-DD HH:MM:SS for a timestamp. As above, we use here the log number of views to Peyton Manning鈥檚 Wikipedia page, available here.
df <- read.csv('raw/example_wp_log_peyton_manning.csv')


# We call the prophet function to fit the model. The first argument is the historical dataframe. Additional arguments control how Prophet fits the data and are described in later pages of this documentation.
m <- prophet(df)

# Predictions are made on a dataframe with a column ds containing the dates for which predictions are to be made. The make_future_dataframe function takes the model object and a number of periods to forecast and produces a suitable dataframe. By default it will also include the historical dates so we can evaluate in-sample fit.
# R
future <- make_future_dataframe(m, periods = 365)
tail(future)


# As with most modeling procedures in R, we use the generic predict function to get our forecast. The forecast object is a dataframe with a column yhat containing the forecast. It has additional columns for uncertainty intervals and seasonal components.
# R
forecast <- predict(m, future)
tail(forecast[c('ds', 'yhat', 'yhat_lower', 'yhat_upper')])

# You can use the generic plot function to plot the forecast, by passing in the model and the forecast dataframe.
# R
plot(m, forecast)

# You can use the prophet_plot_components function to see the forecast broken down into trend, weekly seasonality, and yearly seasonality.
# R
prophet_plot_components(m, forecast)

# An interactive plot of the forecast using Dygraphs can be made with the command dyplot.prophet(m, forecast).
library(dygraphs)
dyplot.prophet(m, forecast).

But end up with the following error message:

Error: unexpected symbol in "dyplot.prophet(m, forecast)."

Anyone else get the same?

@mkrasmus I think the issue is that it looks like you included the period at the end of the sentence as part of the command. If you just do

dyplot.prophet(m, forecast)

(no period at the end) it should work.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

annabednarska picture annabednarska  路  3Comments

xiaoyaoyang picture xiaoyaoyang  路  3Comments

davidjayjackson picture davidjayjackson  路  3Comments

datafool picture datafool  路  3Comments

ChaymaeHarfoush picture ChaymaeHarfoush  路  3Comments