diff --git a/python/prophet/plot.py b/python/prophet/plot.py index 3e7efb9d7..00629df42 100644 --- a/python/prophet/plot.py +++ b/python/prophet/plot.py @@ -309,7 +309,11 @@ def seasonality_plot_df( ------- A dataframe with seasonal components on ds. """ - df_dict = {'ds': ds, 'cap': 1., 'floor': 0.} + floor = 0. + if not m.logistic_floor and m.scaling == 'minmax': + # setup_dataframe sets the floor to y_min, so keep the cap above it. + floor = cast(float, m.y_min) + df_dict = {'ds': ds, 'cap': floor + 1., 'floor': floor} for name in m.extra_regressors: df_dict[name] = 0. # Activate all conditional seasonality columns diff --git a/python/prophet/tests/test_plot.py b/python/prophet/tests/test_plot.py index e3df0489d..17a74e1c0 100644 --- a/python/prophet/tests/test_plot.py +++ b/python/prophet/tests/test_plot.py @@ -162,6 +162,19 @@ def test_without_uncertainty_samples(self, daily_univariate_ts, backend): data = _seasonality_plot_data(m, "weekly", days, uncertainty=True) assert list(data.columns) == ["ds", "weekly"] + def test_logistic_minmax_without_floor(self, daily_univariate_ts, backend): + # With minmax scaling and no floor column, the floor is the minimum of y. + history = daily_univariate_ts.copy() + history["cap"] = history["y"].max() * 1.5 + assert history["y"].min() > 1 + m = Prophet(stan_backend=backend, growth="logistic", scaling="minmax") + m.fit(history, seed=1237861298) + days = pd.date_range("2017-01-01", periods=7) + data = _seasonality_plot_data(m, "weekly", days) + fcst = m.predict(pd.DataFrame({"ds": days, "cap": history["cap"].iloc[0]})) + for col in ["weekly", "weekly_lower", "weekly_upper"]: + np.testing.assert_allclose(data[col], fcst[col]) + @pytest.mark.parametrize("uncertainty", [True, False]) def test_matplotlib_draws_data(self, model_and_forecast, uncertainty): m, _ = model_and_forecast