Skip to content

Add gallery of examples using sphinx-gallery #846

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

Merged
merged 14 commits into from
Jan 10, 2020
Merged
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
4 changes: 4 additions & 0 deletions docs/examples/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Example Gallery
===============

This gallery shows examples of pvlib functionality. Community contributions are welcome!
77 changes: 77 additions & 0 deletions docs/examples/plot_single_axis_tracking.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
"""
Single-axis tracking
====================

Examples of modeling tilt angles for single-axis tracker arrays.
"""

#%%
# This example shows basic usage of pvlib's tracker position calculations with
# :py:meth:`pvlib.tracking.singleaxis`. The examples shown here demonstrate
# how the tracker parameters affect the generated tilt angles.
#
# Because tracker angle is based on where the sun is in the sky, calculating
# solar position is always the first step.
#
# True-tracking
# -------------
#
# The basic tracking algorithm is called "true-tracking". It orients the panels
# towards the sun as much as possible in order to maximize the cross section
# presented towards incoming beam irradiance.

from pvlib import solarposition, tracking
import pandas as pd
import matplotlib.pyplot as plt

tz = 'US/Eastern'
lat, lon = 40, -80

times = pd.date_range('2019-01-01', '2019-01-02', closed='left', freq='5min',
tz=tz)
solpos = solarposition.get_solarposition(times, lat, lon)

truetracking_angles = tracking.singleaxis(
apparent_zenith=solpos['apparent_zenith'],
apparent_azimuth=solpos['azimuth'],
axis_tilt=0,
axis_azimuth=180,
max_angle=90,
backtrack=False, # for true-tracking
gcr=0.5) # irrelevant for true-tracking

truetracking_position = truetracking_angles['tracker_theta'].fillna(0)
truetracking_position.plot(title='Truetracking Curve')

plt.show()

#%%
# Backtracking
# -------------
#
# Because truetracking yields steep tilt angle in morning and afternoon, it
# will cause row to row shading as the shadows from adjacent rows fall on each
# other. To prevent this, the trackers can rotate backwards when the sun is
# near the horizon -- "backtracking". The shading angle depends on row
# geometry, so the gcr parameter must be specified. The greater the gcr, the
# tighter the row spacing and the more aggressively the array must backtrack.

fig, ax = plt.subplots()

for gcr in [0.2, 0.4, 0.6]:
backtracking_angles = tracking.singleaxis(
apparent_zenith=solpos['apparent_zenith'],
apparent_azimuth=solpos['azimuth'],
axis_tilt=0,
axis_azimuth=180,
max_angle=90,
backtrack=True,
gcr=gcr)

backtracking_position = backtracking_angles['tracker_theta'].fillna(0)
backtracking_position.plot(title='Backtracking Curve',
label='GCR:{:0.01f}'.format(gcr),
ax=ax)

plt.legend()
plt.show()
137 changes: 137 additions & 0 deletions docs/examples/plot_sunpath_diagrams.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
"""
Sun path diagram
================

Examples of generating sunpath diagrams.
"""

#%%
# This example shows basic usage of pvlib's solar position calculations with
# :py:meth:`pvlib.solarposition.get_solarposition`. The examples shown here
# will generate sunpath diagrams that shows solar position over a year.
#
# Polar plot
# ----------
#
# Below is an example plot of solar position in
# `polar coordinates <https://en.wikipedia.org/wiki/Polar_coordinate_system>`_.

from pvlib import solarposition
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

tz = 'Asia/Calcutta'
lat, lon = 28.6, 77.2

times = pd.date_range('2019-01-01 00:00:00', '2020-01-01', closed='left',
freq='H', tz=tz)
solpos = solarposition.get_solarposition(times, lat, lon)
# remove nighttime
solpos = solpos.loc[solpos['apparent_elevation'] > 0, :]

ax = plt.subplot(1, 1, 1, projection='polar')
# draw the analemma loops
points = ax.scatter(np.radians(solpos.azimuth), solpos.apparent_zenith,
s=2, label=None, c=solpos.index.dayofyear)
ax.figure.colorbar(points)

# draw hour labels
for hour in np.unique(solpos.index.hour):
# choose label position by the smallest radius for each hour
subset = solpos.loc[solpos.index.hour == hour, :]
r = subset.apparent_zenith
pos = solpos.loc[r.idxmin(), :]
ax.text(np.radians(pos['azimuth']), pos['apparent_zenith'], str(hour))

# draw individual days
for date in pd.to_datetime(['2019-03-21', '2019-06-21', '2019-12-21']):
times = pd.date_range(date, date+pd.Timedelta('24h'), freq='5min', tz=tz)
solpos = solarposition.get_solarposition(times, lat, lon)
solpos = solpos.loc[solpos['apparent_elevation'] > 0, :]
label = date.strftime('%Y-%m-%d')
ax.plot(np.radians(solpos.azimuth), solpos.apparent_zenith, label=label)

ax.figure.legend(loc='upper left')

# change coordinates to be like a compass
ax.set_theta_zero_location('N')
ax.set_theta_direction(-1)
ax.set_rmax(90)

plt.show()

#%%
# This is a polar plot of hourly solar zenith and azimuth. The figure-8
# patterns are called `analemmas <https://en.wikipedia.org/wiki/Analemma>`_ and
# show how the sun's path slowly shifts over the course of the year . The
# colored lines show the single-day sun paths for the winter and summer
# solstices as well as the spring equinox.
#
# The soltice paths mark the boundary of the sky area that the sun traverses
# over a year. The diagram shows that there is no point in the
# year when is the sun directly overhead (zenith=0) -- note that this location
# is north of the Tropic of Cancer.
#
# Examining the sun path for the summer solstice in particular shows that
# the sun rises north of east, crosses into the southern sky around 10 AM for a
# few hours before crossing back into the northern sky around 3 PM and setting
# north of west. In contrast, the winter solstice sun path remains in the
# southern sky the entire day. Moreover, the diagram shows that the winter
# solstice is a shorter day than the summer soltice -- in December, the sun
# rises after 7 AM and sets before 6 PM, whereas in June the sun is up before
# 6 AM and sets after 7 PM.
#
# Another use of this diagram is to determine what times of year the sun is
# blocked by obstacles. For instance, for a mountain range on the western side
# of an array that extends 10 degrees above the horizon, the sun is blocked:
#
# - after about 6:30 PM on the summer solstice
# - after about 5:30 PM on the spring equinox
# - after about 4:30 PM on the winter solstice

#%%
# PVSyst Plot
# -----------
#
# PVSyst users will be more familiar with sunpath diagrams in Cartesian
# coordinates:

from pvlib import solarposition
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

tz = 'Asia/Calcutta'
lat, lon = 28.6, 77.2
times = pd.date_range('2019-01-01 00:00:00', '2020-01-01', closed='left',
freq='H', tz=tz)

solpos = solarposition.get_solarposition(times, lat, lon)
# remove nighttime
solpos = solpos.loc[solpos['apparent_elevation'] > 0, :]

fig, ax = plt.subplots()
points = ax.scatter(solpos.azimuth, solpos.apparent_elevation, s=2,
c=solpos.index.dayofyear, label=None)
fig.colorbar(points)

for hour in np.unique(solpos.index.hour):
# choose label position by the largest elevation for each hour
subset = solpos.loc[solpos.index.hour == hour, :]
height = subset.apparent_elevation
pos = solpos.loc[height.idxmax(), :]
ax.text(pos['azimuth'], pos['apparent_elevation'], str(hour))

for date in pd.to_datetime(['2019-03-21', '2019-06-21', '2019-12-21']):
times = pd.date_range(date, date+pd.Timedelta('24h'), freq='5min', tz=tz)
solpos = solarposition.get_solarposition(times, lat, lon)
solpos = solpos.loc[solpos['apparent_elevation'] > 0, :]
label = date.strftime('%Y-%m-%d')
ax.plot(solpos.azimuth, solpos.apparent_elevation, label=label)

ax.figure.legend(loc='upper left')
ax.set_xlabel('Solar Azimuth (degrees)')
ax.set_ylabel('Solar Elevation (degrees)')

plt.show()
19 changes: 18 additions & 1 deletion docs/sphinx/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
# Mock modules so RTD works
from unittest.mock import MagicMock

# for warning suppression
import warnings


class Mock(MagicMock):
@classmethod
Expand Down Expand Up @@ -55,7 +58,8 @@ def __getattr__(cls, name):
'sphinx.ext.napoleon',
'sphinx.ext.autosummary',
'IPython.sphinxext.ipython_directive',
'IPython.sphinxext.ipython_console_highlighting'
'IPython.sphinxext.ipython_console_highlighting',
'sphinx_gallery.gen_gallery',
]

napoleon_use_rtype = False # group rtype on same line together with return
Expand Down Expand Up @@ -324,3 +328,16 @@ def setup(app):
# suppress "WARNING: Footnote [1] is not referenced." messages
# https://github.com/pvlib/pvlib-python/issues/837
suppress_warnings = ['ref.footnote']

# settings for sphinx-gallery
sphinx_gallery_conf = {
'examples_dirs': ['../../examples'], # location of gallery scripts
'gallery_dirs': ['auto_examples'], # location of generated output
# sphinx-gallery only shows plots from plot_*.py files by default:
# 'filename_pattern': '*.py',
}
# supress warnings in gallery output
# https://sphinx-gallery.github.io/stable/configuration.html
warnings.filterwarnings("ignore", category=UserWarning,
message='Matplotlib is currently using agg, which is a'
' non-GUI backend, so cannot show the figure.')
3 changes: 2 additions & 1 deletion docs/sphinx/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,8 @@ Contents
:maxdepth: 1

package_overview
introexamples
introtutorial
auto_examples/index
whatsnew
installation
contributing
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
.. _introexamples:
.. _introtutorial:
Copy link
Member

Choose a reason for hiding this comment

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

update link in package_overview.rst line 15


Intro Examples
Intro Tutorial
==============

This page contains introductory examples of pvlib python usage.
Expand Down
2 changes: 1 addition & 1 deletion docs/sphinx/source/package_overview.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ interoperable, and benchmark implementations of PV system models.
There are at least as many opinions about how to model PV systems as
there are modelers of PV systems, so pvlib-python provides several
modeling paradigms: functions, the Location/PVSystem classes, and the
ModelChain class. Read more about this in the :ref:`introexamples`
ModelChain class. Read more about this in the :ref:`introtutorial`
section.


Expand Down
1 change: 1 addition & 0 deletions docs/sphinx/source/whatsnew/v0.7.1.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ Testing

Documentation
~~~~~~~~~~~~~
* Created an Example Gallery. (:pull:`846`)
* Updated list of allowed years for `iotools.get_psm3`.

Contributors
Expand Down
3 changes: 2 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@
EXTRAS_REQUIRE = {
'optional': ['ephem', 'cython', 'netcdf4', 'nrel-pysam', 'numba',
'pvfactors', 'scipy', 'siphon', 'tables'],
'doc': ['ipython', 'matplotlib', 'sphinx == 1.8.5', 'sphinx_rtd_theme'],
'doc': ['ipython', 'matplotlib', 'sphinx == 1.8.5', 'sphinx_rtd_theme',
'sphinx-gallery'],
'test': TESTS_REQUIRE
}
EXTRAS_REQUIRE['all'] = sorted(set(sum(EXTRAS_REQUIRE.values(), [])))
Expand Down