Skip to content

Commit c3ff3ba

Browse files
lkstrpfneum
andauthored
Add statistics documentation (PyPSA#1175)
* Add statistics documentation * Update doc/user-guide/statistics.rst Co-authored-by: Fabian Neumann <[email protected]> * Update doc/user-guide/statistics.rst Co-authored-by: Fabian Neumann <[email protected]> * Update pypsa/statistics/expressions.py Co-authored-by: Fabian Neumann <[email protected]> * Update pypsa/statistics/expressions.py Co-authored-by: Fabian Neumann <[email protected]> --------- Co-authored-by: Fabian Neumann <[email protected]>
1 parent b88c8cc commit c3ff3ba

22 files changed

+1074
-324
lines changed

doc/api/statistics.rst

Lines changed: 8 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@
22
Statistics
33
###########
44

5-
Statistic functions which can be called within a :class:`pypsa.Network` via
6-
``n.statistics.func``. For example ``n.statistics.capex()``.
5+
.. seealso::
76

8-
Statistic methods
9-
~~~~~~~~~~~~~~~~~~
7+
See :doc:`/user-guide/statistics` for the usage documentation.
8+
9+
Metrics
10+
========
1011

1112
.. autosummary::
1213
:toctree: _source/
@@ -27,42 +28,9 @@ Statistic methods
2728
~pypsa.statistics.StatisticsAccessor.revenue
2829
~pypsa.statistics.StatisticsAccessor.market_value
2930

30-
31-
Statistic groupers
32-
~~~~~~~~~~~~~~~~~~~
33-
34-
Groupers can be used via the ``groupby`` argument in the statistic methods.
35-
36-
.. code-block:: python
37-
38-
groupers = n.statistics.groupers
39-
n.statistics.capex(groupby=groupers.carrier)
40-
# or simply
41-
n.statistics.capex(groupby='carrier')
42-
43-
All default groupers are defined in the :class:`pypsa.statistics.grouping.Groupers`
44-
class and currently included are, grouping by ..
4531

46-
* .. :meth:`carrier <pypsa.statistics.grouping.Groupers.carrier>`
47-
* .. :meth:`bus_carrier <pypsa.statistics.grouping.Groupers.bus_carrier>`
48-
* .. :meth:`name <pypsa.statistics.grouping.Groupers.name>`
49-
* .. :meth:`bus <pypsa.statistics.grouping.Groupers.bus>`
50-
* .. :meth:`country <pypsa.statistics.grouping.Groupers.country>`
51-
* .. :meth:`unit <pypsa.statistics.grouping.Groupers.unit>`
52-
53-
Custom groupers can be registered on module level via
54-
:meth:`pypsa.statistics.groupers.add_grouper <pypsa.statistics.grouping.Groupers.add_grouper>`.
55-
The key will be used as identifier in the ``groupby`` argument.
56-
57-
Groupers can also be used to create multiindexed groupers. For example, to group by
58-
bus and carrier:
59-
60-
.. code-block:: python
61-
62-
groupers = n.statistics.groupers
63-
n.statistics.capex(groupby=groupers['bus', 'carrier'])
64-
# or simply
65-
n.statistics.capex(groupby=['bus', 'carrier'])
32+
Grouping
33+
========
6634

6735
.. autosummary::
6836
:toctree: _source/
@@ -74,5 +42,4 @@ bus and carrier:
7442
~pypsa.statistics.grouping.Groupers.name
7543
~pypsa.statistics.grouping.Groupers.bus
7644
~pypsa.statistics.grouping.Groupers.country
77-
~pypsa.statistics.grouping.Groupers.unit
78-
45+
~pypsa.statistics.grouping.Groupers.unit

doc/conf.py

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
# documentation root, use os.path.abspath to make it absolute, like shown here.
1717
# sys.path.insert(0, os.path.abspath('.'))
1818

19+
import doctest
1920
import os
2021
import sys
2122
from importlib.metadata import version as get_version
@@ -50,10 +51,8 @@
5051
"sphinx_reredirects",
5152
"nbsphinx",
5253
"nbsphinx_link",
53-
# 'sphinx.ext.pngmath',
54-
# 'sphinxcontrib.tikz',
55-
# 'rinoh.frontend.sphinx',
5654
"sphinx.ext.imgconverter", # for SVG conversion
55+
"sphinx.ext.doctest",
5756
]
5857

5958
autodoc_default_flags = ["members"]
@@ -346,6 +345,7 @@
346345
# Example configuration for intersphinx: refer to the Python standard library.
347346
intersphinx_mapping = {"python": ("https://docs.python.org/3", None)}
348347

348+
# Redirects for old URLs
349349
redirects = {
350350
# Redirects from old/ similar urls to new ones
351351
# Getting Started
@@ -377,3 +377,17 @@
377377
"users.html": "references/users.html",
378378
"developers.html": "references/developers.html",
379379
}
380+
381+
# Doctest configuration
382+
# Warning: Keep in sync with settings in test/test_docs.py
383+
doctest_global_setup = """
384+
import pypsa
385+
import pandas as pd
386+
import numpy as np
387+
388+
n = pypsa.examples.ac_dc_meshed()
389+
"""
390+
391+
doctest_default_flags = (
392+
doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS | doctest.IGNORE_EXCEPTION_DETAIL
393+
)
77.2 KB
Loading

doc/index.rst

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,11 +104,12 @@ Documentation
104104
* :doc:`/user-guide/power-flow`
105105
* :doc:`/user-guide/optimal-power-flow`
106106
* :doc:`/user-guide/contingency-analysis`
107+
* :doc:`/user-guide/statistics`
107108
* :doc:`/user-guide/plotting`
108109

109110
.. toctree::
110111
:hidden:
111-
:maxdepth: 2
112+
:maxdepth: 0
112113
:caption: User Guide
113114

114115
user-guide/design
@@ -117,6 +118,7 @@ Documentation
117118
user-guide/power-flow
118119
user-guide/optimal-power-flow
119120
user-guide/contingency-analysis
121+
user-guide/statistics
120122
user-guide/plotting
121123

122124
**Examples**
@@ -128,7 +130,7 @@ Documentation
128130

129131
.. toctree::
130132
:hidden:
131-
:maxdepth: 2
133+
:maxdepth: 1
132134
:caption: Examples
133135

134136
examples-index/lopf
@@ -144,7 +146,7 @@ Documentation
144146

145147
.. toctree::
146148
:hidden:
147-
:maxdepth: 1
149+
:maxdepth: 0
148150
:caption: Contributing & Support
149151

150152
contributing/contributing

doc/user-guide/statistics.rst

Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
###########
2+
Statistics
3+
###########
4+
5+
.. seealso::
6+
7+
See :doc:`/api/statistics` for the API reference.
8+
9+
Overview
10+
=========
11+
12+
The ``pypsa.statistics`` module provides an accessor to the ``pypsa.Network`` object
13+
via ``n.statistics``, enabling users to efficiently calculate key network metrics.
14+
This module is designed to simplify the analysis of network data by abstracting complex
15+
calculations into more accessible methods. It is particularly useful for users who
16+
prefer to avoid manual calculations and directly obtain relevant statistical data
17+
about the network.
18+
19+
20+
Available Metrics
21+
==================
22+
23+
.. autosummary::
24+
25+
~pypsa.statistics.StatisticsAccessor.capex
26+
~pypsa.statistics.StatisticsAccessor.installed_capex
27+
~pypsa.statistics.StatisticsAccessor.expanded_capex
28+
~pypsa.statistics.StatisticsAccessor.optimal_capacity
29+
~pypsa.statistics.StatisticsAccessor.installed_capacity
30+
~pypsa.statistics.StatisticsAccessor.expanded_capacity
31+
~pypsa.statistics.StatisticsAccessor.opex
32+
~pypsa.statistics.StatisticsAccessor.supply
33+
~pypsa.statistics.StatisticsAccessor.withdrawal
34+
~pypsa.statistics.StatisticsAccessor.transmission
35+
~pypsa.statistics.StatisticsAccessor.energy_balance
36+
~pypsa.statistics.StatisticsAccessor.curtailment
37+
~pypsa.statistics.StatisticsAccessor.capacity_factor
38+
~pypsa.statistics.StatisticsAccessor.revenue
39+
~pypsa.statistics.StatisticsAccessor.market_value
40+
41+
Usage
42+
-----------------
43+
44+
To utilize the statistics module, instantiate the accessor from a PyPSA network object
45+
as follows:
46+
47+
.. doctest::
48+
49+
>>> n = pypsa.Network()
50+
51+
You can then call specific methods from the ``statistics`` property to calculate various
52+
metrics, such as installed capacity or operational expenditure. For example:
53+
54+
.. doctest::
55+
56+
>>> installed_capacity = n.statistics.installed_capacity()
57+
>>> installed_capacity
58+
Component carrier
59+
Generator gas 100.0
60+
wind 50.0
61+
solar 30.0
62+
Name: optimal_capacity, dtype: float64
63+
64+
>>> opex = n.statistics.opex()
65+
>>> opex
66+
Component carrier
67+
Generator gas 1000.0
68+
wind 0.0
69+
solar 0.0
70+
Name: opex, dtype: float64
71+
72+
73+
Have a look at the method's docstring for more details on the arguments.
74+
75+
For example, to calculate the capital expenditure (capex) as a sum for all components,
76+
you can use:
77+
78+
.. doctest::
79+
80+
>>> n.statistics.capex(aggregate_groups='sum')
81+
82+
Similarly, to calculate the operational expenditure for all Link components, which
83+
connect to hydrogen (H2) buses:
84+
85+
.. doctest::
86+
87+
>>> n.statistics.opex(comps=["Link"], bus_carrier="H2")
88+
89+
Statistic groupers
90+
===================
91+
92+
Groupers can be used via the ``groupby`` argument in the statistic methods.
93+
94+
All default groupers are defined in the :class:`pypsa.statistics.grouping.Groupers`
95+
class and currently included are, grouping by ..
96+
97+
* :meth:`carrier <pypsa.statistics.grouping.Groupers.carrier>`
98+
* :meth:`bus_carrier <pypsa.statistics.grouping.Groupers.bus_carrier>`
99+
* :meth:`name <pypsa.statistics.grouping.Groupers.name>`
100+
* :meth:`bus <pypsa.statistics.grouping.Groupers.bus>`
101+
* :meth:`country <pypsa.statistics.grouping.Groupers.country>`
102+
* :meth:`unit <pypsa.statistics.grouping.Groupers.unit>`
103+
* A list of registered groupers can be accessed via
104+
:meth:`pypsa.statistics.groupers.list_groupers <pypsa.statistics.grouping.Groupers.list_groupers>`
105+
106+
Custom groupers can be registered on module level via
107+
:meth:`pypsa.statistics.groupers.add_grouper <pypsa.statistics.grouping.Groupers.add_grouper>`.
108+
The key will be used as identifier in the ``groupby`` argument.
109+
110+
Usage
111+
-----------------
112+
113+
.. doctest::
114+
115+
>>> groupers = n.statistics.groupers
116+
>>> n.statistics.capex(groupby=groupers.carrier)
117+
carrier
118+
gas 10000.0
119+
wind 5000.0
120+
solar 3000.0
121+
Name: capex, dtype: float64
122+
123+
>>> # or simply
124+
>>> n.statistics.capex(groupby='carrier')
125+
carrier
126+
gas 10000.0
127+
wind 5000.0
128+
solar 3000.0
129+
Name: capex, dtype: float64
130+
131+
132+
Groupers can also be used to create multiindexed groupers. For example, to group by
133+
bus and carrier:
134+
135+
.. code-block:: python
136+
137+
groupers = n.statistics.groupers
138+
n.statistics.capex(groupby=groupers['bus', 'carrier'])
139+
# or simply
140+
n.statistics.capex(groupby=['bus', 'carrier'])
141+
142+
.. autosummary::
143+
144+
~pypsa.statistics.grouping.Groupers.add_grouper
145+
~pypsa.statistics.grouping.Groupers.list_groupers
146+
~pypsa.statistics.grouping.Groupers.carrier
147+
~pypsa.statistics.grouping.Groupers.bus_carrier
148+
~pypsa.statistics.grouping.Groupers.name
149+
~pypsa.statistics.grouping.Groupers.bus
150+
~pypsa.statistics.grouping.Groupers.country
151+
~pypsa.statistics.grouping.Groupers.unit
152+
153+
154+
Advanced Examples and Visualization
155+
=======================================
156+
157+
In addition to basic usage, the statistics module offers advanced functionality for
158+
in-depth analysis and visualization of network metrics. Here are some advanced examples
159+
and visualization techniques:
160+
161+
1. **Comparative Analysis**: Users can compare different scenarios or network
162+
configurations by calculating metrics for each scenario and visualizing the results
163+
side by side. For example, compare the installed capacity of renewable energy sources
164+
in two different network models.
165+
166+
2. **Temporal Analysis**: Utilize the aggregate_time parameter to analyze temporal
167+
variations in network metrics. Plotting time series data can reveal patterns
168+
and trends over time, such as seasonal variations in energy supply or demand.
169+
170+
3. **Geospatial Visualization**: If the network includes geospatial data, users can
171+
create maps to visualize the distribution of network components and metrics
172+
geographically. This can be particularly useful for understanding spatial dependencies
173+
and identifying areas with high or low capacity utilization.
174+
175+
4. **Scenario Planning**: Explore different scenarios or what-if analyses by adjusting
176+
input parameters and observing the impact on network metrics. For example,
177+
simulate the effect of increasing renewable energy penetration on curtailment and
178+
market value.
179+
180+
5. **Interactive Dashboards**: Develop interactive dashboards using visualization
181+
libraries like Plotly or Bokeh to allow users to dynamically explore network
182+
metrics and drill down into specific details. Dashboards can provide a user-friendly
183+
interface for exploring complex network data.
184+
185+
Example Code Snippet:
186+
187+
.. doctest::
188+
189+
>>> import matplotlib.pyplot as plt
190+
>>> # Calculate installed capacity
191+
>>> installed_capacity = n.statistics.installed_capacity().droplevel(0)
192+
>>> # Plot installed capacity by component type
193+
>>> installed_capacity.plot(kind='bar', figsize=(10, 6))
194+
>>> plt.title('Installed Capacity by Component Type')
195+
>>> plt.xlabel('Component Type')
196+
>>> plt.ylabel('Installed Capacity (MW)')
197+
>>> plt.xticks(rotation=45)
198+
>>> plt.grid(axis='y')
199+
>>> plt.tight_layout()
200+
>>> plt.savefig('statistics_advanced_usage.png')
201+
>>> plt.close()
202+
203+
.. figure:: ../img/statistics_advanced_usage.png
204+
:alt: Installed Capacity by Component Type
205+
:width: 100%
206+
207+
Installed capacity by component type.
208+
209+
This code snippet calculates the installed capacity for each component type in the
210+
network and visualizes the results using a bar plot. Similar visualizations can
211+
be created for other metrics, providing valuable insights into the network's composition
212+
and characteristics.

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ ignore = [
158158
[tool.ruff.lint.per-file-ignores]
159159
# pydocstyle ignores, which could be enabled in future when existing
160160
# issues are fixed
161-
"!**/{grouping.py,components/**}" = [
161+
"!**/{grouping.py,components/**,statistics/**}" = [
162162
'D100', # Missing docstring in public module
163163
'D101', # Missing docstring in public class
164164
'D102', # Missing docstring in public method

0 commit comments

Comments
 (0)