diff --git a/R/R/prophet.R b/R/R/prophet.R index 658afda..5a2cbe3 100644 --- a/R/R/prophet.R +++ b/R/R/prophet.R @@ -900,6 +900,8 @@ df_for_plotting <- function(m, fcst) { #' @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 plot_cap Boolean indicating if the capacity should be shown in the +#' figure, if available. #' @param xlabel Optional label for x-axis #' @param ylabel Optional label for y-axis #' @param ... additional arguments @@ -917,12 +919,12 @@ df_for_plotting <- function(m, fcst) { #' } #' #' @export -plot.prophet <- function(x, fcst, uncertainty = TRUE, xlabel = 'ds', - ylabel = 'y', ...) { +plot.prophet <- function(x, fcst, uncertainty = TRUE, plot_cap = TRUE, + xlabel = 'ds', ylabel = 'y', ...) { df <- df_for_plotting(x, fcst) gg <- ggplot2::ggplot(df, ggplot2::aes(x = ds, y = y)) + ggplot2::labs(x = xlabel, y = ylabel) - if (exists('cap', where = df)) { + if (exists('cap', where = df) && plot_cap) { gg <- gg + ggplot2::geom_line( ggplot2::aes(y = cap), linetype = 'dashed', na.rm = TRUE) } @@ -949,15 +951,18 @@ plot.prophet <- function(x, fcst, uncertainty = TRUE, xlabel = 'ds', #' @param fcst Data frame returned by predict(m, df). #' @param uncertainty Boolean indicating if the uncertainty interval should be #' plotted for the trend, from fcst columns trend_lower and trend_upper. +#' @param plot_cap Boolean indicating if the capacity should be shown in the +#' figure, if available. #' #' @return Invisibly return a list containing the plotted ggplot objects #' #' @export #' @importFrom dplyr "%>%" -prophet_plot_components <- function(m, fcst, uncertainty = TRUE) { +prophet_plot_components <- function(m, fcst, uncertainty = TRUE, + plot_cap = TRUE) { df <- df_for_plotting(m, fcst) # Plot the trend - panels <- list(plot_trend(df, uncertainty)) + panels <- list(plot_trend(df, uncertainty, plot_cap)) # Plot holiday components, if present. if (!is.null(m$holidays)) { panels[[length(panels) + 1]] <- plot_holidays(m, df, uncertainty) @@ -985,13 +990,15 @@ prophet_plot_components <- function(m, fcst, uncertainty = TRUE) { #' #' @param df Forecast dataframe for plotting. #' @param uncertainty Boolean to plot uncertainty intervals. +#' @param plot_cap Boolean indicating if the capacity should be shown in the +#' figure, if available. #' #' @return A ggplot2 plot. -plot_trend <- function(df, uncertainty = TRUE) { +plot_trend <- function(df, uncertainty = TRUE, plot_cap = TRUE) { df.t <- df[!is.na(df$trend),] gg.trend <- ggplot2::ggplot(df.t, ggplot2::aes(x = ds, y = trend)) + ggplot2::geom_line(color = "#0072B2", na.rm = TRUE) - if (exists('cap', where = df.t)) { + if (exists('cap', where = df.t) && plot_cap) { gg.trend <- gg.trend + ggplot2::geom_line(ggplot2::aes(y = cap), linetype = 'dashed', na.rm = TRUE) @@ -1046,8 +1053,8 @@ plot_holidays <- function(m, df, uncertainty = TRUE) { #' @return A ggplot2 plot. plot_weekly <- function(m, uncertainty = TRUE) { # Compute weekly seasonality for a Sun-Sat sequence of dates. - df.w <- data.frame(ds=seq.Date(zoo::as.Date('2017-01-01'), by='d', - length.out=7)) + df.w <- data.frame( + ds=seq.Date(zoo::as.Date('2017-01-01'), by='d', length.out=7), cap=1.) df.w <- setup_dataframe(m, df.w)$df seas <- predict_seasonal_components(m, df.w) seas$dow <- factor(weekdays(df.w$ds), levels=weekdays(df.w$ds)) @@ -1075,8 +1082,8 @@ plot_weekly <- function(m, uncertainty = TRUE) { #' @return A ggplot2 plot. plot_yearly <- function(m, uncertainty = TRUE) { # Compute yearly seasonality for a Jan 1 - Dec 31 sequence of dates. - df.y <- data.frame(ds=seq.Date(zoo::as.Date('2017-01-01'), by='d', - length.out=365)) + df.y <- data.frame( + ds=seq.Date(zoo::as.Date('2017-01-01'), by='d', length.out=365), cap=1.) df.y <- setup_dataframe(m, df.y)$df seas <- predict_seasonal_components(m, df.y) seas$ds <- df.y$ds diff --git a/R/man/plot.prophet.Rd b/R/man/plot.prophet.Rd index 5862f34..324a32f 100644 --- a/R/man/plot.prophet.Rd +++ b/R/man/plot.prophet.Rd @@ -4,8 +4,8 @@ \alias{plot.prophet} \title{Plot the prophet forecast.} \usage{ -\method{plot}{prophet}(x, fcst, uncertainty = TRUE, xlabel = "ds", - ylabel = "y", ...) +\method{plot}{prophet}(x, fcst, uncertainty = TRUE, plot_cap = TRUE, + xlabel = "ds", ylabel = "y", ...) } \arguments{ \item{x}{Prophet object.} @@ -15,6 +15,9 @@ \item{uncertainty}{Boolean indicating if the uncertainty interval for yhat should be plotted. Must be present in fcst as yhat_lower and yhat_upper.} +\item{plot_cap}{Boolean indicating if the capacity should be shown in the +figure, if available.} + \item{xlabel}{Optional label for x-axis} \item{ylabel}{Optional label for y-axis} diff --git a/R/man/plot_trend.Rd b/R/man/plot_trend.Rd index 19ecc78..8e74a11 100644 --- a/R/man/plot_trend.Rd +++ b/R/man/plot_trend.Rd @@ -4,12 +4,15 @@ \alias{plot_trend} \title{Plot the prophet trend.} \usage{ -plot_trend(df, uncertainty = TRUE) +plot_trend(df, uncertainty = TRUE, plot_cap = TRUE) } \arguments{ \item{df}{Forecast dataframe for plotting.} \item{uncertainty}{Boolean to plot uncertainty intervals.} + +\item{plot_cap}{Boolean indicating if the capacity should be shown in the +figure, if available.} } \value{ A ggplot2 plot. diff --git a/R/man/prophet_plot_components.Rd b/R/man/prophet_plot_components.Rd index 493c092..7d28a9a 100644 --- a/R/man/prophet_plot_components.Rd +++ b/R/man/prophet_plot_components.Rd @@ -6,7 +6,7 @@ Prints a ggplot2 with panels for trend, weekly and yearly seasonalities if present, and holidays if present.} \usage{ -prophet_plot_components(m, fcst, uncertainty = TRUE) +prophet_plot_components(m, fcst, uncertainty = TRUE, plot_cap = TRUE) } \arguments{ \item{m}{Prophet object.} @@ -15,6 +15,9 @@ prophet_plot_components(m, fcst, uncertainty = TRUE) \item{uncertainty}{Boolean indicating if the uncertainty interval should be plotted for the trend, from fcst columns trend_lower and trend_upper.} + +\item{plot_cap}{Boolean indicating if the capacity should be shown in the +figure, if available.} } \value{ Invisibly return a list containing the plotted ggplot objects diff --git a/python/fbprophet/forecaster.py b/python/fbprophet/forecaster.py index bb58a82..fdb9a14 100644 --- a/python/fbprophet/forecaster.py +++ b/python/fbprophet/forecaster.py @@ -857,13 +857,16 @@ class Prophet(object): return pd.DataFrame({'ds': dates}) - def plot(self, fcst, uncertainty=True, xlabel='ds', ylabel='y'): + def plot(self, fcst, uncertainty=True, plot_cap=True, xlabel='ds', + ylabel='y'): """Plot the Prophet forecast. Parameters ---------- fcst: pd.DataFrame output of self.predict. uncertainty: Optional boolean to plot uncertainty intervals. + plot_cap: Optional boolean indicating if the capacity should be shown + in the figure, if available. xlabel: Optional label name on X-axis ylabel: Optional label name on Y-axis @@ -875,7 +878,7 @@ class Prophet(object): ax = fig.add_subplot(111) ax.plot(self.history['ds'].values, self.history['y'], 'k.') ax.plot(fcst['ds'].values, fcst['yhat'], ls='-', c='#0072B2') - if 'cap' in fcst: + if 'cap' in fcst and plot_cap: ax.plot(fcst['ds'].values, fcst['cap'], ls='--', c='k') if uncertainty: ax.fill_between(fcst['ds'].values, fcst['yhat_lower'], @@ -887,7 +890,7 @@ class Prophet(object): fig.tight_layout() return fig - def plot_components(self, fcst, uncertainty=True): + def plot_components(self, fcst, uncertainty=True, plot_cap=True): """Plot the Prophet forecast components. Will plot whichever are available of: trend, holidays, weekly @@ -897,31 +900,41 @@ class Prophet(object): ---------- fcst: pd.DataFrame output of self.predict. uncertainty: Optional boolean to plot uncertainty intervals. + plot_cap: Optional boolean indicating if the capacity should be shown + in the figure, if available. Returns ------- a matplotlib figure. """ # Identify components to be plotted - components = [('plot_trend', True), - ('plot_holidays', self.holidays is not None), - ('plot_weekly', 'weekly' in fcst), - ('plot_yearly', 'yearly' in fcst)] - components = [(plot, cond) for plot, cond in components if cond] + components = [('trend', True), + ('holidays', self.holidays is not None), + ('weekly', 'weekly' in fcst), + ('yearly', 'yearly' in fcst)] + components = [plot for plot, cond in components if cond] npanel = len(components) fig, axes = plt.subplots(npanel, 1, facecolor='w', figsize=(9, 3 * npanel)) artists = [] - for ax, plot in zip(axes, - [getattr(self, plot) for plot, _ in components]): - artists += plot(fcst, ax=ax, uncertainty=uncertainty) + for ax, plot in zip(axes, components): + if plot == 'trend': + artists += self.plot_trend( + fcst, ax=ax, uncertainty=uncertainty, plot_cap=plot_cap) + elif plot == 'holidays': + artists += self.plot_holidays(fcst, ax=ax, + uncertainty=uncertainty) + elif plot == 'weekly': + artists += self.plot_weekly(ax=ax, uncertainty=uncertainty) + elif plot == 'yearly': + artists += self.plot_yearly(ax=ax, uncertainty=uncertainty) fig.tight_layout() return artists - def plot_trend(self, fcst, ax=None, uncertainty=True): + def plot_trend(self, fcst, ax=None, uncertainty=True, plot_cap=True): """Plot the trend component of the forecast. Parameters @@ -929,6 +942,8 @@ class Prophet(object): fcst: pd.DataFrame output of self.predict. ax: Optional matplotlib Axes to plot on. uncertainty: Optional boolean to plot uncertainty intervals. + plot_cap: Optional boolean indicating if the capacity should be shown + in the figure, if available. Returns ------- @@ -941,7 +956,7 @@ class Prophet(object): ax = fig.add_subplot(111) artists += ax.plot(fcst['ds'].values, fcst['trend'], ls='-', c='#0072B2') - if 'cap' in fcst: + if 'cap' in fcst and plot_cap: artists += ax.plot(fcst['ds'].values, fcst['cap'], ls='--', c='k') if uncertainty: artists += [ax.fill_between( @@ -988,12 +1003,11 @@ class Prophet(object): ax.set_ylabel('holidays') return artists - def plot_weekly(self, fcst, ax=None, uncertainty=True): + def plot_weekly(self, ax=None, uncertainty=True): """Plot the weekly component of the forecast. Parameters ---------- - fcst: pd.DataFrame output of self.predict. ax: Optional matplotlib Axes to plot on. One will be created if this is not provided. uncertainty: Optional boolean to plot uncertainty intervals. @@ -1008,7 +1022,7 @@ class Prophet(object): ax = fig.add_subplot(111) # Compute weekly seasonality for a Sun-Sat sequence of dates. days = pd.date_range(start='2017-01-01', periods=7) - df_w = pd.DataFrame({'ds': days}) + df_w = pd.DataFrame({'ds': days, 'cap': 1.}) df_w = self.setup_dataframe(df_w) seas = self.predict_seasonal_components(df_w) days = days.weekday_name @@ -1025,12 +1039,11 @@ class Prophet(object): ax.set_ylabel('weekly') return artists - def plot_yearly(self, fcst, ax=None, uncertainty=True): + def plot_yearly(self, ax=None, uncertainty=True): """Plot the yearly component of the forecast. Parameters ---------- - fcst: pd.DataFrame output of self.predict. ax: Optional matplotlib Axes to plot on. One will be created if this is not provided. uncertainty: Optional boolean to plot uncertainty intervals. @@ -1044,7 +1057,8 @@ class Prophet(object): fig = plt.figure(facecolor='w', figsize=(10, 6)) ax = fig.add_subplot(111) # Compute yearly seasonality for a Jan 1 - Dec 31 sequence of dates. - df_y = pd.DataFrame({'ds': pd.date_range(start='2017-01-01', periods=365)}) + df_y = pd.DataFrame( + {'ds': pd.date_range(start='2017-01-01', periods=365), 'cap': 1.}) df_y = self.setup_dataframe(df_y) seas = self.predict_seasonal_components(df_y) artists += ax.plot(df_y['ds'], seas['yearly'], ls='-',