Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Major] Separate plotting dependencies to enable running without plotting #1611

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 36 additions & 26 deletions neuralprophet/plot_forecast_plotly.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,17 @@

import numpy as np
import pandas as pd
import plotly.express as px
import plotly.graph_objs as go

try:
import plotly.express as px
import plotly.graph_objs as go

plotly_installed = True
except ImportError:
from neuralprophet.plot_utils import show_import_error_warning

plotly_installed = False
show_import_error_warning("plotly")

from neuralprophet.plot_model_parameters_plotly import get_dynamic_axis_range
from neuralprophet.plot_utils import set_y_as_percent
Expand All @@ -19,30 +28,31 @@
plotly_resampler_installed = False
log.error("Importing plotly failed. Interactive plots will not work.")

# UI Configuration
prediction_color = "#2d92ff"
actual_color = "black"
trend_color = "#B23B00"
line_width = 2
marker_size = 4
xaxis_args = {
"showline": True,
"mirror": True,
"linewidth": 1.5,
}
yaxis_args = {
"showline": True,
"mirror": True,
"linewidth": 1.5,
}
layout_args = {
"autosize": True,
"template": "plotly_white",
"margin": go.layout.Margin(l=0, r=10, b=0, t=10, pad=0),
"font": dict(size=10),
"title": dict(font=dict(size=12)),
"hovermode": "x unified",
}
if plotly_installed:
# UI Configuration
prediction_color = "#2d92ff"
actual_color = "black"
trend_color = "#B23B00"
line_width = 2
marker_size = 4
xaxis_args = {
"showline": True,
"mirror": True,
"linewidth": 1.5,
}
yaxis_args = {
"showline": True,
"mirror": True,
"linewidth": 1.5,
}
layout_args = {
"autosize": True,
"template": "plotly_white",
"margin": go.layout.Margin(l=0, r=10, b=0, t=10, pad=0),
"font": dict(size=10),
"title": dict(font=dict(size=12)),
"hovermode": "x unified",
}


def plot(
Expand Down
57 changes: 35 additions & 22 deletions neuralprophet/plot_model_parameters_plotly.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,18 @@

import numpy as np
import pandas as pd
import plotly.graph_objs as go
from plotly.subplots import make_subplots

try:
import plotly.express as px

Check failure on line 8 in neuralprophet/plot_model_parameters_plotly.py

View workflow job for this annotation

GitHub Actions / flake8

'plotly.express as px' imported but unused
import plotly.graph_objs as go

plotly_installed = True

except ImportError:
from neuralprophet.plot_utils import show_import_error_warning

plotly_installed = False
show_import_error_warning("plotly")

from neuralprophet.plot_utils import predict_one_season, predict_season_from_dates

Expand All @@ -18,26 +28,29 @@
plotly_resampler_installed = False
log.error("Importing plotly failed. Interactive plots will not work.")

# UI Configuration
color = "#2d92ff"
xaxis_args = {
"showline": True,
"mirror": True,
"linewidth": 1.5,
}
yaxis_args = {
"showline": True,
"mirror": True,
"linewidth": 1.5,
}
layout_args = {
"autosize": True,
"template": "plotly_white",
"margin": go.layout.Margin(l=0, r=10, b=0, t=10, pad=0),
"font": dict(size=10),
"title": dict(font=dict(size=12)),
"hovermode": "x unified",
}

if plotly_installed:
# UI Configuration
color = "#2d92ff"
xaxis_args = {
"showline": True,
"mirror": True,
"linewidth": 1.5,
}
yaxis_args = {
"showline": True,
"mirror": True,
"linewidth": 1.5,
}
layout_args = {
"autosize": True,
"template": "plotly_white",
"margin": go.layout.Margin(l=0, r=10, b=0, t=10, pad=0),
"font": dict(size=10),
"title": dict(font=dict(size=12)),
"hovermode": "x unified",
}

if plotly_resampler_installed:
register_plotly_resampler(mode="auto")

Expand Down Expand Up @@ -895,7 +908,7 @@
figsize = figsize if figsize else (700, 210 * npanel)

# Create Plotly subplot figure and add the components to it
fig = make_subplots(npanel, cols=1, print_grid=False)

Check failure on line 911 in neuralprophet/plot_model_parameters_plotly.py

View workflow job for this annotation

GitHub Actions / flake8

undefined name 'make_subplots'
fig.update_layout(go.Layout(showlegend=False, width=figsize[0], height=figsize[1] * npanel, **layout_args))

for i, comp in enumerate(compnents_to_plot):
Expand Down
52 changes: 50 additions & 2 deletions neuralprophet/plot_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -581,7 +581,10 @@
the code and the function did not switch to a valid environment.
"""

from IPython import get_ipython
try:
from IPython import get_ipython
except ImportError:
return None # TODO not entirely sure if that is the correct behavior to simply return None here @Oscar?

if "google.colab" in str(get_ipython()):
if auto:
Expand Down Expand Up @@ -627,6 +630,7 @@
def select_plotting_backend(model, plotting_backend):
"""Automatically selects the plotting backend based on the global plotting_backend and plotting_backend set by the
user. If the plotting backend is selected as "plotly-resampler", triggers warning message.
If the plotting backend is not installed, triggers warning message and returns "no-backend-installed".

Parameters
----------
Expand All @@ -652,4 +656,48 @@
plotting_backend = "plotly"
elif plotting_backend == "plotly-resampler":
validate_current_env_for_resampler()
return plotting_backend.lower()
return validate_plotting_backend_installed(
plotting_backend.lower()
) # in case plotting backend is not installed, return None


def show_import_error_warning(module_name: str):
"""
Raise a warning if a module is not installed.

Parameters
----------
module_name: str
The name of the module that is not installed.
"""
logging.warning(f"{module_name} not installed. Plotting will not work.")
warnings.warn(
f"{module_name} not installed. Plotting will not work."
"This might be due to you running with poetry in minimal mode."
"Use `poety install --with plotting` to install."
)


def validate_plotting_backend_installed(plotting_backend: str):
"""
Validate if the plotting backend is installed.

Parameters
----------
plotting_backend: str
The plotting backend to validate.
"""
if plotting_backend.startswith("plotly"):
try:
import plotly.graph_objects as go

Check failure on line 692 in neuralprophet/plot_utils.py

View workflow job for this annotation

GitHub Actions / flake8

'plotly.graph_objects as go' imported but unused
except ImportError:
show_import_error_warning("plotly")
return "no-backend-installed"
elif plotting_backend == "matplotlib":
try:
import matplotlib.pyplot as plt

Check failure on line 698 in neuralprophet/plot_utils.py

View workflow job for this annotation

GitHub Actions / flake8

'matplotlib.pyplot as plt' imported but unused
except ImportError:
show_import_error_warning("matplotlib")
return "no-backend-installed"
else:
return plotting_backend
2 changes: 2 additions & 0 deletions neuralprophet/uncertainty.py
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,8 @@
else:
fig = plot_interval_width_per_timestep_plotly(self.q_hats, method, resampler_active=False)
fig.show()
elif plotting_backend == "no-backend-installed":
return None
else:
if self.n_forecasts == 1:
# includes nonconformity scores of the first timestep
Expand All @@ -284,7 +286,7 @@
else:
fig = plot_interval_width_per_timestep(self.q_hats, method)
if plotting_backend in ["matplotlib", "plotly", "plotly-resampler"] and matplotlib.is_interactive():
fig

Check warning on line 289 in neuralprophet/uncertainty.py

View workflow job for this annotation

GitHub Actions / pyright

Expression value is unused (reportUnusedExpression)


def uncertainty_evaluate(df_forecast: pd.DataFrame) -> pd.DataFrame:
Expand Down
Loading
Loading