Skip to content

Commit

Permalink
[Major] Add support for Python 3.12, drop support for Python 3.8 (#1544)
Browse files Browse the repository at this point in the history
* update poetry dependencies to py3.9 - py3.12

* make plotly-resampler optional

* fix register plotly imports

* Update ci.yml

* Update metrics.yml to use poetry for install
  • Loading branch information
ourownstory authored Feb 23, 2024
1 parent 7756a08 commit dbd0458
Show file tree
Hide file tree
Showing 8 changed files with 383 additions and 590 deletions.
12 changes: 7 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest]
python-version: ["3.8", "3.11"]
python-version: ["3.9", "3.12"]
env:
POETRY_VIRTUALENVS_CREATE: false
steps:
Expand All @@ -32,9 +32,11 @@ jobs:
- name: Install Poetry
uses: snok/install-poetry@v1
- name: Install dependencies
run: poetry install
run: poetry install --no-root --no-interaction --without docs
- name: Install Project
run: poetry install --no-interaction --without docs
- name: Pytest
run: poetry run pytest tests -v --cov=./ --cov-report=xml
run: poetry run pytest tests -v -n auto --durations=0 --cov=./ --cov-report=xml
- name: Upload coverage to codecov
uses: codecov/codecov-action@v3
with:
Expand All @@ -51,12 +53,12 @@ jobs:
- name: Install Python
uses: actions/setup-python@v4
with:
python-version: "3.11"
python-version: "3.12"
- name: Install Poetry
uses: abatilo/actions-poetry@v2
- name: Setup Pandoc
uses: r-lib/actions/setup-pandoc@v2
- name: Setup Requirements
run: poetry install --with=docs
run: poetry install --no-interaction --with docs
- name: Build with Sphinx
run: poetry run sphinx-build docs/source _site
14 changes: 7 additions & 7 deletions .github/workflows/linters.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ jobs:
- name: Checkout
uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: "3.10"
python-version: "3.12"
- run: python -m pip install flake8
- name: flake8
uses: liskin/gh-problem-matcher-wrap@v2
Expand All @@ -44,9 +44,9 @@ jobs:
- name: Checkout
uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: "3.10"
python-version: "3.12"
- run: python -m pip install isort
- name: isort
uses: liskin/gh-problem-matcher-wrap@v2
Expand All @@ -72,9 +72,9 @@ jobs:
- name: Checkout
uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: "3.10"
python-version: "3.12"
- name: Cache poetry
id: poetry-cache
uses: actions/cache@v3
Expand All @@ -85,6 +85,6 @@ jobs:
if: steps.poetry-cache.outputs.cache-hit != 'true'
uses: snok/install-poetry@v1
- name: Install dependencies
run: poetry install --with=docs,pyright
run: poetry install --no-interaction --with=docs,pyright
- name: pyright
uses: jakebailey/pyright-action@v1
43 changes: 24 additions & 19 deletions .github/workflows/metrics.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,24 +13,30 @@ on:
workflow_dispatch:
jobs:
metrics:
runs-on: ubuntu-latest
container: docker://ghcr.io/iterative/cml:0-dvc2-base1
env:
POETRY_VIRTUALENVS_CREATE: false
runs-on: ubuntu-latest # container: docker://ghcr.io/iterative/cml:0-dvc2-base1
steps:
- name: Checkout
uses: actions/checkout@v3
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: Install dependencies
run: |
python3 -m pip install --upgrade pip
pip3 install .
pip3 install pytest
pip3 install tabulate # required to md export
pip3 install kaleido # required for plotly export
- name: Install Python 3.12
uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Setup NodeJS (for CML)
uses: actions/setup-node@v3 # For CML
with:
node-version: '16'
- name: Setup CML
uses: iterative/setup-cml@v1
- name: Install Poetry
uses: snok/install-poetry@v1
- name: Install Dependencies
run: poetry install --no-interaction --no-root --without docs
- name: Install Project
run: poetry install --no-interaction --without docs
- name: Train model
run: pytest tests/test_model_performance.py
run: poetry run pytest tests/test_model_performance.py -n 1 --durations=0
- name: Download metrics from main
uses: dawidd6/action-download-artifact@v2
with:
Expand All @@ -39,11 +45,11 @@ jobs:
name: metrics
path: tests/metrics-main/
if_no_artifact_found: warn
- name: Compare performance
run: |
echo "## Model Benchmark" >> report.md
python tests/metrics/compareMetrics.py >> report.md
- name: Publish report
- name: Open Benchmark Report
run: echo "## Model Benchmark" >> report.md
- name: Write Benchmark Report
run: poetry run python tests/metrics/compareMetrics.py >> report.md
- name: Publish Report with CML
env:
REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
Expand All @@ -58,8 +64,7 @@ jobs:
echo "### EnergyPriceDaily" >> report.md
cml asset publish tests/metrics/EnergyPriceDaily.svg --md >> report.md
echo "\n</details>" >> report.md
# Post reports as comments in GitHub PRs
cml comment update --target=pr report.md # post to PR
cml comment update --target=pr report.md # Post reports as comments in GitHub PRs
cml check create --title=ModelReport report.md # update status of check in PR
- name: Upload metrics if on main
uses: actions/upload-artifact@v3
Expand Down
66 changes: 44 additions & 22 deletions neuralprophet/plot_forecast_plotly.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,21 @@

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

from neuralprophet.plot_model_parameters_plotly import get_dynamic_axis_range
from neuralprophet.plot_utils import set_y_as_percent

log = logging.getLogger("NP.plotly")

try:
import plotly.express as px
import plotly.graph_objs as go
from plotly.subplots import make_subplots
from plotly_resampler import register_plotly_resampler, unregister_plotly_resampler

plotly_resampler_installed = True
except ImportError:
plotly_resampler_installed = False
log.error("Importing plotly failed. Interactive plots will not work.")

# UI Configuration
Expand Down Expand Up @@ -81,10 +84,13 @@ def plot(
-------
Plotly figure
"""
if resampler_active:
register_plotly_resampler(mode="auto")
else:
unregister_plotly_resampler()
if plotly_resampler_installed:
if resampler_active:
register_plotly_resampler(mode="auto")
else:
unregister_plotly_resampler()
if resampler_active and not plotly_resampler_installed:
log.error("plotly-resampler is not installed. Please install it to use the resampler.")

cross_marker_color = "blue"
cross_symbol = "x"
Expand Down Expand Up @@ -222,7 +228,8 @@ def plot(
**layout_args,
)
fig = go.Figure(data=data, layout=layout)
unregister_plotly_resampler()
if plotly_resampler_installed:
unregister_plotly_resampler()
if plotly_static:
fig = fig.show("svg")
return fig
Expand Down Expand Up @@ -265,10 +272,14 @@ def plot_components(
Plotly figure
"""
log.debug("Plotting forecast components")
if resampler_active:
register_plotly_resampler(mode="auto")
else:
unregister_plotly_resampler()
if plotly_resampler_installed:
if resampler_active:
register_plotly_resampler(mode="auto")
else:
unregister_plotly_resampler()
if resampler_active and not plotly_resampler_installed:
log.error("plotly-resampler is not installed. Please install it to use the resampler.")

fcst = fcst.fillna(value=np.nan)
components_to_plot = plot_configuration["components_list"]

Expand Down Expand Up @@ -339,7 +350,8 @@ def plot_components(
# Reset multiplicative axes labels after tight_layout adjustment
for ax in multiplicative_axes:
ax = set_y_as_percent(ax)
unregister_plotly_resampler()
if plotly_resampler_installed:
unregister_plotly_resampler()
if plotly_static:
fig = fig.show("svg")
return fig
Expand Down Expand Up @@ -739,10 +751,14 @@ def plot_nonconformity_scores(scores, alpha, q, method, resampler_active=False):
Figure showing the nonconformity score with horizontal line for q-value based on the significance level or
alpha
"""
if resampler_active:
register_plotly_resampler(mode="auto")
else:
unregister_plotly_resampler()
if plotly_resampler_installed:
if resampler_active:
register_plotly_resampler(mode="auto")
else:
unregister_plotly_resampler()
if resampler_active and not plotly_resampler_installed:
log.error("plotly-resampler is not installed. Please install it to use the resampler.")

if not isinstance(q, list):
q_sym = q
scores = scores["noncon_scores"]
Expand Down Expand Up @@ -820,7 +836,8 @@ def plot_nonconformity_scores(scores, alpha, q, method, resampler_active=False):
line_color="red",
)
fig.update_layout(margin=dict(l=70, r=70, t=60, b=50))
unregister_plotly_resampler()
if plotly_resampler_installed:
unregister_plotly_resampler()
return fig


Expand All @@ -845,10 +862,14 @@ def plot_interval_width_per_timestep(q_hats, method, resampler_active=False):
plotly.graph_objects.Figure
Figure showing the q-values for each timestep
"""
if resampler_active:
register_plotly_resampler(mode="auto")
else:
unregister_plotly_resampler()
if plotly_resampler_installed:
if resampler_active:
register_plotly_resampler(mode="auto")
else:
unregister_plotly_resampler()
if resampler_active and not plotly_resampler_installed:
log.error("plotly-resampler is not installed. Please install it to use the resampler.")

# check if q_hats contains q_hat_sym
if "q_hat_sym" in q_hats.columns:
q_hats_sym = q_hats["q_hat_sym"]
Expand Down Expand Up @@ -880,7 +901,8 @@ def plot_interval_width_per_timestep(q_hats, method, resampler_active=False):
height=400,
)
fig.update_layout(margin=dict(l=70, r=70, t=60, b=50))
unregister_plotly_resampler()
if plotly_resampler_installed:
unregister_plotly_resampler()
return fig


Expand Down
25 changes: 17 additions & 8 deletions neuralprophet/plot_model_parameters_plotly.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,19 @@

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

from neuralprophet.plot_utils import predict_one_season, predict_season_from_dates

log = logging.getLogger("NP.plotly")

try:
import plotly.graph_objs as go
from plotly.subplots import make_subplots
from plotly_resampler import register_plotly_resampler, unregister_plotly_resampler

plotly_resampler_installed = True
except ImportError:
plotly_resampler_installed = False
log.error("Importing plotly failed. Interactive plots will not work.")

# UI Configuration
Expand All @@ -35,7 +38,8 @@
"title": dict(font=dict(size=12)),
"hovermode": "x unified",
}
register_plotly_resampler(mode="auto")
if plotly_resampler_installed:
register_plotly_resampler(mode="auto")


def get_dynamic_axis_range(df_range, type, pad=0.05, inverse=False):
Expand Down Expand Up @@ -872,10 +876,14 @@ def plot_parameters(
Returns:
Plotly figure
"""
if resampler_active:
register_plotly_resampler(mode="auto")
else:
unregister_plotly_resampler()
if plotly_resampler_installed:
if resampler_active:
register_plotly_resampler(mode="auto")
else:
unregister_plotly_resampler()
if resampler_active and not plotly_resampler_installed:
log.error("plotly-resampler is not installed. Please install it to use the resampler.")

compnents_to_plot = plot_configuration["components_list"]
additive_future_regressors = plot_configuration["additive_future_regressors"]
additive_events = plot_configuration["additive_events"]
Expand Down Expand Up @@ -963,5 +971,6 @@ def plot_parameters(
yaxis.update(**yaxis_args)
for trace in trace_object["traces"]:
fig.add_trace(trace, row=i + 1, col=1) # adapt var name to plotly-resampler
unregister_plotly_resampler()
if plotly_resampler_installed:
unregister_plotly_resampler()
return fig
Loading

0 comments on commit dbd0458

Please sign in to comment.