Skip to content
Open
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
7 changes: 4 additions & 3 deletions .github/workflows/nbval.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ jobs:
'TrendAnalysis_example.ipynb',
'TrendAnalysis_example_NSRDB.ipynb',
'degradation_and_soiling_example.ipynb',
'system_availability_example.ipynb'
'system_availability_example.ipynb',
'Multi-year_on_year_example.ipynb'
]

steps:
Expand All @@ -28,8 +29,8 @@ jobs:
pip install --timeout=300 -r requirements.txt -r docs/notebook_requirements.txt .[test]
- name: Run notebook and check output
run: |
# --sanitize-with: pre-process text to remove irrelevant differences (e.g. warning filepaths)
pytest --nbval docs/${{ matrix.notebook-file }} --sanitize-with docs/nbval_sanitization_rules.cfg
# --nbval-sanitize-with: pre-process text to remove irrelevant differences (e.g. warning filepaths)
pytest --nbval --nbval-sanitize-with docs/nbval_sanitization_rules.cfg docs/${{ matrix.notebook-file }}
- name: Run notebooks again, save files
run: |
pip install nbconvert[webpdf]
Expand Down
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@
# ignore byte compiled files
*.py[co]

# ignore coveralls yaml, coverge dir
# ignore coveralls yaml, coverage dir
.coveralls.yml
.coverage
.coverage.*
htmlcov/

# ignore test cache
Expand Down
553 changes: 553 additions & 0 deletions docs/Multi-year_on_year_example.ipynb

Large diffs are not rendered by default.

30,696 changes: 182 additions & 30,514 deletions docs/TrendAnalysis_example.ipynb

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion docs/TrendAnalysis_example_NSRDB.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@
"ax.plot(df.index, df.soiling, 'o', alpha=0.01)\n",
"#ax.set_ylim(0,1500)\n",
"fig.autofmt_xdate()\n",
"ax.set_ylabel('soiling signal');\n",
"ax.set_ylabel('soiling signal')\n",
"df['power'] = df['power_ac'] * df['soiling']\n",
"\n",
"plt.show()"
Expand Down
4 changes: 3 additions & 1 deletion docs/notebook_requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ nbconvert==7.17.0
nbformat==5.10.4
nest-asyncio==1.6.0
notebook==7.2.2
numexpr==2.10.1
numexpr==2.10.2
pandocfilters==1.5.1
parso==0.8.4
pexpect==4.9.0
Expand All @@ -45,6 +45,7 @@ qtconsole==5.5.2
Send2Trash==1.8.3
simplegeneric==0.8.1
soupsieve==2.6
tabulate==0.9.0
terminado==0.18.1
testpath==0.6.0
tinycss2==1.2.1
Expand All @@ -53,3 +54,4 @@ traitlets==5.14.3
wcwidth==0.2.13
webencodings==0.5.1
widgetsnbextension==4.0.11

2 changes: 1 addition & 1 deletion docs/sphinx/source/changelog.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
RdTools Change Log
==================
.. include:: changelog/pending.rst
.. include:: changelog/v3.2.0.rst
.. include:: changelog/v3.1.1.rst
.. include:: changelog/v3.1.0.rst
.. include:: changelog/v3.0.1.rst
Expand Down
10 changes: 0 additions & 10 deletions docs/sphinx/source/changelog/pending.rst

This file was deleted.

78 changes: 78 additions & 0 deletions docs/sphinx/source/changelog/v3.2.0.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
*************************
v3.2.0 (X, X, 2026)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to add an explanation that the index of YoY_values has changed from a timestamp to integer and that the original behavior can be reconstructed with the help of calc_info['YoY_times']. Strictly speaking, I don't think this is backward compatible, but for this case I think it may be ok to keep it in a minor version update.

*************************

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another even more in the weeds changes is that we have replaced NaNs in calc_info['usage_of_points'] with zeros. I don't know if this ever happens in practice but probably worth it to call out the edge case change.


Enhancements
------------
* :py:func:`~rdtools.degradation.degradation_year_on_year` has new parameter ``multi_yoy``
(default False) to trigger multiple YoY degradation calculations similar to Hugo Quest et

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's include a citation to the Quest paper

al 2023. In this mode, instead of a series of 1-year duration slopes, 2-year, 3-year etc
slopes are also included. calc_info['YoY_values'] returns a non-monotonic index
in this mode due to multiple overlapping annual slopes. (:issue:`394`)
* :py:func:`~rdtools.degradation.degradation_year_on_year` now returns
``calc_info['YoY_times']`` DataFrame with ``dt_right``, ``dt_center``, and ``dt_left``
columns for each YoY slope. (:issue:`459`)
* :py:func:`~rdtools.plotting.degradation_timeseries_plot` now supports ``multi_yoy=True``
data. To avoid over-filtering, only slopes on the order of 2 years (731 days) or
shorter are included in the center-labeled median. (:issue:`394`) (:pull:`498`)
* :py:func:`~rdtools.plotting.degradation_timeseries_plot` refactored to do a rolling
median, for all slopes whose center timestamp is inside the window.
``min_periods`` reduced to ``rolling_days//4``.
(:issue:`455`) (:pull:`498`)
* Added ``min_periods_divisor`` argument to
:py:func:`rdtools.plotting.degradation_timeseries_plot` to control the
minimum number of observations required in each rolling window
(``rolling_days // min_periods_divisor``). The current default of ``2``
is preserved, and a ``FutureWarning`` is emitted when the default is
used to signal that the default will change to ``4`` in a future major
release, making the time-series plot more resilient to small data
outages without losing fidelity. (:pull:`498`)
* :py:func:`~rdtools.plotting.degradation_summary_plots` ``detailed=True`` mode now
properly handles points used odd vs even number of times (not just 0, 1, 2).
(:issue:`394`)
* Added new example notebook ``docs/Multi-year_on_year_example.ipynb`` demonstrating the
``multi_yoy=True`` features of
:py:func:`~rdtools.degradation.degradation_year_on_year`. (:issue:`394`)

Bug Fixes
---------
* Fixed ``usage_of_points`` calculation in :py:func:`~rdtools.degradation.degradation_year_on_year`
to properly handle ``multi_yoy=True`` mode with overlapping slopes. (:issue:`394`)

Maintenance
-----------
* Added ``_avg_timestamp_old_Pandas`` helper function for pandas <2.0 compatibility
when calculating center labels.
* Fixed nbval workflow command syntax (``--sanitize-with`` to ``--nbval-sanitize-with``).
* Improved pandas 3.0 compatibility with datetime resolution handling.
* Updated ``docs/notebook_requirements.txt`` to require ``numexpr>=2.10.2`` and
``tabulate>=0.9.0`` to satisfy pandas' optional dependency minimum versions and
avoid related warnings/errors.
* Removed trailing semicolons in example notebooks.
* Added ``.coverage.*`` pattern to ``.gitignore``.
* Updated the download URL for the ``pvdaq_system_4_2010-2016_subset_soil_signal.csv``
example dataset used by the notebooks and the analysis chains tests to a
GitHub release asset under ``NatLabRockies/rdtools``. (:pull:`513`)

Testing
-------
* Added tests for error handling paths in :py:mod:`~rdtools.analysis_chains`:
``filter_params`` and ``filter_params_aggregated`` setter validation,
``clearsky_rescale_index_mismatch``, ``poa_filter_without_poa``,
``tcell_filter_without_temperature``, ``hour_angle_filter_without_location``,
``clearsky_filter_without_poa``, and ``degradation_timeseries_plot_invalid_case``.
* Added tests for error handling paths in :py:mod:`~rdtools.degradation`:
``classical_decomposition`` missing/irregular data, ``year_on_year`` circular block
validation, no valid pairs error, and ``_mk_test`` edge cases (no trend, ties,
decreasing).
* Added test for ``multi_yoy=True`` parameter in ``degradation_year_on_year``.
* Added tests for :py:func:`~rdtools.plotting.degradation_timeseries_plot`
covering multi-YoY duplicate index handling, and ``KeyError`` path.
* Set matplotlib backend to ``Agg`` in test ``conftest.py`` to avoid tkinter issues.


Contributors
------------
* Chris Deline (:ghuser:`cdeline`)
* Martin Springer (:ghuser:`martin-springer`)

1 change: 1 addition & 0 deletions docs/sphinx/source/examples.rst
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,4 @@ This page shows example usage of the RdTools analysis functions.
examples/TrendAnalysis_example
examples/TrendAnalysis_example_NSRDB
examples/system_availability_example
examples/Multi-year_on_year_example
3 changes: 3 additions & 0 deletions docs/sphinx/source/examples/Multi-year_on_year_example.nblink
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"path": "../../../Multi-year_on_year_example.ipynb"
}
19 changes: 14 additions & 5 deletions rdtools/analysis_chains.py
Original file line number Diff line number Diff line change
Expand Up @@ -1053,7 +1053,7 @@ def clearsky_analysis(
Analyses to perform as a list of strings. Valid entries are 'yoy_degradation'
and 'srr_soiling'
yoy_kwargs : dict
kwargs to pass to :py:func:`rdtools.degradation.degradation_year_on_year`
kwargs to pass to :py:func:`rdtools.degradation.degradation_year_on_year`.
srr_kwargs : dict
kwargs to pass to :py:func:`rdtools.soiling.soiling_srr`

Expand Down Expand Up @@ -1248,7 +1248,7 @@ def plot_pv_vs_irradiance(self, case, alpha=0.01, **kwargs):
ax.set_ylabel("PV Energy (Wh/timestep)")
return fig

def plot_degradation_timeseries(self, case, rolling_days=365, **kwargs):
def plot_degradation_timeseries(self, case, rolling_days=365, center=None, **kwargs):
"""
Plot resampled time series of degradation trend with time

Expand All @@ -1257,8 +1257,17 @@ def plot_degradation_timeseries(self, case, rolling_days=365, **kwargs):
case: str
The workflow result to plot, allowed values are 'sensor' and 'clearsky'
rolling_days: int, default 365
Number of days for rolling window. Note that the window must contain
at least 50% of datapoints to be included in rolling plot.
Number of days for rolling window. The window must contain at least
``rolling_days // min_periods_divisor`` datapoints to be included in
the rolling plot; see
:py:func:`rdtools.plotting.degradation_timeseries_plot` for details
on ``min_periods_divisor`` and its pending default change.
center : bool, default False
If ``True``, the rolling window is centered and results are reindexed
using center timestamps before any calculations are performed.
The recommended value is ``True``; the default of ``False`` is retained
only for backward compatibility. A warning is raised when this argument
is not explicitly supplied.
kwargs :
Extra parameters passed to :py:func:`rdtools.plotting.degradation_timeseries_plot`

Expand All @@ -1274,7 +1283,7 @@ def plot_degradation_timeseries(self, case, rolling_days=365, **kwargs):
else:
raise ValueError("case must be either 'sensor' or 'clearsky'")

fig = plotting.degradation_timeseries_plot(yoy_info, rolling_days, **kwargs)
fig = plotting.degradation_timeseries_plot(yoy_info, rolling_days, center=center, **kwargs)
return fig


Expand Down
Loading
Loading