From 4c8f4353d250a928e4ec0b5f802389785b7f63c3 Mon Sep 17 00:00:00 2001 From: Kevin Anderson Date: Fri, 3 Jan 2020 18:48:26 -0700 Subject: [PATCH 01/13] draft of sunpath diagram example --- docs/sphinx/source/index.rst | 1 + docs/sphinx/source/solarposition.rst | 70 ++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 docs/sphinx/source/solarposition.rst diff --git a/docs/sphinx/source/index.rst b/docs/sphinx/source/index.rst index eea01dd9df..d9b2f0331a 100644 --- a/docs/sphinx/source/index.rst +++ b/docs/sphinx/source/index.rst @@ -87,6 +87,7 @@ Contents pvsystem modelchain timetimezones + solarposition clearsky forecasts api diff --git a/docs/sphinx/source/solarposition.rst b/docs/sphinx/source/solarposition.rst new file mode 100644 index 0000000000..bc845512ae --- /dev/null +++ b/docs/sphinx/source/solarposition.rst @@ -0,0 +1,70 @@ +.. _solarposition: + +Solar Position +============== + +This section shows basic usage of pvlib's solar position calculations with +:py:meth:`pvlib.solarposition.get_solarposition`. The example shown here will +generate a sunpath diagram that shows how solar position varies across a year. + +.. ipython:: + + In [1]: from pvlib import solarposition + ...: import pandas as pd + ...: import numpy as np + ...: import matplotlib.pyplot as plt + ...: + + In [5]: tz = 'Asia/Calcutta' + ...: lat, lon = 28.6, 77.2 + ...: + + In [8]: times = pd.date_range('2019-01-01 00:00:00', '2020-01-01', closed='left', + ...: freq='H', tz=tz) + ...: + + In [9]: solpos = solarposition.get_solarposition(times, lat, lon) + ...: # remove nighttime + ...: solpos = solpos.loc[solpos['apparent_elevation'] > 0, :] + + In [13]: ax = plt.subplot(1, 1, 1, projection='polar') + + In [14]: # 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) + ....: + + In [16]: # 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)) + ....: + ....: + + In [17]: # 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') + ....: + + @savefig sunpath-diagram.png width=6in + In [19]: # change coordinates to be like a compass + ....: ax.set_theta_zero_location('N') + ....: ax.set_theta_direction(-1) + ....: ax.set_rmax(90) + ....: + +This is a polar plot of hourly solar zenith and azimuth. The figure-8 patterns +are called `analemmas `_ 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. From 9f2a117b59baef86fd51c859f9d248f10482eb6b Mon Sep 17 00:00:00 2001 From: Kevin Anderson Date: Fri, 3 Jan 2020 21:56:16 -0700 Subject: [PATCH 02/13] add explanation text and cartesian diagram --- docs/sphinx/source/solarposition.rst | 90 +++++++++++++++++++++++++++- 1 file changed, 87 insertions(+), 3 deletions(-) diff --git a/docs/sphinx/source/solarposition.rst b/docs/sphinx/source/solarposition.rst index bc845512ae..f3c2c4345e 100644 --- a/docs/sphinx/source/solarposition.rst +++ b/docs/sphinx/source/solarposition.rst @@ -4,8 +4,14 @@ Solar Position ============== This section shows basic usage of pvlib's solar position calculations with -:py:meth:`pvlib.solarposition.get_solarposition`. The example shown here will -generate a sunpath diagram that shows how solar position varies across a year. +:py:meth:`pvlib.solarposition.get_solarposition`. The examples shown here will +generate sunpath diagrams that shows how solar position varies across a year. + +Polar Plot +---------- + +Below is an example plot of solar position in +`polar coordinates `_. .. ipython:: @@ -56,7 +62,7 @@ generate a sunpath diagram that shows how solar position varies across a year. ....: ax.figure.legend(loc='upper left') ....: - @savefig sunpath-diagram.png width=6in + @savefig sunpath-diagram-polar.png width=6in In [19]: # change coordinates to be like a compass ....: ax.set_theta_zero_location('N') ....: ax.set_theta_direction(-1) @@ -68,3 +74,81 @@ are called `analemmas `_ 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, you can see 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 tree line bordering the western edge +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: + +.. ipython:: + + In [1]: from pvlib import solarposition + ...: import pandas as pd + ...: import numpy as np + ...: import matplotlib.pyplot as plt + ...: + + In [2]: 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) + ...: + + In [3]: solpos = solarposition.get_solarposition(times, lat, lon) + ...: # remove nighttime + ...: solpos = solpos.loc[solpos['apparent_elevation'] > 0, :] + ...: + + In [4]: fig, ax = plt.subplots() + ...: points = ax.scatter(solpos.azimuth, solpos.apparent_elevation, s=2, + ...: c=solpos.index.dayofyear) + ...: fig.colorbar(points) + ...: + Out[4]: + + In [5]: 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)) + ...: + ...: + + In [6]: 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) + ...: + ...: + + @savefig sunpath-diagram-cartesian.png width=6in + In [7]: ax.figure.legend(loc='upper left') + ...: ax.set_xlabel('Solar Azimuth (degrees)') + ...: ax.set_ylabel('Solar Elevation (degrees)') + ...: From 46f7cd793e748bf67f9878797f18a51a2cac1abb Mon Sep 17 00:00:00 2001 From: Kevin Anderson Date: Wed, 8 Jan 2020 21:56:54 -0700 Subject: [PATCH 03/13] Delete solarposition.rst --- docs/sphinx/source/solarposition.rst | 154 --------------------------- 1 file changed, 154 deletions(-) delete mode 100644 docs/sphinx/source/solarposition.rst diff --git a/docs/sphinx/source/solarposition.rst b/docs/sphinx/source/solarposition.rst deleted file mode 100644 index f3c2c4345e..0000000000 --- a/docs/sphinx/source/solarposition.rst +++ /dev/null @@ -1,154 +0,0 @@ -.. _solarposition: - -Solar Position -============== - -This section 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 how solar position varies across a year. - -Polar Plot ----------- - -Below is an example plot of solar position in -`polar coordinates `_. - -.. ipython:: - - In [1]: from pvlib import solarposition - ...: import pandas as pd - ...: import numpy as np - ...: import matplotlib.pyplot as plt - ...: - - In [5]: tz = 'Asia/Calcutta' - ...: lat, lon = 28.6, 77.2 - ...: - - In [8]: times = pd.date_range('2019-01-01 00:00:00', '2020-01-01', closed='left', - ...: freq='H', tz=tz) - ...: - - In [9]: solpos = solarposition.get_solarposition(times, lat, lon) - ...: # remove nighttime - ...: solpos = solpos.loc[solpos['apparent_elevation'] > 0, :] - - In [13]: ax = plt.subplot(1, 1, 1, projection='polar') - - In [14]: # 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) - ....: - - In [16]: # 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)) - ....: - ....: - - In [17]: # 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') - ....: - - @savefig sunpath-diagram-polar.png width=6in - In [19]: # change coordinates to be like a compass - ....: ax.set_theta_zero_location('N') - ....: ax.set_theta_direction(-1) - ....: ax.set_rmax(90) - ....: - -This is a polar plot of hourly solar zenith and azimuth. The figure-8 patterns -are called `analemmas `_ 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, you can see 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 tree line bordering the western edge -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: - -.. ipython:: - - In [1]: from pvlib import solarposition - ...: import pandas as pd - ...: import numpy as np - ...: import matplotlib.pyplot as plt - ...: - - In [2]: 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) - ...: - - In [3]: solpos = solarposition.get_solarposition(times, lat, lon) - ...: # remove nighttime - ...: solpos = solpos.loc[solpos['apparent_elevation'] > 0, :] - ...: - - In [4]: fig, ax = plt.subplots() - ...: points = ax.scatter(solpos.azimuth, solpos.apparent_elevation, s=2, - ...: c=solpos.index.dayofyear) - ...: fig.colorbar(points) - ...: - Out[4]: - - In [5]: 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)) - ...: - ...: - - In [6]: 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) - ...: - ...: - - @savefig sunpath-diagram-cartesian.png width=6in - In [7]: ax.figure.legend(loc='upper left') - ...: ax.set_xlabel('Solar Azimuth (degrees)') - ...: ax.set_ylabel('Solar Elevation (degrees)') - ...: From 4fdc1293edd0f79ea17af35b313310e6aca8b7f2 Mon Sep 17 00:00:00 2001 From: Kevin Anderson Date: Wed, 8 Jan 2020 21:57:32 -0700 Subject: [PATCH 04/13] Add sphinx-gallery and configuration --- docs/examples/README.rst | 4 ++++ docs/sphinx/source/conf.py | 17 ++++++++++++++++- docs/sphinx/source/index.rst | 2 +- setup.py | 3 ++- 4 files changed, 23 insertions(+), 3 deletions(-) create mode 100644 docs/examples/README.rst diff --git a/docs/examples/README.rst b/docs/examples/README.rst new file mode 100644 index 0000000000..4f0e8ab71c --- /dev/null +++ b/docs/examples/README.rst @@ -0,0 +1,4 @@ +Example Gallery +=============== + +This gallery shows examples of pvlib functionality. Community contributions are welcome! \ No newline at end of file diff --git a/docs/sphinx/source/conf.py b/docs/sphinx/source/conf.py index d4de03fa5f..5c7f1e86b4 100644 --- a/docs/sphinx/source/conf.py +++ b/docs/sphinx/source/conf.py @@ -55,7 +55,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 @@ -324,3 +325,17 @@ 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 +import warnings +warnings.filterwarnings("ignore", category=UserWarning, + message='Matplotlib is currently using agg, which is a' + ' non-GUI backend, so cannot show the figure.') diff --git a/docs/sphinx/source/index.rst b/docs/sphinx/source/index.rst index d9b2f0331a..5816d13890 100644 --- a/docs/sphinx/source/index.rst +++ b/docs/sphinx/source/index.rst @@ -87,13 +87,13 @@ Contents pvsystem modelchain timetimezones - solarposition clearsky forecasts api comparison_pvlib_matlab variables_style_rules singlediode + auto_examples/index Indices and tables diff --git a/setup.py b/setup.py index 35543bf7e0..b52a8ce731 100755 --- a/setup.py +++ b/setup.py @@ -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(), []))) From 2b6a9f3330653ed23ef1eaaa05b322bae990eff1 Mon Sep 17 00:00:00 2001 From: Kevin Anderson Date: Wed, 8 Jan 2020 21:57:42 -0700 Subject: [PATCH 05/13] add sunpath example --- docs/examples/plot_sunpath_diagrams.py | 137 +++++++++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100644 docs/examples/plot_sunpath_diagrams.py diff --git a/docs/examples/plot_sunpath_diagrams.py b/docs/examples/plot_sunpath_diagrams.py new file mode 100644 index 0000000000..ed1393d995 --- /dev/null +++ b/docs/examples/plot_sunpath_diagrams.py @@ -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 `_. + +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 `_ 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, you can see 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 tree line bordering the western edge +# 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() \ No newline at end of file From f04fe0ba383232963f6d9e504adec2a6241008fb Mon Sep 17 00:00:00 2001 From: Kevin Anderson Date: Wed, 8 Jan 2020 21:57:54 -0700 Subject: [PATCH 06/13] add singleaxis tracker example --- docs/examples/plot_single_axis_tracking.py | 78 ++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 docs/examples/plot_single_axis_tracking.py diff --git a/docs/examples/plot_single_axis_tracking.py b/docs/examples/plot_single_axis_tracking.py new file mode 100644 index 0000000000..87fe0c3b68 --- /dev/null +++ b/docs/examples/plot_single_axis_tracking.py @@ -0,0 +1,78 @@ +""" +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 numpy as np +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() \ No newline at end of file From b1d8015bd9ad8084acfb4266d36eb348bc0e500a Mon Sep 17 00:00:00 2001 From: Kevin Anderson Date: Thu, 9 Jan 2020 11:56:04 -0700 Subject: [PATCH 07/13] linting fixes --- docs/examples/plot_single_axis_tracking.py | 27 ++++++++-------- docs/examples/plot_sunpath_diagrams.py | 36 +++++++++++----------- 2 files changed, 31 insertions(+), 32 deletions(-) diff --git a/docs/examples/plot_single_axis_tracking.py b/docs/examples/plot_single_axis_tracking.py index 87fe0c3b68..75ea3ba1ca 100644 --- a/docs/examples/plot_single_axis_tracking.py +++ b/docs/examples/plot_single_axis_tracking.py @@ -11,18 +11,17 @@ # 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. -# +# solar position is always the first step. +# # True-tracking # ------------- # -# The basic tracking algorithm is called "true-tracking". It orients the panels +# 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. +# presented towards incoming beam irradiance. from pvlib import solarposition, tracking import pandas as pd -import numpy as np import matplotlib.pyplot as plt tz = 'US/Eastern' @@ -38,8 +37,8 @@ axis_tilt=0, axis_azimuth=180, max_angle=90, - backtrack=False, # for true-tracking - gcr=0.5) # irrelevant for true-tracking + 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') @@ -50,12 +49,12 @@ # 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. +# 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() @@ -75,4 +74,4 @@ ax=ax) plt.legend() -plt.show() \ No newline at end of file +plt.show() diff --git a/docs/examples/plot_sunpath_diagrams.py b/docs/examples/plot_sunpath_diagrams.py index ed1393d995..2b36b7e6b4 100644 --- a/docs/examples/plot_sunpath_diagrams.py +++ b/docs/examples/plot_sunpath_diagrams.py @@ -9,11 +9,11 @@ # 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 +# Below is an example plot of solar position in # `polar coordinates `_. from pvlib import solarposition @@ -62,30 +62,30 @@ plt.show() #%% -# This is a polar plot of hourly solar zenith and azimuth. The figure-8 patterns -# are called `analemmas `_ 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. -# +# This is a polar plot of hourly solar zenith and azimuth. The figure-8 +# patterns are called `analemmas `_ 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, you can see that +# 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. -# +# 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 tree line bordering the western edge +# 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 @@ -93,7 +93,7 @@ #%% # PVSyst Plot # ----------- -# +# # PVSyst users will be more familiar with sunpath diagrams in Cartesian # coordinates: @@ -121,7 +121,7 @@ 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)) + 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) @@ -134,4 +134,4 @@ ax.set_xlabel('Solar Azimuth (degrees)') ax.set_ylabel('Solar Elevation (degrees)') -plt.show() \ No newline at end of file +plt.show() From 92ead4e541622028b94efc7f06e44d597a32840f Mon Sep 17 00:00:00 2001 From: Kevin Anderson Date: Thu, 9 Jan 2020 11:58:08 -0700 Subject: [PATCH 08/13] rename "Intro Examples" to "Intro Tutorial", move "Example Gallery" up in the toctree --- docs/sphinx/source/index.rst | 4 ++-- docs/sphinx/source/{introexamples.rst => introtutorial.rst} | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) rename docs/sphinx/source/{introexamples.rst => introtutorial.rst} (99%) diff --git a/docs/sphinx/source/index.rst b/docs/sphinx/source/index.rst index 5816d13890..06b7578a06 100644 --- a/docs/sphinx/source/index.rst +++ b/docs/sphinx/source/index.rst @@ -80,7 +80,8 @@ Contents :maxdepth: 1 package_overview - introexamples + introtutorial + auto_examples/index whatsnew installation contributing @@ -93,7 +94,6 @@ Contents comparison_pvlib_matlab variables_style_rules singlediode - auto_examples/index Indices and tables diff --git a/docs/sphinx/source/introexamples.rst b/docs/sphinx/source/introtutorial.rst similarity index 99% rename from docs/sphinx/source/introexamples.rst rename to docs/sphinx/source/introtutorial.rst index 184346e7ba..5d95af4477 100644 --- a/docs/sphinx/source/introexamples.rst +++ b/docs/sphinx/source/introtutorial.rst @@ -1,6 +1,6 @@ .. _introexamples: -Intro Examples +Intro Tutorial ============== This page contains introductory examples of pvlib python usage. From 3a2f0fda413c397a1ddeab800c0a7eda2306fa0f Mon Sep 17 00:00:00 2001 From: Kevin Anderson Date: Thu, 9 Jan 2020 11:59:13 -0700 Subject: [PATCH 09/13] Update introtutorial.rst --- docs/sphinx/source/introtutorial.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sphinx/source/introtutorial.rst b/docs/sphinx/source/introtutorial.rst index 5d95af4477..2ad8c967c4 100644 --- a/docs/sphinx/source/introtutorial.rst +++ b/docs/sphinx/source/introtutorial.rst @@ -1,4 +1,4 @@ -.. _introexamples: +.. _introtutorial: Intro Tutorial ============== From 4e13906a67fee92200e84c2e15ebbf46e8c4c3a2 Mon Sep 17 00:00:00 2001 From: Kevin Anderson Date: Thu, 9 Jan 2020 12:01:46 -0700 Subject: [PATCH 10/13] more linting fixes --- docs/sphinx/source/conf.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/sphinx/source/conf.py b/docs/sphinx/source/conf.py index 5c7f1e86b4..9737547533 100644 --- a/docs/sphinx/source/conf.py +++ b/docs/sphinx/source/conf.py @@ -328,10 +328,10 @@ def setup(app): # settings for sphinx-gallery sphinx_gallery_conf = { - 'examples_dirs': ['../../examples'], # location of gallery scripts - 'gallery_dirs': ['auto_examples'], # location of generated output + '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', + # 'filename_pattern': '*.py', } # supress warnings in gallery output # https://sphinx-gallery.github.io/stable/configuration.html From 937166ae9f3ae5338a93581c0f0509417e45d4f3 Mon Sep 17 00:00:00 2001 From: Kevin Anderson Date: Thu, 9 Jan 2020 12:02:28 -0700 Subject: [PATCH 11/13] last linting fix, probably --- docs/sphinx/source/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sphinx/source/conf.py b/docs/sphinx/source/conf.py index 9737547533..7e50edd825 100644 --- a/docs/sphinx/source/conf.py +++ b/docs/sphinx/source/conf.py @@ -331,7 +331,7 @@ def setup(app): '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', + # 'filename_pattern': '*.py', } # supress warnings in gallery output # https://sphinx-gallery.github.io/stable/configuration.html From beabb4b3b889ed13c731ebf9ead5baab8f969330 Mon Sep 17 00:00:00 2001 From: Kevin Anderson Date: Thu, 9 Jan 2020 12:15:21 -0700 Subject: [PATCH 12/13] Mention example gallery in whatsnew --- docs/sphinx/source/whatsnew/v0.7.1.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/sphinx/source/whatsnew/v0.7.1.rst b/docs/sphinx/source/whatsnew/v0.7.1.rst index 53dace9cfe..f4d47a714a 100644 --- a/docs/sphinx/source/whatsnew/v0.7.1.rst +++ b/docs/sphinx/source/whatsnew/v0.7.1.rst @@ -27,6 +27,7 @@ Testing Documentation ~~~~~~~~~~~~~ +* Created an Example Gallery. (:pull:`846`) * Updated list of allowed years for `iotools.get_psm3`. Contributors From b60e06b385cfdd80dab061b9a033ae5024606e71 Mon Sep 17 00:00:00 2001 From: Kevin Anderson Date: Thu, 9 Jan 2020 20:12:33 -0700 Subject: [PATCH 13/13] update introtutorial link in package_overview.rst; move warnings import to top of conf.py --- docs/sphinx/source/conf.py | 4 +++- docs/sphinx/source/package_overview.rst | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/sphinx/source/conf.py b/docs/sphinx/source/conf.py index 7e50edd825..524a77a048 100644 --- a/docs/sphinx/source/conf.py +++ b/docs/sphinx/source/conf.py @@ -18,6 +18,9 @@ # Mock modules so RTD works from unittest.mock import MagicMock +# for warning suppression +import warnings + class Mock(MagicMock): @classmethod @@ -335,7 +338,6 @@ def setup(app): } # supress warnings in gallery output # https://sphinx-gallery.github.io/stable/configuration.html -import warnings warnings.filterwarnings("ignore", category=UserWarning, message='Matplotlib is currently using agg, which is a' ' non-GUI backend, so cannot show the figure.') diff --git a/docs/sphinx/source/package_overview.rst b/docs/sphinx/source/package_overview.rst index a5cf1eb818..5bbbece5a5 100644 --- a/docs/sphinx/source/package_overview.rst +++ b/docs/sphinx/source/package_overview.rst @@ -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.