From 41a66fa0e1e37c1088de624583526ea24cb0a4bf Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Tue, 24 Sep 2024 22:40:36 -0700 Subject: [PATCH 01/28] Update conf.py --- docs/conf.py | 38 +++++++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index c5728ccae..a92fc0487 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -36,11 +36,22 @@ # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. -extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode', 'sphinx_rtd_theme', 'sphinx.ext.napoleon'] +#extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode', 'sphinx_rtd_theme', 'sphinx.ext.napoleon'] +extensions = [ + "sphinx.ext.autodoc", + "sphinx.ext.autosummary", + "sphinx.ext.napoleon", + "sphinx.ext.viewcode", + "sphinx_autosummary_accessors", + "sphinx_copybutton", + "sphinx_rtd_theme", + "nbsphinx", + "sphinx_design", +] # autosummary and autodoc configurations -# autosummary_generate = True -""" +autosummary_generate = True + autodoc_member_order = "bysource" autodoc_default_options = { "members": True, @@ -48,7 +59,6 @@ "private-members": True, } autodoc_typehints = "none" -""" # Napoleon configurations napoleon_google_docstring = False @@ -57,9 +67,13 @@ napoleon_use_rtype = False napoleon_preprocess_types = True +# sphinx-copybutton configurations +copybutton_prompt_text = r">>> |\.\.\. |\$ |In \[\d*\]: | {2,5}\.\.\.: | {5,8}: " +copybutton_prompt_is_regexp = True + # Add any paths that contain templates here, relative to this directory. -# templates_path = ['_templates', sphinx_autosummary_accessors.templates_path] -templates_path = ['_templates'] +templates_path = ["_templates", sphinx_autosummary_accessors.templates_path] +# templates_path = ['_templates'] # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: @@ -70,6 +84,11 @@ # The master toctree document. master_doc = "index" +# General information about the project. +project = "PCMDI Metrics Package (PMP)" +copyright = "2024, PMP Developers" +author = "PMP Developers" + # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. # @@ -80,7 +99,12 @@ # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path. -exclude_patterns = [] +exclude_patterns = [ + "_build", + "Thumbs.db", + ".DS_Store", + "demos/1-25-23-cwss-seminar/xsearch-xcdat-example.ipynb", +] # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' From adf7510808531e9a7eaea5c254670efd1416f494 Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Tue, 24 Sep 2024 22:51:57 -0700 Subject: [PATCH 02/28] Update and rename utils.rst to api.rst --- docs/api.rst | 22 ++++++++++++++++++++++ docs/utils.rst | 9 --------- 2 files changed, 22 insertions(+), 9 deletions(-) create mode 100644 docs/api.rst delete mode 100644 docs/utils.rst diff --git a/docs/api.rst b/docs/api.rst new file mode 100644 index 000000000..b59801096 --- /dev/null +++ b/docs/api.rst @@ -0,0 +1,22 @@ +API Reference +============= + +API Functions for Developpers +----------------------------- + +Below is a list of top-level API functions that are available in ``pcmdi_metrics``. + +.. autosummary:: + :toctree: generated/ + + check_daily_time_axis + check_monthly_time_axis + create_land_sea_mask + apply_landmask + apply_oceanmask + regrid + +.. automodule:: pcmdi_metrics.utils + :members: check_daily_time_axis, check_monthly_time_axis, create_land_sea_mask, apply_landmask, apply_oceanmask, regrid + :undoc-members: + :show-inheritance: diff --git a/docs/utils.rst b/docs/utils.rst deleted file mode 100644 index 45749ab04..000000000 --- a/docs/utils.rst +++ /dev/null @@ -1,9 +0,0 @@ -***** -Utils -***** - - -.. automodule:: pcmdi_metrics.utils - :members: check_daily_time_axis, check_monthly_time_axis, create_land_sea_mask, apply_landmask, apply_oceanmask, regrid - :undoc-members: - :show-inheritance: From 61ff11400b4d7f7c7cd9ed8fba764c4d8e9be1d3 Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Tue, 24 Sep 2024 22:54:04 -0700 Subject: [PATCH 03/28] Update resources.rst --- docs/resources.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/resources.rst b/docs/resources.rst index e25fa645e..331e1119d 100644 --- a/docs/resources.rst +++ b/docs/resources.rst @@ -7,5 +7,5 @@ Resources .. toctree:: :maxdepth: 1 - utils - resources_legacy \ No newline at end of file + api + resources_legacy From b3f3ca4521e5d5ba116106afc25e16a4bb4bca27 Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Tue, 24 Sep 2024 22:55:20 -0700 Subject: [PATCH 04/28] Update dev.yml --- conda-env/dev.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/conda-env/dev.yml b/conda-env/dev.yml index 98ed112be..8abeceaf7 100644 --- a/conda-env/dev.yml +++ b/conda-env/dev.yml @@ -45,11 +45,13 @@ dependencies: # Documentation # ================== - sphinx + - sphinx-autosummary-accessors - sphinx-book-theme - sphinx-copybutton - sphinx_rtd_theme - nbsphinx - pandoc + - sphinx-design - ipython # Required for nbsphinx syntax highlighting prefix: /opt/miniconda3/envs/pmcdi_metrics_dev From 916215857fc36d418eb5bd18b5a6954457e4d80b Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Tue, 24 Sep 2024 22:57:01 -0700 Subject: [PATCH 05/28] Update conf.py --- docs/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index a92fc0487..63d33efa0 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -13,7 +13,7 @@ import os sys.path.insert(0, os.path.abspath('../pcmdi_metrics/utils')) -# import sphinx_autosummary_accessors +import sphinx_autosummary_accessors # -- Project information ----------------------------------------------------- From 368d278e60428328a491343d21df096ac9f7217f Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Tue, 24 Sep 2024 23:02:30 -0700 Subject: [PATCH 06/28] Update conf.py --- docs/conf.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 63d33efa0..264ebfe8c 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -14,12 +14,17 @@ sys.path.insert(0, os.path.abspath('../pcmdi_metrics/utils')) import sphinx_autosummary_accessors +import yaml +from sphinx.application import Sphinx +from sphinx.util import logging -# -- Project information ----------------------------------------------------- +LOGGER = logging.getLogger("conf") -project = 'PCMDI Metrics Package' -copyright = '2024 PCMDI' -author = 'PCMDI' +# -- Project information ----------------------------------------------------- +# General information about the project. +project = "PCMDI Metrics Package (PMP)" +copyright = "2024, PMP Developers" +author = "PMP Developers" # The version info for the project you're documenting, acts as replacement # for |version| and |release|, also used in various other places throughout @@ -84,11 +89,6 @@ # The master toctree document. master_doc = "index" -# General information about the project. -project = "PCMDI Metrics Package (PMP)" -copyright = "2024, PMP Developers" -author = "PMP Developers" - # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. # From 78259e5a20ff5a698dc08625ebed673bf93e22b8 Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Tue, 24 Sep 2024 23:05:18 -0700 Subject: [PATCH 07/28] Update documentation.yaml --- .github/workflows/documentation.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/documentation.yaml b/.github/workflows/documentation.yaml index 6df2e0719..75ab1cb16 100644 --- a/.github/workflows/documentation.yaml +++ b/.github/workflows/documentation.yaml @@ -10,7 +10,7 @@ jobs: - uses: actions/setup-python@v3 - name: Install dependencies run: | - pip install sphinx sphinx_rtd_theme sphinx_book_theme + pip install sphinx sphinx_rtd_theme sphinx_book_theme sphinx_autosummary_accessors - name: Sphinx build run: | sphinx-build docs _build From 0a2f881744f2915e9f9c2bc172887d45c818aff5 Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Tue, 24 Sep 2024 23:06:49 -0700 Subject: [PATCH 08/28] Update conf.py --- docs/conf.py | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index 264ebfe8c..d2b895ab3 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -14,7 +14,6 @@ sys.path.insert(0, os.path.abspath('../pcmdi_metrics/utils')) import sphinx_autosummary_accessors -import yaml from sphinx.application import Sphinx from sphinx.util import logging From 82f68aeabcf94e68b28040b85c67cacf272066a3 Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Tue, 24 Sep 2024 23:09:52 -0700 Subject: [PATCH 09/28] Update documentation.yaml --- .github/workflows/documentation.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/documentation.yaml b/.github/workflows/documentation.yaml index 75ab1cb16..8ebe84855 100644 --- a/.github/workflows/documentation.yaml +++ b/.github/workflows/documentation.yaml @@ -10,7 +10,7 @@ jobs: - uses: actions/setup-python@v3 - name: Install dependencies run: | - pip install sphinx sphinx_rtd_theme sphinx_book_theme sphinx_autosummary_accessors + pip install sphinx sphinx_rtd_theme sphinx_book_theme sphinx_autosummary_accessors sphinx-copybutton sphinx-design - name: Sphinx build run: | sphinx-build docs _build From 9b75c6493ddb75fe4b2d18af65a9ca889a948684 Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Tue, 24 Sep 2024 23:10:39 -0700 Subject: [PATCH 10/28] Update documentation.yaml --- .github/workflows/documentation.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/documentation.yaml b/.github/workflows/documentation.yaml index 8ebe84855..6f898d2e0 100644 --- a/.github/workflows/documentation.yaml +++ b/.github/workflows/documentation.yaml @@ -10,7 +10,7 @@ jobs: - uses: actions/setup-python@v3 - name: Install dependencies run: | - pip install sphinx sphinx_rtd_theme sphinx_book_theme sphinx_autosummary_accessors sphinx-copybutton sphinx-design + pip install sphinx sphinx_rtd_theme sphinx_book_theme sphinx_autosummary_accessors sphinx-copybutton sphinx-design nbsphinx - name: Sphinx build run: | sphinx-build docs _build From b9353301b5c9f3509fa04307e3a723b8a45dc23d Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Tue, 24 Sep 2024 23:32:16 -0700 Subject: [PATCH 11/28] Update api.rst --- docs/api.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/api.rst b/docs/api.rst index b59801096..99b337d1d 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -4,17 +4,17 @@ API Reference API Functions for Developpers ----------------------------- -Below is a list of top-level API functions that are available in ``pcmdi_metrics``. +Below is a list of some API functions that are available in ``pcmdi_metrics`` for developpers. .. autosummary:: :toctree: generated/ - check_daily_time_axis - check_monthly_time_axis - create_land_sea_mask - apply_landmask - apply_oceanmask - regrid + utils.check_daily_time_axis + utils.check_monthly_time_axis + utils.create_land_sea_mask + utils.apply_landmask + utils.apply_oceanmask + utils.regrid .. automodule:: pcmdi_metrics.utils :members: check_daily_time_axis, check_monthly_time_axis, create_land_sea_mask, apply_landmask, apply_oceanmask, regrid From 92d8eeb1404d461c2062fb63f57b9e4f5d9e14f4 Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Tue, 24 Sep 2024 23:33:39 -0700 Subject: [PATCH 12/28] Update api.rst --- docs/api.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/api.rst b/docs/api.rst index 99b337d1d..d3e5a7516 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -4,17 +4,17 @@ API Reference API Functions for Developpers ----------------------------- -Below is a list of some API functions that are available in ``pcmdi_metrics`` for developpers. +Below is a list of some API functions that are available in ``pcmdi_metrics.utils`` for developpers. .. autosummary:: :toctree: generated/ - utils.check_daily_time_axis - utils.check_monthly_time_axis - utils.create_land_sea_mask - utils.apply_landmask - utils.apply_oceanmask - utils.regrid + check_daily_time_axis + check_monthly_time_axis + create_land_sea_mask + apply_landmask + apply_oceanmask + regrid .. automodule:: pcmdi_metrics.utils :members: check_daily_time_axis, check_monthly_time_axis, create_land_sea_mask, apply_landmask, apply_oceanmask, regrid From de4b4a90f11e5f6523a748828edd39d64d5da032 Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Wed, 25 Sep 2024 10:58:43 -0700 Subject: [PATCH 13/28] remove readthedocs components --- .readthedocs.yaml | 23 ----------------- conda-env/readthedocs.yml | 52 --------------------------------------- 2 files changed, 75 deletions(-) delete mode 100644 .readthedocs.yaml delete mode 100644 conda-env/readthedocs.yml diff --git a/.readthedocs.yaml b/.readthedocs.yaml deleted file mode 100644 index ff9fc2152..000000000 --- a/.readthedocs.yaml +++ /dev/null @@ -1,23 +0,0 @@ -# .readthedocs.yaml -# Read the Docs configuration file -# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details - -# Required -version: 2 - -# Set the OS, Python version and other tools you might need -build: - os: ubuntu-22.04 - tools: - python: "mambaforge-4.10" - -# Build documentation in the "docs/" directory with Sphinx -sphinx: - configuration: docs/conf.py - -# Optionally build your docs in additional formats such as PDF and ePub -formats: - - pdf - -conda: - environment: conda-env/readthedocs.yml diff --git a/conda-env/readthedocs.yml b/conda-env/readthedocs.yml deleted file mode 100644 index 44321a4ff..000000000 --- a/conda-env/readthedocs.yml +++ /dev/null @@ -1,52 +0,0 @@ -name: pcmdi_metrics_rtd -channels: - - conda-forge - - defaults -dependencies: - # ================== - # Base - # ================== - # NOTE: If versions are updated, also `additional_dependencies` list for mypy in `.pre-commit-config.yaml` - - python=3.10.10 - - pip=23.1.2 - - numpy=1.23.5 - - cartopy=0.21.1 - - matplotlib=3.7.1 - - cdms2=3.1.5 - - genutil=8.2.1 - - cdutil=8.2.1 - - cdp=1.7.0 - - eofs=1.4.0 - - seaborn=0.12.2 - - enso_metrics=1.1.1 - - xcdat=0.5.0 - - xmltodict=0.13.0 - - setuptools=67.7.2 - - netcdf4=1.6.3 - - regionmask=0.9.0 - - rasterio=1.3.6 - - shapely=2.0.1 - # ================== - # Testing - # ================== - - pre_commit=3.2.2 - - pytest=7.3.1 - - pytest-cov=4.0.0 - # ================== - # Developer Tools - # ================== - - jupyterlab=3.6.3 - - nb_conda=2.2.1 - - nb_conda_kernels=2.3.1 - # ================== - # Documentation - # ================== - - sphinx=5.3.0 - - sphinx-autosummary-accessors=2022.4.0 - - sphinx-book-theme=1.0.1 - - sphinx-copybutton=0.5.1 - - nbsphinx=0.9.1 - - pandoc=3.1.1 - - ipython=8.11.0 # Required for nbsphinx syntax highlighting - -prefix: /opt/miniconda3/envs/pcmdi_metrics_rtd From 9ff48bf669661fba935f0e448cb7cc96b4897f58 Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Wed, 25 Sep 2024 10:59:02 -0700 Subject: [PATCH 14/28] add import pcmdi_metrics --- docs/conf.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/conf.py b/docs/conf.py index d2b895ab3..786951964 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -19,6 +19,8 @@ LOGGER = logging.getLogger("conf") +import pcmdi_metrics + # -- Project information ----------------------------------------------------- # General information about the project. project = "PCMDI Metrics Package (PMP)" From 1591361c7a365c94a8a4b7f1a46e8ec767b40d85 Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Wed, 25 Sep 2024 11:02:24 -0700 Subject: [PATCH 15/28] run only when PR merged; add steps to get pcmdi_metrics installed so sphinx autosummary can find functions --- .github/workflows/documentation.yaml | 44 ++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/.github/workflows/documentation.yaml b/.github/workflows/documentation.yaml index 6f898d2e0..711f6df3e 100644 --- a/.github/workflows/documentation.yaml +++ b/.github/workflows/documentation.yaml @@ -1,5 +1,5 @@ name: Docs -on: [push, pull_request, workflow_dispatch] +on: [pull_request, workflow_dispatch] permissions: contents: write jobs: @@ -8,9 +8,47 @@ jobs: steps: - uses: actions/checkout@v3 - uses: actions/setup-python@v3 - - name: Install dependencies + + - name: Set up Conda Environment + uses: conda-incubator/setup-miniconda@v2 + with: + activate-environment: "pcmdi_metrics_dev" + miniforge-variant: Mambaforge + miniforge-version: latest + use-mamba: true + mamba-version: "*" + channel-priority: strict + auto-update-conda: true + + # Used for refreshing the cache every 24 hours to avoid inconsistencies of package + # versions between the CI pipeline and local installations. + - name: Get Date + id: get-date + run: echo "today=$(/bin/date -u '+%Y%m%d')" >> $GITHUB_OUTPUT + shell: bash + + - name: Cache Conda + uses: actions/cache@v3 + with: + path: ${{ env.CONDA }}/envs + key: + conda-${{ runner.os }}--${{ runner.arch }}--${{ + steps.get-date.outputs.today }}-${{ + hashFiles('conda-env/dev.yml') }}-${{ env.CACHE_NUMBER}} + env: + # Increase this value to reset cache if conda/dev.yml has not changed in the workflow + CACHE_NUMBER: 0 + + - name: Update environment + run: + mamba env update -n pcmdi_metrics_dev -f conda-env/dev.yml + if: steps.cache.outputs.cache-hit != 'true' + + - name: Install pcmdi_metrics + # Source: https://github.com/conda/conda-build/issues/4251#issuecomment-1053460542 run: | - pip install sphinx sphinx_rtd_theme sphinx_book_theme sphinx_autosummary_accessors sphinx-copybutton sphinx-design nbsphinx + python -m pip install --no-build-isolation --no-deps -e . + - name: Sphinx build run: | sphinx-build docs _build From f5b9c6e3cad8eb5ecf7e30d2364afab1eba414c3 Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Wed, 25 Sep 2024 11:11:22 -0700 Subject: [PATCH 16/28] refer dev.yml when generating conda env --- .github/workflows/documentation.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/documentation.yaml b/.github/workflows/documentation.yaml index 711f6df3e..776caba96 100644 --- a/.github/workflows/documentation.yaml +++ b/.github/workflows/documentation.yaml @@ -15,6 +15,7 @@ jobs: activate-environment: "pcmdi_metrics_dev" miniforge-variant: Mambaforge miniforge-version: latest + environment-file: conda-env/ci.yml use-mamba: true mamba-version: "*" channel-priority: strict From 02825d6f4ce208e9886a219c31630db012fbeffe Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Wed, 25 Sep 2024 11:17:15 -0700 Subject: [PATCH 17/28] update --- .github/workflows/build_workflow.yml | 73 ++++++++++++++++++++++++++++ .github/workflows/documentation.yaml | 4 +- 2 files changed, 75 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build_workflow.yml b/.github/workflows/build_workflow.yml index 192e22322..e8c5d9df5 100644 --- a/.github/workflows/build_workflow.yml +++ b/.github/workflows/build_workflow.yml @@ -96,3 +96,76 @@ jobs: - name: Run Tests run: | pytest + + publish-docs: + if: ${{ github.event_name == 'push' }} + runs-on: ubuntu-latest + defaults: + run: + shell: bash -l {0} + timeout-minutes: 5 + steps: + - uses: actions/checkout@v3 + with: + persist-credentials: false + fetch-depth: 0 + + - name: Cache Conda + uses: actions/cache@v3 + env: + # Increase this value to reset cache if conda-env/ci.yml has not changed in the workflow + CACHE_NUMBER: 0 + with: + path: ~/conda_pkgs_dir + key: ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-${{ + hashFiles('conda-env/ci.yml') }} + + - name: Set up Conda Environment + uses: conda-incubator/setup-miniconda@v2 + with: + activate-environment: "pcmdi_metrics_dev" + miniforge-variant: Miniforge3 + miniforge-version: latest + environment-file: conda-env/dev.yml + channel-priority: strict + auto-update-conda: true + + - name: Build Sphinx Docs + run: | + cd docs + sphinx-multiversion source _build/html + + - name: Copy Docs and Commit + run: | + # gh-pages branch must already exist + git clone https://github.com/E3SM-Project/e3sm_diags.git --branch gh-pages --single-branch gh-pages + + # Make sure we're in the gh-pages directory. + cd gh-pages + + # Create `.nojekyll` (if it doesn't already exist) for proper GH Pages configuration. + touch .nojekyll + + # Add `index.html` to point to the `main` branch automatically. + printf '' > index.html + + # Only replace `main` docs with latest changes. Docs for tags should be untouched. + rm -rf _build/html/main + mkdir -p _build/html/main + cp -r ../docs/_build/html/main _build/html + + # Configure git using GitHub Actions credentials. + git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com" + git config --local user.name "github-actions[bot]" + + # The below command will fail if no changes were present, so we ignore it + git add . + git commit -m "Update documentation" -a || true + + - name: Push Changes + uses: ad-m/github-push-action@master + with: + branch: gh-pages + directory: gh-pages + github_token: ${{ secrets.GITHUB_TOKEN }} + force: true \ No newline at end of file diff --git a/.github/workflows/documentation.yaml b/.github/workflows/documentation.yaml index 776caba96..94c98a949 100644 --- a/.github/workflows/documentation.yaml +++ b/.github/workflows/documentation.yaml @@ -1,5 +1,5 @@ name: Docs -on: [pull_request, workflow_dispatch] +on: [push, pull_request, workflow_dispatch] permissions: contents: write jobs: @@ -15,7 +15,7 @@ jobs: activate-environment: "pcmdi_metrics_dev" miniforge-variant: Mambaforge miniforge-version: latest - environment-file: conda-env/ci.yml + environment-file: conda-env/dev.yml use-mamba: true mamba-version: "*" channel-priority: strict From a57d7cd844fc44184b00f9dd6743fa3bafebcb62 Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Wed, 25 Sep 2024 11:20:57 -0700 Subject: [PATCH 18/28] combined to build_workflow.yml --- .github/workflows/documentation.yaml | 63 ---------------------------- 1 file changed, 63 deletions(-) delete mode 100644 .github/workflows/documentation.yaml diff --git a/.github/workflows/documentation.yaml b/.github/workflows/documentation.yaml deleted file mode 100644 index 94c98a949..000000000 --- a/.github/workflows/documentation.yaml +++ /dev/null @@ -1,63 +0,0 @@ -name: Docs -on: [push, pull_request, workflow_dispatch] -permissions: - contents: write -jobs: - docs: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-python@v3 - - - name: Set up Conda Environment - uses: conda-incubator/setup-miniconda@v2 - with: - activate-environment: "pcmdi_metrics_dev" - miniforge-variant: Mambaforge - miniforge-version: latest - environment-file: conda-env/dev.yml - use-mamba: true - mamba-version: "*" - channel-priority: strict - auto-update-conda: true - - # Used for refreshing the cache every 24 hours to avoid inconsistencies of package - # versions between the CI pipeline and local installations. - - name: Get Date - id: get-date - run: echo "today=$(/bin/date -u '+%Y%m%d')" >> $GITHUB_OUTPUT - shell: bash - - - name: Cache Conda - uses: actions/cache@v3 - with: - path: ${{ env.CONDA }}/envs - key: - conda-${{ runner.os }}--${{ runner.arch }}--${{ - steps.get-date.outputs.today }}-${{ - hashFiles('conda-env/dev.yml') }}-${{ env.CACHE_NUMBER}} - env: - # Increase this value to reset cache if conda/dev.yml has not changed in the workflow - CACHE_NUMBER: 0 - - - name: Update environment - run: - mamba env update -n pcmdi_metrics_dev -f conda-env/dev.yml - if: steps.cache.outputs.cache-hit != 'true' - - - name: Install pcmdi_metrics - # Source: https://github.com/conda/conda-build/issues/4251#issuecomment-1053460542 - run: | - python -m pip install --no-build-isolation --no-deps -e . - - - name: Sphinx build - run: | - sphinx-build docs _build - - name: Deploy - uses: peaceiris/actions-gh-pages@v3 - if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} - with: - publish_branch: gh-pages - github_token: ${{ secrets.GITHUB_TOKEN }} - publish_dir: _build/ - force_orphan: true From 354074213e365703c88bc6ab828af820595c9042 Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Wed, 25 Sep 2024 11:32:35 -0700 Subject: [PATCH 19/28] clean up --- docs/api.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api.rst b/docs/api.rst index d3e5a7516..dd6dac8c3 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -4,7 +4,7 @@ API Reference API Functions for Developpers ----------------------------- -Below is a list of some API functions that are available in ``pcmdi_metrics.utils`` for developpers. +Below is a list of some API functions that are available in ``pcmdi_metrics.` for developpers. .. autosummary:: :toctree: generated/ From 901fd590776cff6fb2dd717dc3171737def98b2d Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Wed, 25 Sep 2024 11:43:30 -0700 Subject: [PATCH 20/28] orgarnize functions into categories --- docs/api.rst | 39 +++++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/docs/api.rst b/docs/api.rst index dd6dac8c3..5e1fc4d0d 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -4,19 +4,34 @@ API Reference API Functions for Developpers ----------------------------- -Below is a list of some API functions that are available in ``pcmdi_metrics.` for developpers. +.. currentmodule:: pcmdi_metrics + +Below is a list of some API functions that are available in `pcmdi_metrics.` for developpers. + +QC tools +~~~~~~~~ + +.. autosummary:: + :toctree: generated/ + + pcmdi_metrics.utils.check_daily_time_axis + pcmdi_metrics.utils.check_monthly_time_axis + +Land-sea mask tools +~~~~~~~~~~~~~~~~~~~ .. autosummary:: :toctree: generated/ - check_daily_time_axis - check_monthly_time_axis - create_land_sea_mask - apply_landmask - apply_oceanmask - regrid - -.. automodule:: pcmdi_metrics.utils - :members: check_daily_time_axis, check_monthly_time_axis, create_land_sea_mask, apply_landmask, apply_oceanmask, regrid - :undoc-members: - :show-inheritance: + pcmdi_metrics.utils.create_land_sea_mask + pcmdi_metrics.utils.apply_landmask + pcmdi_metrics.utils.apply_oceanmask + +Regrid (horizontal interpolation) tool +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. autosummary:: + :toctree: generated/ + + pcmdi_metrics.utils.regrid + From bf3d37824df73b97461568238be9b51b3e41cfac Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Wed, 25 Sep 2024 11:56:58 -0700 Subject: [PATCH 21/28] separate ci.yml from dev.yml to make lighter env for build --- .github/workflows/build_workflow.yml | 14 +++++----- conda-env/ci.yml | 39 ++++++++++++++++++++++++++++ conda-env/dev.yml | 2 +- 3 files changed, 47 insertions(+), 8 deletions(-) create mode 100644 conda-env/ci.yml diff --git a/.github/workflows/build_workflow.yml b/.github/workflows/build_workflow.yml index e8c5d9df5..e59217003 100644 --- a/.github/workflows/build_workflow.yml +++ b/.github/workflows/build_workflow.yml @@ -56,9 +56,10 @@ jobs: - name: Set up Conda Environment uses: conda-incubator/setup-miniconda@v2 with: - activate-environment: "pcmdi_metrics_dev" + activate-environment: "pcmdi_metrics_ci" miniforge-variant: Mambaforge miniforge-version: latest + environment-file: conda-env/ci.yml use-mamba: true mamba-version: "*" channel-priority: strict @@ -83,11 +84,6 @@ jobs: # Increase this value to reset cache if conda/dev.yml has not changed in the workflow CACHE_NUMBER: 0 - - name: Update environment - run: - mamba env update -n pcmdi_metrics_dev -f conda-env/dev.yml - if: steps.cache.outputs.cache-hit != 'true' - - name: Install pcmdi_metrics # Source: https://github.com/conda/conda-build/issues/4251#issuecomment-1053460542 run: | @@ -97,6 +93,10 @@ jobs: run: | pytest + - name: Run Unit Tests + run: pytest tests + + publish-docs: if: ${{ github.event_name == 'push' }} runs-on: ubuntu-latest @@ -138,7 +138,7 @@ jobs: - name: Copy Docs and Commit run: | # gh-pages branch must already exist - git clone https://github.com/E3SM-Project/e3sm_diags.git --branch gh-pages --single-branch gh-pages + git clone https://github.com/PCMDI/pcmdi_metrics.git --branch gh-pages --single-branch gh-pages # Make sure we're in the gh-pages directory. cd gh-pages diff --git a/conda-env/ci.yml b/conda-env/ci.yml new file mode 100644 index 000000000..3abae185c --- /dev/null +++ b/conda-env/ci.yml @@ -0,0 +1,39 @@ +# Conda pcmdi_metrics CI/CD environment (used in GH Actions). +name: pcmdi_metrics_ci +channels: + - conda-forge + - defaults +dependencies: + # ================== + # Base + # ================== + # NOTE: If versions are updated, also `additional_dependencies` list for mypy in `.pre-commit-config.yaml` + - python=3.10.10 + - pip=23.1.2 + - numpy=1.23.5 + - cartopy=0.22.0 + - matplotlib=3.7.1 + - cdms2=3.1.5 + - genutil=8.2.1 + - cdutil=8.2.1 + - cdp=1.7.0 + - eofs=1.4.1 + - seaborn=0.12.2 + - enso_metrics=1.1.1 + - xcdat>=0.7.0 + - xmltodict=0.13.0 + - setuptools=67.7.2 + - netcdf4>=1.6.3 + - regionmask=0.9.0 + - rasterio>=1.3.6 + - shapely=2.0.1 + - numdifftools + - nc-time-axis + # ================== + # Testing + # ================== + - pre_commit=3.2.2 + - pytest=7.3.1 + - pytest-cov=4.0.0 + +prefix: /opt/miniconda3/envs/pmcdi_metrics_ci diff --git a/conda-env/dev.yml b/conda-env/dev.yml index 8abeceaf7..1ebb21307 100644 --- a/conda-env/dev.yml +++ b/conda-env/dev.yml @@ -1,4 +1,4 @@ -# Conda pcmdi_metrics development environment +# A conda development environment with all dependencies, including optional and documentation dependencies. name: pcmdi_metrics_dev channels: - conda-forge From 5dc94cbd8814c6752222f8d8cbb225c9b29ff6cd Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Wed, 25 Sep 2024 12:09:30 -0700 Subject: [PATCH 22/28] add docstrings --- pcmdi_metrics/utils/sort_human.py | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/pcmdi_metrics/utils/sort_human.py b/pcmdi_metrics/utils/sort_human.py index 7e13e017b..757f4b9fc 100644 --- a/pcmdi_metrics/utils/sort_human.py +++ b/pcmdi_metrics/utils/sort_human.py @@ -3,17 +3,37 @@ def sort_human(input_list: list[str]) -> list: - """Sort list by natual order + """ + Sort a list of strings in natural order. + + This function sorts a list of strings using a natural sorting algorithm, + which means that strings containing numbers are sorted in a way that + respects numerical order within the string. Parameters ---------- - input_list : list - input list + input_list : list of str + The input list of strings to be sorted. Returns ------- - list - sorted list + list of str + A new list containing the input strings sorted in natural order. + + Notes + ----- + The natural sorting algorithm used in this function considers the + numerical values within strings when determining the sort order. For + example, "file2" will be sorted before "file10". + + Examples + -------- + >>> sort_human(['file1', 'file10', 'file2']) + ['file1', 'file2', 'file10'] + + >>> sort_human(['1.txt', '10.txt', '2.txt', 'foo.txt']) + ['1.txt', '2.txt', '10.txt', 'foo.txt'] + """ lst = copy(input_list) From f3468f63cfa9fbcda15e138ed58e23356229aab8 Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Wed, 25 Sep 2024 12:13:12 -0700 Subject: [PATCH 23/28] add more functions to the list --- docs/api.rst | 44 +++++++++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/docs/api.rst b/docs/api.rst index 5e1fc4d0d..a643746e5 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -8,8 +8,30 @@ API Functions for Developpers Below is a list of some API functions that are available in `pcmdi_metrics.` for developpers. -QC tools -~~~~~~~~ + +Land-sea mask +~~~~~~~~~~~~~ + +.. autosummary:: + :toctree: generated/ + + pcmdi_metrics.utils.create_land_sea_mask + pcmdi_metrics.utils.apply_landmask + pcmdi_metrics.utils.apply_oceanmask + + +Grid handling and re-gridding (horizontal interpolation) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. autosummary:: + :toctree: generated/ + + pcmdi_metrics.utils.create_target_grid + pcmdi_metrics.utils.regrid + + +Quality control (QC) +~~~~~~~~~~~~~~~~~~~~ .. autosummary:: :toctree: generated/ @@ -17,21 +39,21 @@ QC tools pcmdi_metrics.utils.check_daily_time_axis pcmdi_metrics.utils.check_monthly_time_axis -Land-sea mask tools -~~~~~~~~~~~~~~~~~~~ +Calendar-related functions +~~~~~~~~~~~~~~~~~~~~~~~~~~ .. autosummary:: :toctree: generated/ - pcmdi_metrics.utils.create_land_sea_mask - pcmdi_metrics.utils.apply_landmask - pcmdi_metrics.utils.apply_oceanmask + pcmdi_metrics.utils.custom_season_average + pcmdi_metrics.utils.custom_season_departure -Regrid (horizontal interpolation) tool -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Miscellaneous tools +~~~~~~~~~~~~~~~~~~~ .. autosummary:: :toctree: generated/ - pcmdi_metrics.utils.regrid - + pcmdi_metrics.utils.sort_human + pcmdi_metrics.utils.fill_template + pcmdi_metrics.utils.tree \ No newline at end of file From 0130387d2a0160cf0a1c63db8542e32701389fbc Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Wed, 25 Sep 2024 12:29:52 -0700 Subject: [PATCH 24/28] add docstrings --- pcmdi_metrics/io/region_from_file.py | 43 +++++- pcmdi_metrics/io/xcdat_dataset_io.py | 204 +++++++++++++++++++++++++++ 2 files changed, 241 insertions(+), 6 deletions(-) diff --git a/pcmdi_metrics/io/region_from_file.py b/pcmdi_metrics/io/region_from_file.py index bcb5144fe..cf7cf7290 100644 --- a/pcmdi_metrics/io/region_from_file.py +++ b/pcmdi_metrics/io/region_from_file.py @@ -3,13 +3,44 @@ def region_from_file(data, rgn_path, attr, feature): - # Return data masked from a feature in input file. - # Arguments: - # data: xcdat dataset - # feature: str, name of region - # rgn_path: str, path to file - # attr: str, attribute name + """ + Return data masked from a feature in the input file. + This function reads a region from a file, creates a mask based on the specified feature, + and applies the mask to the input data. + + Parameters + ---------- + data : xarray.Dataset or xarray.DataArray + The input data to be masked. Must have 'lon' and 'lat' coordinates. + rgn_path : str + Path to the file containing region information. + attr : str + Attribute name in the region file to use for feature selection. + feature : str + Name of the region to be selected. + + Returns + ------- + xarray.Dataset or xarray.DataArray + The input data masked to the specified region. + + Raises + ------ + Exception + If there's an error in creating the region subset from the file or in applying the mask. + + Notes + ----- + This function uses geopandas to read the region file and regionmask to create and apply the mask. + The input data must have 'lon' and 'lat' coordinates. + + Examples + -------- + >>> import xarray as xr + >>> data = xr.open_dataset('path/to/data.nc') + >>> masked_data = region_from_file(data, 'path/to/regions.shp', 'region_name', 'Europe') + """ lon = data["lon"].data lat = data["lat"].data diff --git a/pcmdi_metrics/io/xcdat_dataset_io.py b/pcmdi_metrics/io/xcdat_dataset_io.py index db97c5945..d3d79568d 100644 --- a/pcmdi_metrics/io/xcdat_dataset_io.py +++ b/pcmdi_metrics/io/xcdat_dataset_io.py @@ -9,6 +9,28 @@ def _find_key( ds: Union[xr.Dataset, xr.DataArray], axis: str, potential_names: list ) -> str: + """ + Internal function to find the appropriate key for a given axis. + + Parameters + ---------- + ds : Union[xr.Dataset, xr.DataArray] + The input dataset or data array. + axis : str + The axis to find the key for ('T', 'X', or 'Y'). + potential_names : list + List of potential names for the axis. + + Returns + ------- + str + The key corresponding to the given axis. + + Raises + ------ + Exception + If no appropriate key can be found. + """ try: key = xc.get_dim_keys(ds, axis) except Exception as e: @@ -33,11 +55,37 @@ def _find_key( def get_axis_list(ds: Union[xr.Dataset, xr.DataArray]) -> list[str]: + """ + Retrieve coordinate key names from the dataset or data array. + + Parameters + ---------- + ds : Union[xr.Dataset, xr.DataArray] + The input dataset or data array. + + Returns + ------- + list[str] + List of coordinate key names. + """ axes = list(ds.coords.keys()) return axes def get_data_list(ds: Union[xr.Dataset, xr.DataArray]) -> list[str]: + """ + Retrieve data variable names from the dataset or data array. + + Parameters + ---------- + ds : Union[xr.Dataset, xr.DataArray] + The input dataset or data array. + + Returns + ------- + list[str] + List of data variable names. + """ if isinstance(ds, xr.Dataset): return list(ds.data_vars.keys()) elif isinstance(ds, xr.DataArray): @@ -45,18 +93,57 @@ def get_data_list(ds: Union[xr.Dataset, xr.DataArray]) -> list[str]: def get_time_key(ds: Union[xr.Dataset, xr.DataArray]) -> str: + """ + Get the key for the time dimension. + + Parameters + ---------- + ds : Union[xr.Dataset, xr.DataArray] + The input dataset or data array. + + Returns + ------- + str + The key for the time dimension. + """ axis = "T" potential_names = ["time", "t"] return _find_key(ds, axis, potential_names) def get_latitude_key(ds: Union[xr.Dataset, xr.DataArray]) -> str: + """ + Get the key for the latitude dimension. + + Parameters + ---------- + ds : Union[xr.Dataset, xr.DataArray] + The input dataset or data array. + + Returns + ------- + str + The key for the latitude dimension. + """ axis = "Y" potential_names = ["lat", "latitude"] return _find_key(ds, axis, potential_names) def get_longitude_key(ds: Union[xr.Dataset, xr.DataArray]) -> str: + """ + Get the key for the longitude dimension. + + Parameters + ---------- + ds : Union[xr.Dataset, xr.DataArray] + The input dataset or data array. + + Returns + ------- + str + The key for the longitude dimension. + """ axis = "X" potential_names = ["lon", "longitude"] return _find_key(ds, axis, potential_names) @@ -66,16 +153,55 @@ def get_longitude_key(ds: Union[xr.Dataset, xr.DataArray]) -> str: def get_time_bounds_key(ds: Union[xr.Dataset, xr.DataArray]) -> str: + """ + Get the key for the time bounds. + + Parameters + ---------- + ds : Union[xr.Dataset, xr.DataArray] + The input dataset or data array. + + Returns + ------- + str + The key for the time bounds. + """ lat_key = get_time_key(ds) return ds[lat_key].attrs["bounds"] def get_latitude_bounds_key(ds: Union[xr.Dataset, xr.DataArray]) -> str: + """ + Get the key for the latitude bounds. + + Parameters + ---------- + ds : Union[xr.Dataset, xr.DataArray] + The input dataset or data array. + + Returns + ------- + str + The key for the latitude bounds. + """ lat_key = get_latitude_key(ds) return ds[lat_key].attrs["bounds"] def get_longitude_bounds_key(ds: Union[xr.Dataset, xr.DataArray]) -> str: + """ + Get the key for the longitude bounds. + + Parameters + ---------- + ds : Union[xr.Dataset, xr.DataArray] + The input dataset or data array. + + Returns + ------- + str + The key for the longitude bounds. + """ lon_key = get_longitude_key(ds) return ds[lon_key].attrs["bounds"] @@ -84,18 +210,57 @@ def get_longitude_bounds_key(ds: Union[xr.Dataset, xr.DataArray]) -> str: def get_time(ds: Union[xr.Dataset, xr.DataArray]) -> xr.DataArray: + """ + Extract time coordinate data. + + Parameters + ---------- + ds : Union[xr.Dataset, xr.DataArray] + The input dataset or data array. + + Returns + ------- + xr.DataArray + The time coordinate data. + """ time_key = get_time_key(ds) time = ds[time_key] return time def get_longitude(ds: Union[xr.Dataset, xr.DataArray]) -> xr.DataArray: + """ + Extract longitude coordinate data. + + Parameters + ---------- + ds : Union[xr.Dataset, xr.DataArray] + The input dataset or data array. + + Returns + ------- + xr.DataArray + The longitude coordinate data. + """ lon_key = get_longitude_key(ds) lon = ds[lon_key] return lon def get_latitude(ds: Union[xr.Dataset, xr.DataArray]) -> xr.DataArray: + """ + Extract latitude coordinate data. + + Parameters + ---------- + ds : Union[xr.Dataset, xr.DataArray] + The input dataset or data array. + + Returns + ------- + xr.DataArray + The latitude coordinate data. + """ lat_key = get_latitude_key(ds) lat = ds[lat_key] return lat @@ -105,18 +270,57 @@ def get_latitude(ds: Union[xr.Dataset, xr.DataArray]) -> xr.DataArray: def get_time_bounds(ds: Union[xr.Dataset, xr.DataArray]) -> xr.DataArray: + """ + Extract time bounds data. + + Parameters + ---------- + ds : Union[xr.Dataset, xr.DataArray] + The input dataset or data array. + + Returns + ------- + xr.DataArray + The time bounds data. + """ time_bounds_key = get_time_bounds_key(ds) time_bounds = ds[time_bounds_key] return time_bounds def get_longitude_bounds(ds: Union[xr.Dataset, xr.DataArray]) -> xr.DataArray: + """ + Extract longitude bounds data. + + Parameters + ---------- + ds : Union[xr.Dataset, xr.DataArray] + The input dataset or data array. + + Returns + ------- + xr.DataArray + The longitude bounds data. + """ lon_bounds_key = get_longitude_bounds_key(ds) lon_bounds = ds[lon_bounds_key] return lon_bounds def get_latitude_bounds(ds: Union[xr.Dataset, xr.DataArray]) -> xr.DataArray: + """ + Extract latitude bounds data. + + Parameters + ---------- + ds : Union[xr.Dataset, xr.DataArray] + The input dataset or data array. + + Returns + ------- + xr.DataArray + The latitude bounds data. + """ lat_bounds_key = get_latitude_bounds_key(ds) lat_bounds = ds[lat_bounds_key] return lat_bounds From 867620c543ab0827369728dd864dc8bc9a6eabe5 Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Wed, 25 Sep 2024 12:30:09 -0700 Subject: [PATCH 25/28] add more functions to the list --- docs/api.rst | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/docs/api.rst b/docs/api.rst index a643746e5..2286d80fa 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -56,4 +56,35 @@ Miscellaneous tools pcmdi_metrics.utils.sort_human pcmdi_metrics.utils.fill_template - pcmdi_metrics.utils.tree \ No newline at end of file + pcmdi_metrics.utils.tree + + +Region handling +~~~~~~~~~~~~~~~ +.. autosummary:: + :toctree: generated/ + + pcmdi_metrics.io.region_subset + pcmdi_metrics.io.region_from_file + + +Retrieve data from xarray Dataset +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.. autosummary:: + :toctree: generated/ + + pcmdi_metrics.io.get_grid + pcmdi_metrics.io.get_axis_list + pcmdi_metrics.io.get_data_list + pcmdi_metrics.io.get_latitude + pcmdi_metrics.io.get_latitude_bounds + pcmdi_metrics.io.get_latitude_key + pcmdi_metrics.io.get_longitude + pcmdi_metrics.io.get_longitude_bounds + pcmdi_metrics.io.get_longitude_key + pcmdi_metrics.io.get_time + pcmdi_metrics.io.get_time_bounds + pcmdi_metrics.io.get_time_bounds_key + pcmdi_metrics.io.get_time_key + pcmdi_metrics.io.select_subset + From d99cf173d734cfb3fb3ada4e34e5191d2cc773f5 Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Wed, 25 Sep 2024 12:34:38 -0700 Subject: [PATCH 26/28] rewrite docstring to scipy style --- pcmdi_metrics/io/xcdat_dataset_io.py | 62 +++++++++++++++++----------- 1 file changed, 38 insertions(+), 24 deletions(-) diff --git a/pcmdi_metrics/io/xcdat_dataset_io.py b/pcmdi_metrics/io/xcdat_dataset_io.py index d3d79568d..cab6e21c6 100644 --- a/pcmdi_metrics/io/xcdat_dataset_io.py +++ b/pcmdi_metrics/io/xcdat_dataset_io.py @@ -333,33 +333,47 @@ def select_subset( ds: xr.Dataset, lat: tuple = None, lon: tuple = None, time: tuple = None ) -> xr.Dataset: """ - Selects a subset of the given xarray dataset based on specified latitude, longitude, and time ranges. + Select a subset of the given xarray dataset based on specified latitude, longitude, and time ranges. - Parameters: - - ds (xr.Dataset): The input xarray dataset. - - lat (tuple, optional): Latitude range in the form of (min, max). - - lon (tuple, optional): Longitude range in the form of (min, max). - - time (tuple, optional): Time range. If time is specified, it should be in the form of (start_time, end_time), - where start_time and end_time can be integers, floats, string, or cftime.datetime objects. - - Returns: - - xr.Dataset: Subset of the input dataset based on the specified latitude, longitude, and time ranges. - - Example Usage: - ``` - import cftime - - # Define latitude, longitude, and time ranges - lat_tuple = (30, 50) # Latitude range - lon_tuple = (110, 130) # Longitude range - time_tuple = ("1850-01-01 00:00:00", "1851-12-31 23:59:59") # Time range - - # Load your xarray dataset (ds) here + Parameters + ---------- + ds : xr.Dataset + The input xarray dataset. + lat : tuple, optional + Latitude range in the form of (min, max). + lon : tuple, optional + Longitude range in the form of (min, max). + time : tuple, optional + Time range in the form of (start_time, end_time). start_time and end_time + can be integers, floats, strings, or cftime.datetime objects. - # Select subset based on specified ranges - ds_subset = select_subset(ds, lat=lat_tuple, lon=lon_tuple, time=time_tuple) - ``` + Returns + ------- + xr.Dataset + Subset of the input dataset based on the specified latitude, longitude, and time ranges. + + Notes + ----- + This function allows for flexible subsetting of xarray datasets based on + geographical coordinates and time ranges. + + Examples + -------- + >>> import xarray as xr + >>> import cftime + >>> + >>> # Load your xarray dataset (ds) here + >>> ds = xr.open_dataset('path/to/your/dataset.nc') + >>> + >>> # Define latitude, longitude, and time ranges + >>> lat_tuple = (30, 50) # Latitude range + >>> lon_tuple = (110, 130) # Longitude range + >>> time_tuple = ("1850-01-01 00:00:00", "1851-12-31 23:59:59") # Time range + >>> + >>> # Select subset based on specified ranges + >>> ds_subset = select_subset(ds, lat=lat_tuple, lon=lon_tuple, time=time_tuple) """ + sel_keys = {} if lat is not None: lat_key = get_latitude_key(ds) From 9ea275a29867f26b38b686516473feb4b718166c Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Wed, 25 Sep 2024 12:40:23 -0700 Subject: [PATCH 27/28] clean up --- pcmdi_metrics/io/region_from_file.py | 3 +-- pcmdi_metrics/io/xcdat_dataset_io.py | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/pcmdi_metrics/io/region_from_file.py b/pcmdi_metrics/io/region_from_file.py index cf7cf7290..10eea8712 100644 --- a/pcmdi_metrics/io/region_from_file.py +++ b/pcmdi_metrics/io/region_from_file.py @@ -3,8 +3,7 @@ def region_from_file(data, rgn_path, attr, feature): - """ - Return data masked from a feature in the input file. + """Return data masked from a feature in the input file. This function reads a region from a file, creates a mask based on the specified feature, and applies the mask to the input data. diff --git a/pcmdi_metrics/io/xcdat_dataset_io.py b/pcmdi_metrics/io/xcdat_dataset_io.py index cab6e21c6..3683888dd 100644 --- a/pcmdi_metrics/io/xcdat_dataset_io.py +++ b/pcmdi_metrics/io/xcdat_dataset_io.py @@ -31,6 +31,7 @@ def _find_key( Exception If no appropriate key can be found. """ + try: key = xc.get_dim_keys(ds, axis) except Exception as e: @@ -68,6 +69,7 @@ def get_axis_list(ds: Union[xr.Dataset, xr.DataArray]) -> list[str]: list[str] List of coordinate key names. """ + axes = list(ds.coords.keys()) return axes @@ -86,6 +88,7 @@ def get_data_list(ds: Union[xr.Dataset, xr.DataArray]) -> list[str]: list[str] List of data variable names. """ + if isinstance(ds, xr.Dataset): return list(ds.data_vars.keys()) elif isinstance(ds, xr.DataArray): @@ -106,6 +109,7 @@ def get_time_key(ds: Union[xr.Dataset, xr.DataArray]) -> str: str The key for the time dimension. """ + axis = "T" potential_names = ["time", "t"] return _find_key(ds, axis, potential_names) @@ -125,6 +129,7 @@ def get_latitude_key(ds: Union[xr.Dataset, xr.DataArray]) -> str: str The key for the latitude dimension. """ + axis = "Y" potential_names = ["lat", "latitude"] return _find_key(ds, axis, potential_names) @@ -144,6 +149,7 @@ def get_longitude_key(ds: Union[xr.Dataset, xr.DataArray]) -> str: str The key for the longitude dimension. """ + axis = "X" potential_names = ["lon", "longitude"] return _find_key(ds, axis, potential_names) @@ -166,6 +172,7 @@ def get_time_bounds_key(ds: Union[xr.Dataset, xr.DataArray]) -> str: str The key for the time bounds. """ + lat_key = get_time_key(ds) return ds[lat_key].attrs["bounds"] @@ -184,6 +191,7 @@ def get_latitude_bounds_key(ds: Union[xr.Dataset, xr.DataArray]) -> str: str The key for the latitude bounds. """ + lat_key = get_latitude_key(ds) return ds[lat_key].attrs["bounds"] @@ -202,6 +210,7 @@ def get_longitude_bounds_key(ds: Union[xr.Dataset, xr.DataArray]) -> str: str The key for the longitude bounds. """ + lon_key = get_longitude_key(ds) return ds[lon_key].attrs["bounds"] @@ -223,6 +232,7 @@ def get_time(ds: Union[xr.Dataset, xr.DataArray]) -> xr.DataArray: xr.DataArray The time coordinate data. """ + time_key = get_time_key(ds) time = ds[time_key] return time @@ -242,6 +252,7 @@ def get_longitude(ds: Union[xr.Dataset, xr.DataArray]) -> xr.DataArray: xr.DataArray The longitude coordinate data. """ + lon_key = get_longitude_key(ds) lon = ds[lon_key] return lon @@ -261,6 +272,7 @@ def get_latitude(ds: Union[xr.Dataset, xr.DataArray]) -> xr.DataArray: xr.DataArray The latitude coordinate data. """ + lat_key = get_latitude_key(ds) lat = ds[lat_key] return lat @@ -283,6 +295,7 @@ def get_time_bounds(ds: Union[xr.Dataset, xr.DataArray]) -> xr.DataArray: xr.DataArray The time bounds data. """ + time_bounds_key = get_time_bounds_key(ds) time_bounds = ds[time_bounds_key] return time_bounds @@ -302,6 +315,7 @@ def get_longitude_bounds(ds: Union[xr.Dataset, xr.DataArray]) -> xr.DataArray: xr.DataArray The longitude bounds data. """ + lon_bounds_key = get_longitude_bounds_key(ds) lon_bounds = ds[lon_bounds_key] return lon_bounds @@ -321,6 +335,7 @@ def get_latitude_bounds(ds: Union[xr.Dataset, xr.DataArray]) -> xr.DataArray: xr.DataArray The latitude bounds data. """ + lat_bounds_key = get_latitude_bounds_key(ds) lat_bounds = ds[lat_bounds_key] return lat_bounds From 79e53550d7cddca3762eae0f386c519f94d97ae2 Mon Sep 17 00:00:00 2001 From: Jiwoo Lee Date: Wed, 25 Sep 2024 12:44:35 -0700 Subject: [PATCH 28/28] test --- docs/_templates/autosummary/class.rst | 34 +++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 docs/_templates/autosummary/class.rst diff --git a/docs/_templates/autosummary/class.rst b/docs/_templates/autosummary/class.rst new file mode 100644 index 000000000..b2c0c5ed6 --- /dev/null +++ b/docs/_templates/autosummary/class.rst @@ -0,0 +1,34 @@ +{{ fullname | escape | underline}} + +.. currentmodule:: {{ module }} + +.. add toctree option to make autodoc generate the pages + +.. autoclass:: {{ objname }} + + {% block attributes %} + {% if attributes %} + .. rubric:: Attributes + + .. autosummary:: + :toctree: . + {% for item in attributes %} + ~{{ name }}.{{ item }} + {%- endfor %} + {% endif %} + {% endblock %} + + {% block methods %} + {% if methods %} + .. rubric:: Methods + + .. autosummary:: + :toctree: . + {% for item in methods %} + {%- if item != '__init__' %} + ~{{ name }}.{{ item }} + {%- endif -%} + {%- endfor %} + {% endif %} + {% endblock %} +