diff --git a/docs/examples/adr-pvarray/plot_simulate_system.py b/docs/examples/adr-pvarray/plot_simulate_system.py index b0abede934..315492f2ba 100644 --- a/docs/examples/adr-pvarray/plot_simulate_system.py +++ b/docs/examples/adr-pvarray/plot_simulate_system.py @@ -12,12 +12,11 @@ Author: Anton Driesse """ -import os import pandas as pd import matplotlib.pyplot as plt import pvlib -from pvlib import iotools, location +from pvlib import iotools, location, tools from pvlib.irradiance import get_total_irradiance from pvlib.pvarray import pvefficiency_adr @@ -26,10 +25,9 @@ # Read a TMY3 file containing weather data and select needed columns # -PVLIB_DIR = pvlib.__path__[0] -DATA_FILE = os.path.join(PVLIB_DIR, 'data', '723170TYA.CSV') +tmy3_filepath = tools.get_example_dataset_path('723170TYA.CSV') -tmy, metadata = iotools.read_tmy3(DATA_FILE, coerce_year=1990, +tmy, metadata = iotools.read_tmy3(tmy3_filepath, coerce_year=1990, map_variables=True) df = pd.DataFrame({'ghi': tmy['ghi'], 'dhi': tmy['dhi'], 'dni': tmy['dni'], diff --git a/docs/examples/irradiance-decomposition/plot_diffuse_fraction.py b/docs/examples/irradiance-decomposition/plot_diffuse_fraction.py index 30d1385f87..03d2966cf8 100644 --- a/docs/examples/irradiance-decomposition/plot_diffuse_fraction.py +++ b/docs/examples/irradiance-decomposition/plot_diffuse_fraction.py @@ -14,20 +14,19 @@ # GHI into the diffuse and direct components. The separate components are # needed to estimate the total irradiance on a tilted surface. -import pathlib from matplotlib import pyplot as plt import pandas as pd from pvlib.iotools import read_tmy3 from pvlib.solarposition import get_solarposition from pvlib import irradiance -import pvlib +from pvlib import tools # For this example we use the Greensboro, North Carolina, TMY3 file which is # in the pvlib data directory. TMY3 are made from the median months from years # of data measured from 1990 to 2010. Therefore we change the timestamps to a # common year, 1990. -DATA_DIR = pathlib.Path(pvlib.__file__).parent / 'data' -greensboro, metadata = read_tmy3(DATA_DIR / '723170TYA.CSV', coerce_year=1990, +tmy3_filepath = tools.get_example_dataset_path('723170TYA.CSV') +greensboro, metadata = read_tmy3(tmy3_filepath, coerce_year=1990, map_variables=True) # Many of the diffuse fraction estimation methods require the "true" zenith, so diff --git a/docs/examples/irradiance-transposition/plot_seasonal_tilt.py b/docs/examples/irradiance-transposition/plot_seasonal_tilt.py index afe610f6d2..a46e81619e 100644 --- a/docs/examples/irradiance-transposition/plot_seasonal_tilt.py +++ b/docs/examples/irradiance-transposition/plot_seasonal_tilt.py @@ -12,11 +12,9 @@ # to use a custom Mount class to use the Seasonal Tilt strategy # with :py:class:`~pvlib.modelchain.ModelChain`. -import pvlib -from pvlib import pvsystem, location, modelchain, iotools +from pvlib import pvsystem, location, modelchain, iotools, tools from pvlib.temperature import TEMPERATURE_MODEL_PARAMETERS import pandas as pd -import pathlib import matplotlib.pyplot as plt from dataclasses import dataclass @@ -43,9 +41,10 @@ def get_orientation(self, solar_zenith, solar_azimuth): # First let's grab some weather data and make sure our mount produces tilts # like we expect: -DATA_DIR = pathlib.Path(pvlib.__file__).parent / 'data' -tmy, metadata = iotools.read_tmy3(DATA_DIR / '723170TYA.CSV', coerce_year=1990, +tmy3_filepath = tools.get_example_dataset_path('723170TYA.CSV') +tmy, metadata = iotools.read_tmy3(tmy3_filepath, coerce_year=1990, map_variables=True) + # shift from TMY3 right-labeled index to left-labeled index: tmy.index = tmy.index - pd.Timedelta(hours=1) weather = pd.DataFrame({ diff --git a/docs/examples/irradiance-transposition/plot_transposition_gain.py b/docs/examples/irradiance-transposition/plot_transposition_gain.py index 4ce558b47c..047eac0e11 100644 --- a/docs/examples/irradiance-transposition/plot_transposition_gain.py +++ b/docs/examples/irradiance-transposition/plot_transposition_gain.py @@ -19,21 +19,20 @@ # insolation is calculated for each strategy to show how orientation affects # seasonal irradiance collection. -import pvlib from pvlib import location from pvlib import irradiance from pvlib import tracking +from pvlib import tools from pvlib.iotools import read_tmy3 import pandas as pd from matplotlib import pyplot as plt -import pathlib -# get full path to the data directory -DATA_DIR = pathlib.Path(pvlib.__file__).parent / 'data' +# get full path to the example file +tmy3_filepath = tools.get_example_dataset_path('723170TYA.CSV') # get TMY3 dataset -tmy, metadata = read_tmy3(DATA_DIR / '723170TYA.CSV', coerce_year=1990, - map_variables=True) +tmy, metadata = read_tmy3(tmy3_filepath, coerce_year=1990, map_variables=True) + # TMY3 datasets are right-labeled (AKA "end of interval") which means the last # interval of Dec 31, 23:00 to Jan 1 00:00 is labeled Jan 1 00:00. When rolling # up hourly irradiance to monthly insolation, a spurious January value is diff --git a/docs/examples/soiling/plot_fig3A_hsu_soiling_example.py b/docs/examples/soiling/plot_fig3A_hsu_soiling_example.py index 9103fa0207..ddd499321b 100644 --- a/docs/examples/soiling/plot_fig3A_hsu_soiling_example.py +++ b/docs/examples/soiling/plot_fig3A_hsu_soiling_example.py @@ -21,18 +21,19 @@ # PM2.5 and PM10 data come from the EPA. First, let's read in the # weather data and run the HSU soiling model: -import pathlib from matplotlib import pyplot as plt from pvlib import soiling import pvlib import pandas as pd -# get full path to the data directory -DATA_DIR = pathlib.Path(pvlib.__file__).parent / 'data' +# get full path to the example file +soiling_hsu_filepath = \ + pvlib.tools.get_example_dataset_path('soiling_hsu_example_inputs.csv') # read rainfall, PM2.5, and PM10 data from file -imperial_county = pd.read_csv(DATA_DIR / 'soiling_hsu_example_inputs.csv', - index_col=0, parse_dates=True) +imperial_county = pd.read_csv(soiling_hsu_filepath, index_col=0, + parse_dates=True) + rainfall = imperial_county['rain'] depo_veloc = {'2_5': 0.0009, '10': 0.004} # default values from [1] (m/s) rain_accum_period = pd.Timedelta('1h') # default diff --git a/docs/examples/soiling/plot_greensboro_kimber_soiling.py b/docs/examples/soiling/plot_greensboro_kimber_soiling.py index 6565679f6d..6d8a2c8ca4 100644 --- a/docs/examples/soiling/plot_greensboro_kimber_soiling.py +++ b/docs/examples/soiling/plot_greensboro_kimber_soiling.py @@ -30,17 +30,16 @@ # step. from datetime import datetime -import pathlib from matplotlib import pyplot as plt from pvlib.iotools import read_tmy3 from pvlib.soiling import kimber -import pvlib +from pvlib.tools import get_example_dataset_path -# get full path to the data directory -DATA_DIR = pathlib.Path(pvlib.__file__).parent / 'data' +# get full path to the dataset file +tmy_filepath = get_example_dataset_path('723170TYA.CSV') # get TMY3 data with rain -greensboro, _ = read_tmy3(DATA_DIR / '723170TYA.CSV', coerce_year=1990, +greensboro, _ = read_tmy3(tmy_filepath, coerce_year=1990, map_variables=True) # get the rain data greensboro_rain = greensboro['Lprecip depth (mm)'] @@ -65,3 +64,5 @@ plt.tight_layout() plt.show() + +# %% diff --git a/docs/sphinx/source/conf.py b/docs/sphinx/source/conf.py index cadadcd963..fc4b6ba81c 100644 --- a/docs/sphinx/source/conf.py +++ b/docs/sphinx/source/conf.py @@ -366,6 +366,11 @@ def setup(app): # Modules for which function/class level galleries are created. In # this case only pvlib, could include others though. must be tuple of str 'doc_module': ('pvlib',), + + # objects to exclude from implicit backreferences + # https://sphinx-gallery.github.io/stable/configuration.html + # Section #add-mini-galleries-for-api-documentation + 'exclude_implicit_doc': {r'pvlib\.tools\.get_example_dataset_path'}, } # supress warnings in gallery output # https://sphinx-gallery.github.io/stable/configuration.html diff --git a/docs/sphinx/source/reference/iotools.rst b/docs/sphinx/source/reference/iotools.rst index c902e3181a..5b757a1a5f 100644 --- a/docs/sphinx/source/reference/iotools.rst +++ b/docs/sphinx/source/reference/iotools.rst @@ -51,3 +51,10 @@ in some files. location.Location.from_tmy location.Location.from_epw + +Functions for locating the example data files included in pvlib. + +.. autosummary:: + :toctree: generated/ + + tools.get_example_dataset_path diff --git a/docs/sphinx/source/whatsnew/v0.10.0.rst b/docs/sphinx/source/whatsnew/v0.10.0.rst index e7816020bd..4a55e61428 100644 --- a/docs/sphinx/source/whatsnew/v0.10.0.rst +++ b/docs/sphinx/source/whatsnew/v0.10.0.rst @@ -72,6 +72,8 @@ Deprecations Enhancements ~~~~~~~~~~~~ +* Added `map_variables` parameter to :py:func:`pvlib.iotools.read_srml` + and :py:func:`pvlib.iotools.read_srml_month_from_solardat` (:pull:`1773`) * Added two new irradiance decomposition models: :py:func:`pvlib.irradiance.orgill_hollands` (:pull:`1730`) and :py:func:`pvlib.irradiance.louche` (:pull:`1705`). * The return values of :py:func:`pvlib.pvsystem.calcparams_desoto`, diff --git a/docs/sphinx/source/whatsnew/v0.10.2.rst b/docs/sphinx/source/whatsnew/v0.10.2.rst index dacfe27f53..6801232616 100644 --- a/docs/sphinx/source/whatsnew/v0.10.2.rst +++ b/docs/sphinx/source/whatsnew/v0.10.2.rst @@ -17,7 +17,9 @@ Enhancements (:pull:`1800`) * Added option to infer threshold values for :py:func:`pvlib.clearsky.detect_clearsky` (:issue:`1808`, :pull:`1784`) - +* Add :py:func:`pvlib.tools.locate_example_dataset` to get example and test + files under `pvlib/data` path. + (:issue:`924`, :pull:`1763`) Bug fixes ~~~~~~~~~ @@ -43,3 +45,4 @@ Contributors * Adam R. Jensen (:ghuser:`AdamRJensen`) * Abigail Jones (:ghuser:`ajonesr`) * Taos Transue (:ghuser:`reepoi`) +* Echedey Luis (:ghuser:`echedey-ls`) diff --git a/pvlib/tests/test_tools.py b/pvlib/tests/test_tools.py index 583141a726..1aba05d317 100644 --- a/pvlib/tests/test_tools.py +++ b/pvlib/tests/test_tools.py @@ -1,8 +1,10 @@ import pytest +import pvlib from pvlib import tools import numpy as np import pandas as pd +import pathlib @pytest.mark.parametrize('keys, input_dict, expected', [ @@ -120,3 +122,22 @@ def test_get_pandas_index(args, args_idx): assert index is None else: pd.testing.assert_index_equal(args[args_idx].index, index) + + +def test_get_example_dataset_path_passes(): + expected_dataset = '723170TYA.CSV' + assert pathlib.Path(pvlib.__path__[0], 'data', + expected_dataset).exists() + assert tools.get_example_dataset_path(pathlib.Path(expected_dataset)) \ + .name == expected_dataset + assert tools.get_example_dataset_path(expected_dataset).exists() + + +def test_get_example_dataset_path_fails_on_not_found(): + error_prompt = "Dataset has not been found in pvlib at .*. " \ + "Please check dataset name." + nonexistent_file = "_Texto_cualquiera.-formato-" + assert not pathlib.Path(pvlib.__path__[0], 'data', + nonexistent_file).exists() + with pytest.raises(ValueError, match=error_prompt): + tools.get_example_dataset_path(nonexistent_file) diff --git a/pvlib/tools.py b/pvlib/tools.py index fe1b79a5f1..c28595697e 100644 --- a/pvlib/tools.py +++ b/pvlib/tools.py @@ -2,11 +2,14 @@ Collection of functions used in pvlib_python """ +import pvlib + import datetime as dt import numpy as np import pandas as pd import pytz import warnings +import pathlib def cosd(angle): @@ -494,3 +497,30 @@ def get_pandas_index(*args): (a.index for a in args if isinstance(a, (pd.DataFrame, pd.Series))), None ) + + +def get_example_dataset_path(dataset): + """ + Return a filepath to a dataset bundled with PVLIB with name `dataset`. + This utility is intended to be used in examples: + + .. ipython:: python + + import pvlib + pvlib.tools.get_example_dataset_path('surfrad-slv16001.dat') + + Parameters + ---------- + dataset : str or PurePath + Name of dataset file. + + Returns + ------- + path : PurePath + Path pointing to an example dataset file in PVLIB. + """ + dataset = pathlib.Path(pvlib.__path__[0], 'data', dataset) + if not dataset.exists(): + raise ValueError(f"Dataset has not been found in pvlib at {dataset}. " + "Please check dataset name.") + return dataset