From 5ec92e69ca3185903ad9b8b92a7cd953bafeac5d Mon Sep 17 00:00:00 2001 From: Sean Freeman Date: Fri, 15 Nov 2024 11:38:05 -0700 Subject: [PATCH 1/8] switched to pydata theme --- doc/conf.py | 23 +++- doc/{ => developer_guide}/code_reviews.rst | 2 + doc/{ => developer_guide}/code_structure.rst | 4 +- .../index.rst} | 120 ++++++++++-------- doc/{ => developer_guide}/mentoring.rst | 2 + .../testing_sphinx-based_rendering.rst | 2 + doc/examples.rst | 35 ----- doc/{ => getting_started}/data_input.rst | 4 +- .../feature_detection_overview.rst | 4 +- doc/{ => getting_started}/images/cross.png | Bin doc/{ => getting_started}/images/decision.png | Bin .../images/detection_multiplethresholds.png | Bin .../images/linking_prediction.png | Bin doc/{ => getting_started}/images/search.png | Bin doc/getting_started/index.rst | 20 +++ .../installguide.rst} | 3 + doc/{ => getting_started}/merge_split.rst | 0 .../merge_split_out_vars.csv | 0 doc/{ => getting_started}/plotting.rst | 3 + doc/{ => getting_started}/segmentation.rst | 0 .../tracking_basics.rst} | 14 +- doc/images/tobac-logo-colors.png | Bin 0 -> 55419 bytes doc/index.rst | 63 ++------- doc/tobac.rst | 2 +- doc/{ => userguide}/analysis.rst | 6 +- doc/{ => userguide}/big_datasets.rst | 2 + doc/{ => userguide}/bulk_statistics/index.rst | 2 + ..._statistics_during_feature_detection.ipynb | 0 ...mpute_statistics_during_segmentation.ipynb | 0 ...te_statistics_postprocessing_example.ipynb | 0 .../feature_detection/index.rst | 0 .../feature_detection_filtering.ipynb | 0 .../multiple_thresholds_example.ipynb | 0 .../notebooks/n_min_threshold_example.ipynb | 0 .../position_threshold_example.ipynb | 0 .../feature_detection_3D_out_vars.csv | 0 .../feature_detection_base_out_vars.csv | 0 .../feature_detection_output.rst | 8 +- .../features_without_segmented_area.rst | 6 +- .../images/box_vs_column_seeding.png | Bin .../feature_outside_of_threshold_area.png | Bin ...ture_outside_of_threshold_area_extreme.png | Bin .../images/features_without_segment.png | Bin .../images/position_thresholds.png | Bin .../images/sat_radar_combined.png | Bin .../images/sigma_threshold_example.png | Bin doc/userguide/index.rst | 21 +++ doc/{ => userguide}/publications.rst | 2 +- doc/{ => userguide}/segmentation_out_vars.csv | 0 .../segmentation_out_vars_statistics.csv | 0 doc/{ => userguide}/segmentation_output.rst | 2 + .../segmentation_parameters.rst | 6 +- .../threshold_detection_parameters.rst | 12 +- .../tracking_base_out_vars.csv | 0 doc/{ => userguide}/tracking_output.rst | 2 + .../transform_segmentation.rst | 2 +- examples/index.rst | 32 +++++ 57 files changed, 225 insertions(+), 179 deletions(-) rename doc/{ => developer_guide}/code_reviews.rst (98%) rename doc/{ => developer_guide}/code_structure.rst (98%) rename doc/{contributing.rst => developer_guide/index.rst} (78%) rename doc/{ => developer_guide}/mentoring.rst (99%) rename doc/{ => developer_guide}/testing_sphinx-based_rendering.rst (99%) delete mode 100644 doc/examples.rst rename doc/{ => getting_started}/data_input.rst (98%) rename doc/{ => getting_started}/feature_detection_overview.rst (91%) rename doc/{ => getting_started}/images/cross.png (100%) rename doc/{ => getting_started}/images/decision.png (100%) rename doc/{ => getting_started}/images/detection_multiplethresholds.png (100%) rename doc/{ => getting_started}/images/linking_prediction.png (100%) rename doc/{ => getting_started}/images/search.png (100%) create mode 100644 doc/getting_started/index.rst rename doc/{installation.rst => getting_started/installguide.rst} (98%) rename doc/{ => getting_started}/merge_split.rst (100%) rename doc/{ => getting_started}/merge_split_out_vars.csv (100%) rename doc/{ => getting_started}/plotting.rst (86%) rename doc/{ => getting_started}/segmentation.rst (100%) rename doc/{linking.rst => getting_started/tracking_basics.rst} (91%) create mode 100644 doc/images/tobac-logo-colors.png rename doc/{ => userguide}/analysis.rst (75%) rename doc/{ => userguide}/big_datasets.rst (97%) rename doc/{ => userguide}/bulk_statistics/index.rst (97%) rename doc/{ => userguide}/bulk_statistics/notebooks/compute_statistics_during_feature_detection.ipynb (100%) rename doc/{ => userguide}/bulk_statistics/notebooks/compute_statistics_during_segmentation.ipynb (100%) rename doc/{ => userguide}/bulk_statistics/notebooks/compute_statistics_postprocessing_example.ipynb (100%) rename doc/{ => userguide}/feature_detection/index.rst (100%) rename doc/{ => userguide}/feature_detection/notebooks/feature_detection_filtering.ipynb (100%) rename doc/{ => userguide}/feature_detection/notebooks/multiple_thresholds_example.ipynb (100%) rename doc/{ => userguide}/feature_detection/notebooks/n_min_threshold_example.ipynb (100%) rename doc/{ => userguide}/feature_detection/notebooks/position_threshold_example.ipynb (100%) rename doc/{ => userguide}/feature_detection_3D_out_vars.csv (100%) rename doc/{ => userguide}/feature_detection_base_out_vars.csv (100%) rename doc/{ => userguide}/feature_detection_output.rst (71%) rename doc/{ => userguide}/features_without_segmented_area.rst (94%) rename doc/{ => userguide}/images/box_vs_column_seeding.png (100%) rename doc/{ => userguide}/images/feature_outside_of_threshold_area.png (100%) rename doc/{ => userguide}/images/feature_outside_of_threshold_area_extreme.png (100%) rename doc/{ => userguide}/images/features_without_segment.png (100%) rename doc/{ => userguide}/images/position_thresholds.png (100%) rename doc/{ => userguide}/images/sat_radar_combined.png (100%) rename doc/{ => userguide}/images/sigma_threshold_example.png (100%) create mode 100644 doc/userguide/index.rst rename doc/{ => userguide}/publications.rst (99%) rename doc/{ => userguide}/segmentation_out_vars.csv (100%) rename doc/{ => userguide}/segmentation_out_vars_statistics.csv (100%) rename doc/{ => userguide}/segmentation_output.rst (98%) rename doc/{ => userguide}/segmentation_parameters.rst (91%) rename doc/{ => userguide}/threshold_detection_parameters.rst (90%) rename doc/{ => userguide}/tracking_base_out_vars.csv (100%) rename doc/{ => userguide}/tracking_output.rst (96%) rename doc/{ => userguide}/transform_segmentation.rst (94%) create mode 100644 examples/index.rst diff --git a/doc/conf.py b/doc/conf.py index 0b8acaa2..03e268f2 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -3,7 +3,7 @@ """ # This is the standard readthedocs theme. -import sphinx_rtd_theme +import pydata_sphinx_theme import sys, os sys.path.insert(0, os.path.abspath("extensions")) @@ -23,12 +23,31 @@ ] -html_theme = "sphinx_rtd_theme" +html_theme = "pydata_sphinx_theme" html_static_path = ["_static"] exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] +html_theme_options = { + "logo": { + "image_light": "images/tobac-logo-colors.png", + "image_dark": "images/tobac-logo-colors.png", + }, + # https://pydata-sphinx-theme.readthedocs.io/en/stable/user_guide/header-links.html#fontawesome-icons + "icon_links": [ + { + "name": "GitHub", + "url": "https://github.com/tobac-project/tobac", + "icon": "fa-brands fa-github", + }, + ], + "navbar_start": ["navbar-logo"], + "navbar_align": "content", + "header_links_before_dropdown": 5, +} + + project = "tobac" master_doc = "index" diff --git a/doc/code_reviews.rst b/doc/developer_guide/code_reviews.rst similarity index 98% rename from doc/code_reviews.rst rename to doc/developer_guide/code_reviews.rst index da8c2c90..8ae9ecfe 100644 --- a/doc/code_reviews.rst +++ b/doc/developer_guide/code_reviews.rst @@ -1,3 +1,5 @@ +.. _code-reviews: + Code reviews ------------------ diff --git a/doc/code_structure.rst b/doc/developer_guide/code_structure.rst similarity index 98% rename from doc/code_structure.rst rename to doc/developer_guide/code_structure.rst index cbc1b23e..9ef5741a 100644 --- a/doc/code_structure.rst +++ b/doc/developer_guide/code_structure.rst @@ -1,4 +1,6 @@ -Code structure and key design concepts +.. _code_structure: + +Code structure and key design concepts -------------------------------------- ================================== diff --git a/doc/contributing.rst b/doc/developer_guide/index.rst similarity index 78% rename from doc/contributing.rst rename to doc/developer_guide/index.rst index c458a69d..7b30d53d 100644 --- a/doc/contributing.rst +++ b/doc/developer_guide/index.rst @@ -1,16 +1,25 @@ -.. - How to contribute to the tobac project +############################## + Contributing +############################## -How to contribute -------------------------- +.. toctree:: + :maxdepth: 3 + :hidden: -Step-by-step overview of most important points: https://github.com/tobac-project/tobac/blob/main/CONTRIBUTING.md + code_reviews + code_structure + mentoring + testing_sphinx-based_rendering + + + +Thank you for your eagerness to contribute to *tobac*. We have a step-by-step overview of most important points: https://github.com/tobac-project/tobac/blob/main/CONTRIBUTING.md on contributing, and this documentation goes into more detail. ========================= -Code of conduct +Code of conduct ========================= -We are a multi-institutional and international community that aims to maintain and increase our diversity. We acknowledge that we all come with different experiences and capacities. Therefore, we strive to foster an inclusive and respectful environment where we help and support each other. We welcome any types of contributions and believe that we together can create accessible, reusable, and maintanable code that empowers researchers and enables groundbreaking science. +We are a multi-institutional and international community that aims to maintain and increase our diversity. We acknowledge that we all come with different experiences and capacities. Therefore, we strive to foster an inclusive and respectful environment where we help and support each other. We welcome any types of contributions and believe that we together can create accessible, reusable, and maintanable code that empowers researchers and enables groundbreaking science. We would like to refer to the `Python code of conduct `_ as we follow the same principles for communication and working with each other! @@ -18,29 +27,29 @@ We would like to refer to the `Python code of conduct `_ if you do not already have one. +* **Create a Github account**: The first thing, you need to do is to `create a GitHub account `_ if you do not already have one. * **Get familiar with the basics of GitHub and git**: * Getting started with the `basics `_ - * Learn about `branches `_ + * Learn about `branches `_ * Learn about `forks `_ * Learn about `pull requests `_ - * Learn about `how to commit and push changes from your local repository `_ + * Learn about `how to commit and push changes from your local repository `_ * **Create an issue**: If you have an idea for a new feature or a suggestion for any kind of code changes, please create an issue for this. We sort `our issues `_ into `milestones `_ to priorize work and manage our workflow, i.e. the different versions of **tobac** to come. - - The issues act, therefore, not only as a place for reporting bugs, but also as a collection of *to do* points. -* **Work on an issue**: You can also work on any issue that was created by somebody else and is already out there. A tip is to look for the **good first issue** label, if you are a new developer. These issues are usually fairly easy to address and can be good to practice our GitHub workflow. + The issues act, therefore, not only as a place for reporting bugs, but also as a collection of *to do* points. + +* **Work on an issue**: You can also work on any issue that was created by somebody else and is already out there. A tip is to look for the **good first issue** label, if you are a new developer. These issues are usually fairly easy to address and can be good to practice our GitHub workflow. + - * **Create a pull request from your fork:** We use our personal forks of the tobac repository to create pull requests. This means that you have to first commit and push your local changes to your personal fork and then create a pull request from that fork: https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request-from-a-fork =================================== Writing proper documentation =================================== -Please provide **Numpy Docstrings** for all new functions. +Please provide **Numpy Docstrings** for all new functions. **Example**: @@ -54,11 +63,11 @@ Please provide **Numpy Docstrings** for all new functions. ---------- tracks : pandas.DataFram DataFrame containing trajectories of cell centres - + param mass : iris.cube.Cube - cube of quantity (need coordinates 'time', 'geopotential_height','projection_x_coordinate' and + cube of quantity (need coordinates 'time', 'geopotential_height','projection_x_coordinate' and 'projection_y_coordinate') - + param mask : iris.cube.Cube cube containing mask (int > where belonging to cloud volume, 0 everywhere else ) @@ -66,9 +75,9 @@ Please provide **Numpy Docstrings** for all new functions. Returns ------- track_out : pandas.DataFrame - Dataframe containing t,x,y,z positions of centre of gravity and total cloud mass each tracked cells + Dataframe containing t,x,y,z positions of centre of gravity and total cloud mass each tracked cells at each timestep - + ''' @@ -77,11 +86,11 @@ Please provide **Numpy Docstrings** for all new functions. Tips on working on your local code =================================== -* Install tobac package with :code:`pip install -e` - * This allows you to directly test your local code changes as you run tobac. Instead of using the **tobac** version of the latest release, your local version of tobac will be used when you import **tobac** in a python script or IDE. +* Install tobac package with :code:`pip install -e` + * This allows you to directly test your local code changes as you run tobac. Instead of using the **tobac** version of the latest release, your local version of tobac will be used when you import **tobac** in a python script or IDE. * *Note that* this way of installing a local package will use the code of the checked in branch, so this allows you also to test code while switching between branches. -* You can locally **build the documentation page**: +* You can locally **build the documentation page**: * see :doc:`testing_sphinx-based_rendering` * Writing `meaningful commit messages `_ can be very helpful for you and people who review your code to better understand the code changes. @@ -91,15 +100,15 @@ Tips on working on your local code Our branching strategy ========================= -While you can use any type of branching strategy and naming as you work in your personal fork, we have three branches in the tobac repository: +While you can use any type of branching strategy and naming as you work in your personal fork, we have three branches in the tobac repository: * :code:`RC_*` * :code:`dev_*` * :code:`hotfix` -:code:`RC_*` is the release candidate of the next tobac version. The asterisk stands here for the specific tobac version: RC_vx.x.x (e.g. RC_v1.5.0). Pull requests to this branch need two reviews to be accepted before it can be merged into main. +:code:`RC_*` is the release candidate of the next tobac version. The asterisk stands here for the specific tobac version: RC_vx.x.x (e.g. RC_v1.5.0). Pull requests to this branch need two reviews to be accepted before it can be merged into main. -:code:`dev_*` is the development branch where we experiment with new features. This branch is perfectly suited to collaboratively work on a feature together with other **tobac** developers (see :doc:`mentoring`). In general, this branch is used for long-term, comprehensive code changes that might not be covered by a single pull request and where it might not be conceivable in which future **tobac** version to include the changes. There are no branch protection rules for this branch, which means that collaborators of our GitHub organization can directly push changes to this branch. Note that **dev_** can never directly merged into main, it has be merged into the release candidate branch :code:`RC_*` first! There can be more than one `dev_*` branch, therefore it we recommend to describe the feature to work on in the respective branch (e.g. :code:`dev_xarray_transition`). +:code:`dev_*` is the development branch where we experiment with new features. This branch is perfectly suited to collaboratively work on a feature together with other **tobac** developers (see :doc:`mentoring`). In general, this branch is used for long-term, comprehensive code changes that might not be covered by a single pull request and where it might not be conceivable in which future **tobac** version to include the changes. There are no branch protection rules for this branch, which means that collaborators of our GitHub organization can directly push changes to this branch. Note that **dev_** can never directly merged into main, it has be merged into the release candidate branch :code:`RC_*` first! There can be more than one `dev_*` branch, therefore it we recommend to describe the feature to work on in the respective branch (e.g. :code:`dev_xarray_transition`). :code:`hotfix` is the branch we use for hotfixes, i.e. bug fixes that need to be released as fast as possible because it influences people's code. This branch needs only one review before it can directly merged into :code:`main`. @@ -110,59 +119,58 @@ In brief: **Unless you are collaboratively working on a comprehensive feature or GitHub workflow ========================= -We use several `GitHub actions `_ to -assure continuous integration and to enable an efficient code development and release process. Our workflow -configuration can be found in +We use several `GitHub actions `_ to +assure continuous integration and to enable an efficient code development and release process. Our workflow +configuration can be found in `.github/workflows `_ and encompass -* check that code is formatted using the latest stable version of black -* linting of the latest code changes that checks the code quality and results in a score compared to the most recent released version -* check of the zenodo JSON file that ensures that the citation is correct -* check that all unit tests pass (including testing on multiple operating systems) and report test coverage -* check that the example jupyter notebooks run without problems +* check that code is formatted using the latest stable version of black +* linting of the latest code changes that checks the code quality and results in a score compared to the most recent released version +* check of the zenodo JSON file that ensures that the citation is correct +* check that all unit tests pass (including testing on multiple operating systems) and report test coverage +* check that the example jupyter notebooks run without problems ========================= Writing unit tests ========================= -We use unit tests that ensure that the functions of each module and submodule work properly. If you add a new -functionality, you should also add a unit test. All tests are located in the `test -folder `_ The module :py:mod:`tobac.testing` may help to -create simple, idealized cases where objects can be tracked to test if the new features result in the expected outcome. +We use unit tests that ensure that the functions of each module and submodule work properly. If you add a new +functionality, you should also add a unit test. All tests are located in the `test +folder `_ The module :py:mod:`tobac.testing` may help to +create simple, idealized cases where objects can be tracked to test if the new features result in the expected outcome. -If you are unsure on how to construct tests and run tests locally, you can find additional documentation on -`pytest `_ and `pytest -fixtures `_. +If you are unsure on how to construct tests and run tests locally, you can find additional documentation on +`pytest `_ and `pytest +fixtures `_. -You will also notice that we report the test coverage, i.e. how much of our current code is triggered and thus tested by -the unit tests. When you submit a pull request, you will see if your code changes have increased or decreased the test -coverage. Ideally, test coverage should not decrease, so please make sure to add appropriate unit tests that cover -all newly added functions. +You will also notice that we report the test coverage, i.e. how much of our current code is triggered and thus tested by +the unit tests. When you submit a pull request, you will see if your code changes have increased or decreased the test +coverage. Ideally, test coverage should not decrease, so please make sure to add appropriate unit tests that cover +all newly added functions. ========================= -Add examples +Add examples ========================= -In addition to the unit tests, we aim to provide examples on how to use all functionalities and how to choose different -tracking parameters. These `examples `_ are in form of jupyter -notebooks and can be based on simple, idealized test cases or real data. We strongly encourage the use of real data that -is publicly accessible, but another option for new examples with real data is to either upload the data to our `zenodo -repository `_ or create your own data upload on zenodo. Please include the name "tobac" in the data title for the latter. +In addition to the unit tests, we aim to provide examples on how to use all functionalities and how to choose different +tracking parameters. These `examples `_ are in form of jupyter +notebooks and can be based on simple, idealized test cases or real data. We strongly encourage the use of real data that +is publicly accessible, but another option for new examples with real data is to either upload the data to our `zenodo +repository `_ or create your own data upload on zenodo. Please include the name "tobac" in the data title for the latter. ========================= -Releasing a new version +Releasing a new version ========================= This is the checklist of steps for a release of a new **tobac** version: * Bump version in :code:`__init__.py` in :code:`RC_vXXX` -* Add changelog in :code:`RC_vXXX` +* Add changelog in :code:`RC_vXXX` * Regenerate example notebooks with the new version -* Merge :code:`RC_vXXX` into :code:`main` -* Merge updated :code:`main` branch back into release and dev branches +* Merge :code:`RC_vXXX` into :code:`main` +* Merge updated :code:`main` branch back into release and dev branches * Delete :code:`RC_vXXX` branch * Create release * Push release to conda-forge: https://github.com/tobac-project/tobac-notes/blob/main/uploading_to_conda-forge.md * Create new tag * E-mail tobac mailing list - diff --git a/doc/mentoring.rst b/doc/developer_guide/mentoring.rst similarity index 99% rename from doc/mentoring.rst rename to doc/developer_guide/mentoring.rst index c956af5e..429d5dfa 100644 --- a/doc/mentoring.rst +++ b/doc/developer_guide/mentoring.rst @@ -1,3 +1,5 @@ +.. _mentoring: + Mentoring and Collaboration ---------------------------- diff --git a/doc/testing_sphinx-based_rendering.rst b/doc/developer_guide/testing_sphinx-based_rendering.rst similarity index 99% rename from doc/testing_sphinx-based_rendering.rst rename to doc/developer_guide/testing_sphinx-based_rendering.rst index f0a7443e..2db13030 100644 --- a/doc/testing_sphinx-based_rendering.rst +++ b/doc/developer_guide/testing_sphinx-based_rendering.rst @@ -1,3 +1,5 @@ +.. _testing-sphinx-rendering: + How to check the Sphinx-based rendering --------------------------------------- diff --git a/doc/examples.rst b/doc/examples.rst deleted file mode 100644 index 85160f30..00000000 --- a/doc/examples.rst +++ /dev/null @@ -1,35 +0,0 @@ -Example Gallery -=============== -tobac is provided with a set of Jupyter notebooks that show examples of the application of tobac for different types of datasets. - - -.. nbgallery:: - :caption: Fundamentals of Detection and Tracking - - Test Blob in 2D - Two crossing Blobs - - On Feature Detection: Part 1 - On Feature Detection: Part 2 - On Segmentation - On Linking - - - - -.. nbgallery:: - :caption: Examples of Using *tobac* with Observations - - OLR from GOES-13 Satellite - Combine Radar & Satellite - - -.. nbgallery:: - :caption: Examples of Using *tobac* with Model Data - - WRF OLR - WRF Precip - WRF Updrafts - WRF Mesoscale Vorticity - -The notebooks can be found in the **examples** folder as part of the python package. The necessary input data for these examples is avaliable on zenodo and can be downloaded automatically by the Jupyter notebooks. \ No newline at end of file diff --git a/doc/data_input.rst b/doc/getting_started/data_input.rst similarity index 98% rename from doc/data_input.rst rename to doc/getting_started/data_input.rst index ec7a259f..6bb63d33 100644 --- a/doc/data_input.rst +++ b/doc/getting_started/data_input.rst @@ -1,6 +1,4 @@ -.. - Description of the input data required. - +.. _data_input: Data Input ========== diff --git a/doc/feature_detection_overview.rst b/doc/getting_started/feature_detection_overview.rst similarity index 91% rename from doc/feature_detection_overview.rst rename to doc/getting_started/feature_detection_overview.rst index a54f4215..6e18b618 100644 --- a/doc/feature_detection_overview.rst +++ b/doc/getting_started/feature_detection_overview.rst @@ -1,4 +1,4 @@ -.. _feature-detection-overview: +.. _feature_detection_overview: Feature Detection Basics ------------------------ @@ -11,7 +11,7 @@ The feature detection is the first step in using **tobac**. Features are identified as regions above or below a sequence of subsequent thresholds (if searching for eather maxima or minima in the data). Subsequently more restrictive threshold values are used to further refine the resulting features and allow for separation of features that are connected through a continuous region of less restrictive threshold values. - .. image:: images/detection_multiplethresholds.png + .. image:: ./images/detection_multiplethresholds.png :width: 500 px **Current development:** diff --git a/doc/images/cross.png b/doc/getting_started/images/cross.png similarity index 100% rename from doc/images/cross.png rename to doc/getting_started/images/cross.png diff --git a/doc/images/decision.png b/doc/getting_started/images/decision.png similarity index 100% rename from doc/images/decision.png rename to doc/getting_started/images/decision.png diff --git a/doc/images/detection_multiplethresholds.png b/doc/getting_started/images/detection_multiplethresholds.png similarity index 100% rename from doc/images/detection_multiplethresholds.png rename to doc/getting_started/images/detection_multiplethresholds.png diff --git a/doc/images/linking_prediction.png b/doc/getting_started/images/linking_prediction.png similarity index 100% rename from doc/images/linking_prediction.png rename to doc/getting_started/images/linking_prediction.png diff --git a/doc/images/search.png b/doc/getting_started/images/search.png similarity index 100% rename from doc/images/search.png rename to doc/getting_started/images/search.png diff --git a/doc/getting_started/index.rst b/doc/getting_started/index.rst new file mode 100644 index 00000000..2dbe56c7 --- /dev/null +++ b/doc/getting_started/index.rst @@ -0,0 +1,20 @@ +########################## + Getting Started +########################## + +.. toctree:: + :maxdepth: 3 + :hidden: + + installguide + data_input + feature_detection_overview + tracking_basics + segmentation + merge_split + plotting + + + +Welcome to *tobac*! We hope that you will find this tracking library to be useful in your research or operational work. To help you get started, we have put together this quickstart guide with some of the basic information you need to know to get started tracking your data with *tobac*. + diff --git a/doc/installation.rst b/doc/getting_started/installguide.rst similarity index 98% rename from doc/installation.rst rename to doc/getting_started/installguide.rst index 825859bf..373320ec 100644 --- a/doc/installation.rst +++ b/doc/getting_started/installguide.rst @@ -1,5 +1,8 @@ +.. _installguide: + Installation ------------ + tobac works with Python 3 installations. The easiest way is to install the most recent version of tobac via conda or mamba and the conda-forge channel: diff --git a/doc/merge_split.rst b/doc/getting_started/merge_split.rst similarity index 100% rename from doc/merge_split.rst rename to doc/getting_started/merge_split.rst diff --git a/doc/merge_split_out_vars.csv b/doc/getting_started/merge_split_out_vars.csv similarity index 100% rename from doc/merge_split_out_vars.csv rename to doc/getting_started/merge_split_out_vars.csv diff --git a/doc/plotting.rst b/doc/getting_started/plotting.rst similarity index 86% rename from doc/plotting.rst rename to doc/getting_started/plotting.rst index b2ad3653..c23d4458 100644 --- a/doc/plotting.rst +++ b/doc/getting_started/plotting.rst @@ -1,3 +1,6 @@ +.. _plotting: + Plotting ======== + tobac provides functions to conveniently visualise the tracking results and analyses. \ No newline at end of file diff --git a/doc/segmentation.rst b/doc/getting_started/segmentation.rst similarity index 100% rename from doc/segmentation.rst rename to doc/getting_started/segmentation.rst diff --git a/doc/linking.rst b/doc/getting_started/tracking_basics.rst similarity index 91% rename from doc/linking.rst rename to doc/getting_started/tracking_basics.rst index 0f88226d..2aa98061 100644 --- a/doc/linking.rst +++ b/doc/getting_started/tracking_basics.rst @@ -1,5 +1,7 @@ -Linking -------- +.. _tracking-basics: + +Tracking Basics +--------------- Currently implemented options for linking detected features into tracks: **Trackpy:** @@ -7,7 +9,7 @@ Currently implemented options for linking detected features into tracks: This method uses the trackpy library (http://soft-matter.github.io/trackpy). This approach only takes the point-like position of the feature, e.g. determined as the weighted mean, into account. Features to link with are looked for in a search radius defined by the parameters v_max or d_max. The position of the center of this search radius is determined by the method keyword. method="random" uses the position of the current feature (:math:`t_i`), while method="predict" makes use of the information from the linked feature in the previous timestep (:math:`t_{i-1}`) to predict the next position. For a simple case the search radii of the two methods look like this: - .. image:: images/linking_prediction.png + .. image:: ./images/linking_prediction.png :width: 500 px If there is only one feature in the search radius, the linking can happen immediately. If there are none, the track ends at this timestep. If there are more options, trackpy performs a decision process. Assume there are :math:`N` features in the current and also :math:`N` in the next timeframe and they are all within each search radius. This means there are :math:`N!` options for linking. Each of these options means that :math:`N` distances between the center of the search radius of a current feature and a feature from the next time frame :math:`\delta_n, n=1, 2, ..., N` are traveled by the features. Trackpy will calculate the sum of the squared distances @@ -18,15 +20,15 @@ If there is only one feature in the search radius, the linking can happen immedi For every option the lowest value of this sum is used for linking. As an example, consider these two crossing features: - .. image:: images/cross.png + .. image:: ./images/cross.png :width: 500 px If the search radius is chosen large enough, each will contain two options, a horizontal and a diagonal feature: - .. image:: images/search.png + .. image:: ./images/search.png :width: 500 px The linking will look differently for both methods in the end. The horizontal features are closer to the current position than the diagonal ones. This is why these are linked by the "random"-method. On the other hand, the diagonal features lie excatly on the guessed positions for the "predict"-method. This means, that the sum of squared distances is 0 and they are the optimal decision for linking in this case: - .. image:: images/decision.png + .. image:: ./images/decision.png :width: 500 px diff --git a/doc/images/tobac-logo-colors.png b/doc/images/tobac-logo-colors.png new file mode 100644 index 0000000000000000000000000000000000000000..5265c2077da4824473b17e3abb0376f3c2d57175 GIT binary patch literal 55419 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 AumAu6 literal 0 HcmV?d00001 diff --git a/doc/index.rst b/doc/index.rst index 1b215f20..870b3854 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -4,11 +4,13 @@ tobac - Tracking and Object-Based Analysis of Clouds ------------------------------------------------------- + + **tobac** is a Python package to rapidly identify, track and analyze clouds in different types of gridded datasets, such as 3D model output from cloud-resolving model simulations or 2D data from satellite retrievals. The software is set up in a modular way to include different algorithms for feature identification, tracking, and analyses. **tobac** is also input variable agnostic and doesn't rely on specific input variables, nor a specific grid to work. -Individual features are identified as either maxima or minima in a 2D or 3D time-varying field (see :doc:`feature_detection_overview`). An associated volume can then be determined using these features with a separate (or identical) time-varying 2D or 3D field and a threshold value (see :doc:`segmentation`). The identified objects are linked into consistent trajectories representing the cloud over its lifecycle in the tracking step. Analysis and visualization methods provide a convenient way to use and display the tracking results. +Individual features are identified as either maxima or minima in a 2D or 3D time-varying field (see :doc:`getting_started/feature_detection_overview`). An associated volume can then be determined using these features with a separate (or identical) time-varying 2D or 3D field and a threshold value (see :doc:`getting_started/segmentation`). The identified objects are linked into consistent trajectories representing the cloud over its lifecycle in the tracking step. Analysis and visualization methods provide a convenient way to use and display the tracking results. Version 1.2 of tobac and some example applications are described in a peer-reviewed article in Geoscientific Model Development as: @@ -21,68 +23,21 @@ Sokolowsky, G. A., Freeman, S. W., Jones, W. K., Kukulies, J., Senf, F., Marines The project is currently being extended by several contributors to include additional workflows and algorithms using the same structure, syntax, and data formats. -.. toctree:: - :caption: Basic Information - :maxdepth: 2 - - installation - data_input - analysis - plotting - big_datasets - examples - publications - -.. toctree:: - :caption: Feature Detection - :maxdepth: 2 - - feature_detection_overview - threshold_detection_parameters - feature_detection/index - feature_detection_output - -.. toctree:: - :caption: Segmentation - :maxdepth: 2 - - segmentation - segmentation_parameters - segmentation_output - features_without_segmented_area - transform_segmentation - -.. toctree:: - :caption: Tracking - :maxdepth: 2 - linking - tracking_output - .. toctree:: - :caption: Merge/Split :maxdepth: 2 + :hidden: - merge_split - + getting_started/index + examples/index + userguide/index + developer_guide/index -.. toctree:: - :caption: Developer guide - :maxdepth: 3 - - code_structure - contributing - code_reviews - mentoring - -.. toctree:: - :caption: Compute bulk statistics - :maxdepth: 2 - bulk_statistics/index .. toctree:: :caption: API Reference :maxdepth: 3 + :hidden: tobac diff --git a/doc/tobac.rst b/doc/tobac.rst index 5e651222..667d4157 100644 --- a/doc/tobac.rst +++ b/doc/tobac.rst @@ -1,4 +1,4 @@ -tobac package +API Documentation ============= Submodules diff --git a/doc/analysis.rst b/doc/userguide/analysis.rst similarity index 75% rename from doc/analysis.rst rename to doc/userguide/analysis.rst index 7c13966f..34074650 100644 --- a/doc/analysis.rst +++ b/doc/userguide/analysis.rst @@ -1,7 +1,5 @@ -.. - Documentation of analysis functions - TODO: include descriptions of the analysis functions and examples +.. _analysis-functions: Analysis -========= +======== tobac provides several analysis functions that allow for the calculation of important quantities based on the tracking results. This includes the calculation of properties such as feature lifetimes and feature areas/volumes, but also allows for a convenient calculation of statistics for arbitrary fields of the same shape as as the input data used for the tracking analysis. diff --git a/doc/big_datasets.rst b/doc/userguide/big_datasets.rst similarity index 97% rename from doc/big_datasets.rst rename to doc/userguide/big_datasets.rst index bac60e83..c6ddb49a 100644 --- a/doc/big_datasets.rst +++ b/doc/userguide/big_datasets.rst @@ -1,3 +1,5 @@ +.. _handling-big-datasets: + Handling Large Datasets ------------------------------------- diff --git a/doc/bulk_statistics/index.rst b/doc/userguide/bulk_statistics/index.rst similarity index 97% rename from doc/bulk_statistics/index.rst rename to doc/userguide/bulk_statistics/index.rst index 2560e3bb..461cd45b 100644 --- a/doc/bulk_statistics/index.rst +++ b/doc/userguide/bulk_statistics/index.rst @@ -1,3 +1,5 @@ +.. _bulk-statistics: + ########################## Compute bulk statistics ########################## diff --git a/doc/bulk_statistics/notebooks/compute_statistics_during_feature_detection.ipynb b/doc/userguide/bulk_statistics/notebooks/compute_statistics_during_feature_detection.ipynb similarity index 100% rename from doc/bulk_statistics/notebooks/compute_statistics_during_feature_detection.ipynb rename to doc/userguide/bulk_statistics/notebooks/compute_statistics_during_feature_detection.ipynb diff --git a/doc/bulk_statistics/notebooks/compute_statistics_during_segmentation.ipynb b/doc/userguide/bulk_statistics/notebooks/compute_statistics_during_segmentation.ipynb similarity index 100% rename from doc/bulk_statistics/notebooks/compute_statistics_during_segmentation.ipynb rename to doc/userguide/bulk_statistics/notebooks/compute_statistics_during_segmentation.ipynb diff --git a/doc/bulk_statistics/notebooks/compute_statistics_postprocessing_example.ipynb b/doc/userguide/bulk_statistics/notebooks/compute_statistics_postprocessing_example.ipynb similarity index 100% rename from doc/bulk_statistics/notebooks/compute_statistics_postprocessing_example.ipynb rename to doc/userguide/bulk_statistics/notebooks/compute_statistics_postprocessing_example.ipynb diff --git a/doc/feature_detection/index.rst b/doc/userguide/feature_detection/index.rst similarity index 100% rename from doc/feature_detection/index.rst rename to doc/userguide/feature_detection/index.rst diff --git a/doc/feature_detection/notebooks/feature_detection_filtering.ipynb b/doc/userguide/feature_detection/notebooks/feature_detection_filtering.ipynb similarity index 100% rename from doc/feature_detection/notebooks/feature_detection_filtering.ipynb rename to doc/userguide/feature_detection/notebooks/feature_detection_filtering.ipynb diff --git a/doc/feature_detection/notebooks/multiple_thresholds_example.ipynb b/doc/userguide/feature_detection/notebooks/multiple_thresholds_example.ipynb similarity index 100% rename from doc/feature_detection/notebooks/multiple_thresholds_example.ipynb rename to doc/userguide/feature_detection/notebooks/multiple_thresholds_example.ipynb diff --git a/doc/feature_detection/notebooks/n_min_threshold_example.ipynb b/doc/userguide/feature_detection/notebooks/n_min_threshold_example.ipynb similarity index 100% rename from doc/feature_detection/notebooks/n_min_threshold_example.ipynb rename to doc/userguide/feature_detection/notebooks/n_min_threshold_example.ipynb diff --git a/doc/feature_detection/notebooks/position_threshold_example.ipynb b/doc/userguide/feature_detection/notebooks/position_threshold_example.ipynb similarity index 100% rename from doc/feature_detection/notebooks/position_threshold_example.ipynb rename to doc/userguide/feature_detection/notebooks/position_threshold_example.ipynb diff --git a/doc/feature_detection_3D_out_vars.csv b/doc/userguide/feature_detection_3D_out_vars.csv similarity index 100% rename from doc/feature_detection_3D_out_vars.csv rename to doc/userguide/feature_detection_3D_out_vars.csv diff --git a/doc/feature_detection_base_out_vars.csv b/doc/userguide/feature_detection_base_out_vars.csv similarity index 100% rename from doc/feature_detection_base_out_vars.csv rename to doc/userguide/feature_detection_base_out_vars.csv diff --git a/doc/feature_detection_output.rst b/doc/userguide/feature_detection_output.rst similarity index 71% rename from doc/feature_detection_output.rst rename to doc/userguide/feature_detection_output.rst index 122fd720..274d901c 100644 --- a/doc/feature_detection_output.rst +++ b/doc/userguide/feature_detection_output.rst @@ -1,3 +1,5 @@ +.. _feature-detection-output: + Feature Detection Output ------------------------- @@ -5,19 +7,19 @@ Feature detection outputs a `pandas` dataframe with several variables. The varia Variables that are common to all feature detection files: -.. csv-table:: tobac Feature Detection Output Variables +.. csv-table:: `tobac` Feature Detection Output Variables :file: ./feature_detection_base_out_vars.csv :widths: 3, 35, 3, 3 :header-rows: 1 Variables that are included when using 3D feature detection in addition to those above: -.. csv-table:: tobac 3D Feature Detection Output Variables +.. csv-table:: `tobac` 3D Feature Detection Output Variables :file: ./feature_detection_3D_out_vars.csv :widths: 3, 35, 3, 3 :header-rows: 1 -One can optionally get the bulk statistics of the data points belonging to each feature regiion or volume. This is done using the `statistics` parameter when calling :ufunc:`tobac.feature_detection_multithreshold` . The user-defined metrics are then added as columns to the output dataframe. +One can optionally get the bulk statistics of the data points belonging to each feature region or volume. This is done using the `statistics` parameter when calling :ufunc:`tobac.feature_detection_multithreshold` . The user-defined metrics are then added as columns to the output dataframe. diff --git a/doc/features_without_segmented_area.rst b/doc/userguide/features_without_segmented_area.rst similarity index 94% rename from doc/features_without_segmented_area.rst rename to doc/userguide/features_without_segmented_area.rst index aa02f4e1..d2adca49 100644 --- a/doc/features_without_segmented_area.rst +++ b/doc/userguide/features_without_segmented_area.rst @@ -1,3 +1,5 @@ +.. _features-without-segmented-area: + Features without segmented areas -------------------------------------- @@ -16,7 +18,7 @@ If the segmentation threshold is lower (assuming `target='minimum'`) than the hi Consider for example the following data with 5 being the highest threshold specified for the Feature Detection (see :doc:`feature_detection_overview`): - .. image:: images/features_without_segment.png + .. image:: ./images/features_without_segment.png :width: 500 px If the segmentation threshold is larger than 5 (e.g. `threshold = 6`), the segmented area contains all values <= 5 (still assuming `target='minimum'`), no matter if the detected feature has a threshold lower than 5 (upper panels) or if it is exactly equal to 5 and does not contain any features with lower thresholds inside (lower panels). @@ -32,7 +34,7 @@ Case 2: Feature position Another reason for features that do not have a segmented area associated with them is the rare but possible case when the feature position is located outside of the threshold area: - .. image:: images/feature_outside_of_threshold_area.png + .. image:: ./images/feature_outside_of_threshold_area.png :width: 500 px diff --git a/doc/images/box_vs_column_seeding.png b/doc/userguide/images/box_vs_column_seeding.png similarity index 100% rename from doc/images/box_vs_column_seeding.png rename to doc/userguide/images/box_vs_column_seeding.png diff --git a/doc/images/feature_outside_of_threshold_area.png b/doc/userguide/images/feature_outside_of_threshold_area.png similarity index 100% rename from doc/images/feature_outside_of_threshold_area.png rename to doc/userguide/images/feature_outside_of_threshold_area.png diff --git a/doc/images/feature_outside_of_threshold_area_extreme.png b/doc/userguide/images/feature_outside_of_threshold_area_extreme.png similarity index 100% rename from doc/images/feature_outside_of_threshold_area_extreme.png rename to doc/userguide/images/feature_outside_of_threshold_area_extreme.png diff --git a/doc/images/features_without_segment.png b/doc/userguide/images/features_without_segment.png similarity index 100% rename from doc/images/features_without_segment.png rename to doc/userguide/images/features_without_segment.png diff --git a/doc/images/position_thresholds.png b/doc/userguide/images/position_thresholds.png similarity index 100% rename from doc/images/position_thresholds.png rename to doc/userguide/images/position_thresholds.png diff --git a/doc/images/sat_radar_combined.png b/doc/userguide/images/sat_radar_combined.png similarity index 100% rename from doc/images/sat_radar_combined.png rename to doc/userguide/images/sat_radar_combined.png diff --git a/doc/images/sigma_threshold_example.png b/doc/userguide/images/sigma_threshold_example.png similarity index 100% rename from doc/images/sigma_threshold_example.png rename to doc/userguide/images/sigma_threshold_example.png diff --git a/doc/userguide/index.rst b/doc/userguide/index.rst new file mode 100644 index 00000000..059c9034 --- /dev/null +++ b/doc/userguide/index.rst @@ -0,0 +1,21 @@ +########################## + User Guide +########################## + +.. toctree:: + :maxdepth: 3 + :hidden: + + feature_detection_output + threshold_detection_parameters + feature_detection/index + segmentation_output + segmentation_parameters + tracking_output + bulk_statistics/index + transform_segmentation + big_datasets + features_without_segmented_area + publications + analysis + diff --git a/doc/publications.rst b/doc/userguide/publications.rst similarity index 99% rename from doc/publications.rst rename to doc/userguide/publications.rst index 0a0d4776..712903ec 100644 --- a/doc/publications.rst +++ b/doc/userguide/publications.rst @@ -1,4 +1,4 @@ -.. _Refereed Publications: +.. _Refereed-Publications: Refereed Publications ===================== diff --git a/doc/segmentation_out_vars.csv b/doc/userguide/segmentation_out_vars.csv similarity index 100% rename from doc/segmentation_out_vars.csv rename to doc/userguide/segmentation_out_vars.csv diff --git a/doc/segmentation_out_vars_statistics.csv b/doc/userguide/segmentation_out_vars_statistics.csv similarity index 100% rename from doc/segmentation_out_vars_statistics.csv rename to doc/userguide/segmentation_out_vars_statistics.csv diff --git a/doc/segmentation_output.rst b/doc/userguide/segmentation_output.rst similarity index 98% rename from doc/segmentation_output.rst rename to doc/userguide/segmentation_output.rst index 2d4d46a1..2a91fee5 100644 --- a/doc/segmentation_output.rst +++ b/doc/userguide/segmentation_output.rst @@ -1,3 +1,5 @@ +.. _segmentation-output: + Segmentation Output ------------------------- diff --git a/doc/segmentation_parameters.rst b/doc/userguide/segmentation_parameters.rst similarity index 91% rename from doc/segmentation_parameters.rst rename to doc/userguide/segmentation_parameters.rst index 786bfb36..fa8d7bbf 100644 --- a/doc/segmentation_parameters.rst +++ b/doc/userguide/segmentation_parameters.rst @@ -1,3 +1,5 @@ +.. _segmentation-parameters: + Watershedding Segmentation Parameters ------------------------------------- @@ -8,7 +10,7 @@ A full list of parameters and descriptions can be found in the API Reference: :p ========================= Basic Operating Procedure ========================= -The *tobac* watershedding segmentation algorithm selects regions of the data :code:`field` with values greater than :code:`threshold` and associates those regions with the features :code:`features` detected by feature detection (see :doc:`feature_detection_overview`). This algorithm uses a *watershedding* approach, which sets the individual features as initial seed points, and then has identified regions grow from those original seed points. For further information on watershedding segmentation, see `the scikit-image documentation `_. +The *tobac* watershedding segmentation algorithm selects regions of the data :code:`field` with values greater than :code:`threshold` and associates those regions with the features :code:`features` detected by feature detection (see :doc:`../getting_started/feature_detection_overview`). This algorithm uses a *watershedding* approach, which sets the individual features as initial seed points, and then has identified regions grow from those original seed points. For further information on watershedding segmentation, see `the scikit-image documentation `_. Note that you can run the watershedding segmentation algorithm on any variable that shares a grid with the variable detected in the feature detection step. It is not required that the variable used in feature detection be the same as the one in segmentation (e.g., you can detect updraft features and then run segmentation on total condensate). @@ -58,7 +60,7 @@ When running feature detection on a 3D dataset and then using these detected fea **Box** seeding (:code:`seed_3D_flag='box'`) sets a cube or rectangular seed markers around the detected feature in 3D space. The marker size is user defined (in array coordinates) by :code:`seed_3D_size` as either an integer (for a cube) or a tuple of :code:`(int, int, int)`, ordered :code:`(vertical, hdim_1, hdim_2)`. Note that :code:`seed_3D_size` must be an odd number to avoid the box becoming biased to one side. If two seed boxes overlap, the seeded area is marked with the closest feature centroid. -.. figure:: images/box_vs_column_seeding.png +.. figure:: ./images/box_vs_column_seeding.png :scale: 50 % :alt: an example 3D plot showing column seeding linking features that should not be linked diff --git a/doc/threshold_detection_parameters.rst b/doc/userguide/threshold_detection_parameters.rst similarity index 90% rename from doc/threshold_detection_parameters.rst rename to doc/userguide/threshold_detection_parameters.rst index b69485e0..c9ff418c 100644 --- a/doc/threshold_detection_parameters.rst +++ b/doc/userguide/threshold_detection_parameters.rst @@ -8,7 +8,7 @@ A full list of parameters and descriptions can be found in the API Reference: :p ========================= Basic Operating Procedure ========================= -The *tobac* multiple threshold algorithm searches the input data (`field_in`) for contiguous regions of data greater than (with `target='maximum'`, see `Target`_) or less than (with `target='minimum'`) the selected thresholds (see `Thresholds`_). Contiguous regions (see `Minimum Threshold Number`_) are then identified as individual features, with a single point representing their location in the output (see `Position Threshold`_). Using this output (see :doc:`feature_detection_output`), segmentation (:doc:`segmentation`) and tracking (:doc:`linking`) can be run. +The *tobac* multiple threshold algorithm searches the input data (`field_in`) for contiguous regions of data greater than (with `target='maximum'`, see `Target`_) or less than (with `target='minimum'`) the selected thresholds (see `Thresholds`_). Contiguous regions (see `Minimum Threshold Number`_) are then identified as individual features, with a single point representing their location in the output (see `Position Threshold`_). Using this output (see :doc:`feature_detection_output`), segmentation (:doc:`segmentation_output`) and tracking (:doc:`tracking_output`) can be run. .. _Target: @@ -24,7 +24,7 @@ Thresholds ========== You can select to detect features on either one or multiple thresholds. The first threshold (or the single threshold) sets the minimum magnitude (either lowest value for :code:`target='maximum'` or highest value for :code:`target='minimum'`) that a feature can be detected on. For example, if you have a field made up of values lower than :code:`10`, and you set :code:`target='maximum', threshold=[10,]`, *tobac* will detect no features. The feature detection uses the threshold value in an inclusive way, which means that if you set :code:`target='maximum', threshold=[10,]` and your field does not only contain values lower than :code:`10`, it will include all values **greater than and equal to** :code:`10`. -Including *multiple* thresholds will allow *tobac* to refine the detection of features and detect multiple features that are connected through a contiguous region of less restrictive threshold values. You can see a conceptual diagram of that here: :doc:`feature_detection_overview`. To examine how setting different thresholds can change the number of features detected, see the example in this notebook: :doc:`feature_detection/notebooks/multiple_thresholds_example`. +Including *multiple* thresholds will allow *tobac* to refine the detection of features and detect multiple features that are connected through a contiguous region of less restrictive threshold values. You can see a conceptual diagram of that here: :doc:`../getting_started/feature_detection_overview`. To examine how setting different thresholds can change the number of features detected, see the example in this notebook: :doc:`./feature_detection/notebooks/multiple_thresholds_example`. .. _Minimum Threshold Number: @@ -32,16 +32,16 @@ Including *multiple* thresholds will allow *tobac* to refine the detection of fe ======================== Minimum Threshold Number ======================== -The minimum number of points per threshold, set by :code:`n_min_threshold`, determines how many contiguous pixels are required to be above the threshold for the feature to be detected. Setting this point very low can allow extraneous points to be detected as erroneous features, while setting this value too high will cause some real features to be missed. The default value for this parameter is :code:`0`, which will cause any values greater than the threshold after filtering to be identified as a feature. You can see a demonstration of the affect of increasing :code:`n_min_threshold` at: :doc:`feature_detection/notebooks/n_min_threshold_example`. +The minimum number of points per threshold, set by :code:`n_min_threshold`, determines how many contiguous pixels are required to be above the threshold for the feature to be detected. Setting this point very low can allow extraneous points to be detected as erroneous features, while setting this value too high will cause some real features to be missed. The default value for this parameter is :code:`0`, which will cause any values greater than the threshold after filtering to be identified as a feature. You can see a demonstration of the affect of increasing :code:`n_min_threshold` at: :doc:`./feature_detection/notebooks/n_min_threshold_example`. .. _Position Threshold: ================ Feature Position ================ -There are four ways of calculating the single point used to represent feature center: arithmetic center, extreme point, difference weighting, and absolute weighting. Generally, difference weighting (:code:`position_threshold='weighted_diff'`) or absolute weighting (:code:`position_threshold='weighted_abs'`) is suggested for most atmospheric applications. An example of these four methods is shown below, and can be further explored in the example notebook: :doc:`feature_detection/notebooks/position_threshold_example`. +There are four ways of calculating the single point used to represent feature center: arithmetic center, extreme point, difference weighting, and absolute weighting. Generally, difference weighting (:code:`position_threshold='weighted_diff'`) or absolute weighting (:code:`position_threshold='weighted_abs'`) is suggested for most atmospheric applications. An example of these four methods is shown below, and can be further explored in the example notebook: :doc:`./feature_detection/notebooks/position_threshold_example`. - .. image:: images/position_thresholds.png + .. image:: ./images/position_thresholds.png :width: 500 px .. _Filtering Options: @@ -51,7 +51,7 @@ Filtering Options ================= Before *tobac* detects features, two filtering options can optionally be employed. First is a multidimensional Gaussian Filter (`scipy.ndimage.gaussian_filter `_), with its standard deviation controlled by the :code:`sigma_threshold` parameter. It is not required that users use this filter (to turn it off, set :code:`sigma_threshold=0`), but the use of the filter is recommended for most atmospheric datasets that are not otherwise smoothed. An example of varying the :code:`sigma_threshold` parameter can be seen in the below figure, and can be explored in the example notebook: :doc:`feature_detection/notebooks/feature_detection_filtering`. - .. image:: images/sigma_threshold_example.png + .. image:: ./images/sigma_threshold_example.png :width: 500 px The second filtering option is a binary erosion (`skimage.morphology.binary_erosion `_), which reduces the size of features in all directions. The amount of the erosion is controlled by the :code:`n_erosion_threshold` parameter, with larger values resulting in smaller potential features. It is not required to use this feature (to turn it off, set :code:`n_erosion_threshold=0`), and its use should be considered alongside careful selection of :code:`n_min_threshold`. The default value is :code:`n_erosion_threshold=0`. diff --git a/doc/tracking_base_out_vars.csv b/doc/userguide/tracking_base_out_vars.csv similarity index 100% rename from doc/tracking_base_out_vars.csv rename to doc/userguide/tracking_base_out_vars.csv diff --git a/doc/tracking_output.rst b/doc/userguide/tracking_output.rst similarity index 96% rename from doc/tracking_output.rst rename to doc/userguide/tracking_output.rst index 89e8d5b7..2553cf59 100644 --- a/doc/tracking_output.rst +++ b/doc/userguide/tracking_output.rst @@ -1,3 +1,5 @@ +.. _tracking-output: + Tracking Output ------------------------- diff --git a/doc/transform_segmentation.rst b/doc/userguide/transform_segmentation.rst similarity index 94% rename from doc/transform_segmentation.rst rename to doc/userguide/transform_segmentation.rst index 79478d1b..47cbfbb7 100644 --- a/doc/transform_segmentation.rst +++ b/doc/userguide/transform_segmentation.rst @@ -3,7 +3,7 @@ Track on one dataset, segment on another *tobac* also has the capability to combine datasets through :doc:`segmentation`, which includes the ability to track on one dataset (e.g., gridded radar data) and run segmentation on a different dataset *on a different grid* (e.g., satellite data). - .. image:: images/sat_radar_combined.png + .. image:: ./images/sat_radar_combined.png :width: 500 px To do this, users should first run :doc:`feature_detection_overview` with a dataset that contains latitude and longitude coordinates, such that they appear in the output dataframe from Feature Detection. Next, use :func:`tobac.utils.transform_feature_points` to transform the feature dataframe into the new coordinate system. Finally, use the output from :func:`tobac.utils.transform_feature_points` to run segmentation with the new data. This can be done with both 2D and 3D feature detection and segmentation. \ No newline at end of file diff --git a/examples/index.rst b/examples/index.rst new file mode 100644 index 00000000..86dc8ced --- /dev/null +++ b/examples/index.rst @@ -0,0 +1,32 @@ +Example Gallery +=============== +tobac is provided with a set of Jupyter notebooks that show examples of the application of tobac for different types of datasets. + + +.. nbgallery:: + :caption: Fundamentals of Detection and Tracking + + Test Blob in 2D <./Basics/Idealized-Case-1_Tracking-of-a-Test-Blob-in-2D> + Two crossing Blobs <./Basics/Idealized-Case-2_Two_crossing_Blobs.ipynb> + + On Feature Detection: Part 1 <./Basics/Methods-and-Parameters-for-Feature-Detection_Part_1.ipynb> + On Feature Detection: Part 2 <./Basics/Methods-and-Parameters-for-Feature-Detection_Part_2.ipynb> + On Segmentation <./Basics/Methods-and-Parameters-for-Segmentation.ipynb> + On Linking <./Basics/Methods-and-Parameters-for-Linking.ipynb> + + +.. nbgallery:: + :caption: Examples of Using tobac with Observations + + OLR from GOES-13 Satellite <./Example_OLR_Tracking_satellite/Example_OLR_Tracking_satellite> + Combine Radar & Satellite <./Example_Track_on_Radar_Segment_on_Satellite/Example_Track_on_Radar_Segment_on_Satellite> + + +.. nbgallery:: + :caption: Examples of Using tobac with Model Data + + WRF OLR <./Example_OLR_Tracking_model/Example_OLR_Tracking_model> + WRF Precip <./Example_Precip_Tracking/Example_Precip_Tracking> + WRF Updrafts <./Example_Updraft_Tracking/Example_Updraft_Tracking> + WRF Mesoscale Vorticity <./Example_vorticity_tracking_model/Example_vorticity_tracking_model> + From e786d22f0f7cae066ff97de22c630e085589c13a Mon Sep 17 00:00:00 2001 From: Sean Freeman Date: Fri, 15 Nov 2024 11:54:21 -0700 Subject: [PATCH 2/8] add pydata as a documentation requirement --- doc/requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/requirements.txt b/doc/requirements.txt index 550ba3d6..443a0ccd 100644 --- a/doc/requirements.txt +++ b/doc/requirements.txt @@ -3,3 +3,4 @@ nbsphinx numpy sphinx_rtd_theme sphinx-gallery +pydata_sphinx_theme \ No newline at end of file From 9f8c0c0b580822f2f2650b012de5e72ae32c9268 Mon Sep 17 00:00:00 2001 From: Sean Freeman Date: Thu, 12 Dec 2024 09:43:53 -0600 Subject: [PATCH 3/8] fixed some underlines --- doc/tobac.rst | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/doc/tobac.rst b/doc/tobac.rst index 667d4157..2749395c 100644 --- a/doc/tobac.rst +++ b/doc/tobac.rst @@ -8,7 +8,7 @@ tobac.analysis module --------------------- tobac.analysis.cell_analysis module ---------------------- +----------------------------------- .. automodule:: tobac.analysis.cell_analysis :members: @@ -16,7 +16,7 @@ tobac.analysis.cell_analysis module :show-inheritance: tobac.analysis.feature_analysis module ---------------------- +-------------------------------------- .. automodule:: tobac.analysis.feature_analysis :members: @@ -24,7 +24,7 @@ tobac.analysis.feature_analysis module :show-inheritance: tobac.analysis.spatial module ---------------------- +----------------------------- .. automodule:: tobac.analysis.spatial :members: @@ -48,7 +48,7 @@ tobac.feature\_detection module :show-inheritance: tobac.merge_split module ---------------------- +------------------------ .. automodule:: tobac.merge_split :members: @@ -91,7 +91,7 @@ tobac.utils modules ------------------ tobac.utils.bulk_statistics module ------------------- +---------------------------------- .. automodule:: tobac.utils.bulk_statistics :members: @@ -99,7 +99,7 @@ tobac.utils.bulk_statistics module :show-inheritance: tobac.utils.decorators module ------------------- +----------------------------- .. automodule:: tobac.utils.decorators :members: @@ -107,7 +107,7 @@ tobac.utils.decorators module :show-inheritance: tobac.utils.general module ------------------- +-------------------------- .. automodule:: tobac.utils.general :members: @@ -115,7 +115,7 @@ tobac.utils.general module :show-inheritance: tobac.utils.mask module ------------------- +----------------------- .. automodule:: tobac.utils.mask :members: @@ -123,7 +123,7 @@ tobac.utils.mask module :show-inheritance: tobac.utils.periodic_boundaries module ------------------- +-------------------------------------- .. automodule:: tobac.utils.periodic_boundaries :members: From 0cecc402311158842721f07f60e6a14006b5385f Mon Sep 17 00:00:00 2001 From: Sean Freeman Date: Fri, 13 Dec 2024 08:46:16 -0600 Subject: [PATCH 4/8] updated homepage --- doc/_static/custom.css | 216 +++++++++++++++++++++++++++ doc/_static/theme_overrides.css | 7 + doc/conf.py | 7 + doc/developer_guide/index.rst | 2 + doc/index.md | 247 +++++++++++++++++++++++++++++++ doc/{index.rst => index_old.rst} | 0 doc/requirements.txt | 4 +- 7 files changed, 482 insertions(+), 1 deletion(-) create mode 100644 doc/_static/custom.css create mode 100644 doc/index.md rename doc/{index.rst => index_old.rst} (100%) diff --git a/doc/_static/custom.css b/doc/_static/custom.css new file mode 100644 index 00000000..d48a159b --- /dev/null +++ b/doc/_static/custom.css @@ -0,0 +1,216 @@ +/* Hero */ + + +#hero { + display: flex; + flex-direction: row; + min-height: min(calc(75vh), 1000px); /* Make hero fill up most of the page on load */ +} +#hero-left { + max-width: 476px; + width: 40%; + margin: auto 0; +} +#hero-right { + min-width: 476px; + width: 60%; + margin: auto 0; +} + +.homepage-button-container { + margin-bottom: 1rem; + display: flex; + flex-direction: column; +} +.homepage-button-container-row { + display: flex; + flex-wrap: wrap; +} + +.homepage-button-container a { + transition: 0.1s; +} +.homepage-button { + min-width: 142px; + padding: 0.5em 2em; + border: 1px solid var(--pst-color-primary); + border-radius: 4px; + margin: 1em 0.5em 0.5em 0; +} +.primary-button { + background-color: var(--pst-color-primary); + color: var(--pst-color-background) !important; +} +.secondary-button { + background-color: var(--pst-color-background); + color: var(--pst-color-primary); +} +.homepage-button:hover { + text-decoration: none; + background-color: var(--pst-color-secondary); + color: var(--pst-color-background); + border: 1px solid var(--pst-color-secondary); +} +.homepage-button-link { + text-decoration: underline; +} + +/* Key Features */ +#key-features .sd-card-body { + display: flex; +} +#key-features .sd-card img { + width: 140px; + height: 140px; +} +#key-features .sd-card-body .key-features-text { + min-width: 70%; + padding: 20px 10px; +} + +/* Sponsors */ +#sponsors-and-institutional-partners p { + text-align: center; +} +#sponsors-and-institutional-partners img { + max-width: 200px; +} + +/* Support ArviZ */ +#support-arviz .sd-col { + margin-bottom: 3rem; +} +#support-arviz p { + text-align: center; +} +.support-arviz-img-merch img { + height: 160px; +} +.support-arviz-img-donate img { + display: block; + width: 100%; + padding: 60px 40px 20px; +} +.support-arviz-img-donate-responsive img { + display: none; + margin: auto; + width: 80%; + min-width: 0px; + padding: 20px; +} + +/* Responsive */ +@media (max-width: 768px) { + #hero { + display: block; + } + #hero-left, + #hero-right { + width: 100%; + min-width: 0px; + } + .support-arviz-img-donate img { + display: none; + } + .support-arviz-img-donate-responsive img { + display: block; + } +} + +/* -------------------- HOMEPAGE + EXAMPLE GALLERY -------------------- */ + +/* Homepage - grid layout */ +.home-flex-grid { + display: flex; + flex-flow: row wrap; + justify-content: center; + gap: 10px; + padding: 20px 0px 40px; +} + +/* Homepage + Example Gallery Body - Set dimensions */ +.home-img-plot, +.bd-content div.sd-card.example-gallery .sd-card-body, +.home-img-plot-overlay, +.example-img-plot-overlay { + display: flex; + justify-content: center; + align-items: center; + overflow: hidden; + padding: 10px; +} +.home-img-plot, +.home-img-plot-overlay { + width: 235px; + height: 130px; +} +.bd-content div.sd-card.example-gallery .sd-card-body, +.example-img-plot-overlay { + width: 100%; + height: 150px; +} +.home-img-plot img, +.bd-content div.sd-card.example-gallery .sd-card-body img { + /* Images keep aspect ratio and fit in container */ + /* To make images stretch/fill container, change to min-width */ + max-width: 100%; + max-height: 100%; +} + +/* Homepage + Example Gallery Body - Set color and hover */ +.home-img-plot.img-thumbnail, +.bd-content div.sd-card.example-gallery .sd-card-body { + background-color: var(--pst-color-plot-background); /* Same as img-thumbnail from pydata css, adjusted for dark mode */ +} +.home-img-plot-overlay, +.example-img-plot-overlay, +.bd-content div.sd-card.example-gallery .sd-card-body { + border: 1px solid #dee2e6; /* Same as img-thumbnail from pydata css */ + border-radius: 0.25rem; /* Same as img-thumbnail from pydata css */ +} +.home-img-plot-overlay, +.example-img-plot-overlay, +.example-img-plot-overlay p.sd-card-text { + background: var(--pst-color-primary); + position: absolute; + color: var(--pst-color-background); + opacity: 0; + transition: .2s ease; + text-align: center; + padding: 10px; + z-index: 998; /* Make sure overlay is above image...this is here to handle dark mode */ +} +.home-img-plot-overlay:hover, +.bd-content div.sd-card.example-gallery:hover .example-img-plot-overlay, +.example-img-plot-overlay p.sd-card-text { + opacity: 90%; +} + +/* Example Gallery Body - Set syntax highlighting for code on hover */ +.example-img-plot-overlay .sd-card-text code.code { + background-color: var(--pst-color-background); +} +.example-img-plot-overlay .sd-card-text .code span.pre { + color: var(--pst-color-primary); + font-weight: 700; +} + +/* Example Gallery Footer - Plot titles goes here */ +.example-gallery .sd-card-footer { + height: 40px; + padding: 5px; + border-top: none !important; +} +.example-gallery .sd-card-footer p.sd-card-text { + color: var(--pst-color-text-muted); + font-size: 1rem; /* This is font size for plot titles (below the chart) */ + font-weight: 700; +} +.sd-card.example-gallery:hover .sd-card-footer p.sd-card-text { + color: var(--pst-color-primary); /* Change text color on hover over card */ +} + +/* Overlapping */ +.example-gallery a.sd-stretched-link.reference.external { + z-index: 999; /* Countermeasure where z-index = 998 */ +} diff --git a/doc/_static/theme_overrides.css b/doc/_static/theme_overrides.css index 83ca9fb8..3206cfd8 100644 --- a/doc/_static/theme_overrides.css +++ b/doc/_static/theme_overrides.css @@ -16,3 +16,10 @@ } } + +html[data-theme="dark"] { + /* tobac primary colors: #A2C2E5, #4D80BE, F6D94F*/ + --pst-color-primary: #4D80BE; + --pst-color-secondary: #F6D94F; +} + diff --git a/doc/conf.py b/doc/conf.py index 03e268f2..b03f342b 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -20,13 +20,19 @@ "sphinx.ext.napoleon", "nbsphinx", "sphinx_gallery.load_style", + "myst_parser", + "sphinx_design", ] html_theme = "pydata_sphinx_theme" html_static_path = ["_static"] +html_css_files = ["custom.css", "theme_overrides.css"] + exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] +source_suffix = {".rst": "restructuredtext", ".md": "restructuredtext"} +myst_enable_extensions = ["colon_fence"] html_theme_options = { @@ -59,6 +65,7 @@ # Include our custom CSS (currently for special table config) def setup(app): app.add_css_file("theme_overrides.css") + app.add_css_file("custom.css") # This should include all modules used in tobac. These are dummy imports, diff --git a/doc/developer_guide/index.rst b/doc/developer_guide/index.rst index 7b30d53d..5b81a38e 100644 --- a/doc/developer_guide/index.rst +++ b/doc/developer_guide/index.rst @@ -1,3 +1,5 @@ +.. _Developer-Guide: + ############################## Contributing ############################## diff --git a/doc/index.md b/doc/index.md new file mode 100644 index 00000000..5b9ff26f --- /dev/null +++ b/doc/index.md @@ -0,0 +1,247 @@ +--- +html_theme.sidebar_secondary.remove: +sd_hide_title: true +--- + + + + +(homepage)= +# tobac - Tracking and Object-Based Analysis of Clouds + +
+ +
+

tobac

+

Tracking atmospheric phenomena with your data

+

tobac is a package that identifies, tracks, and can be used for object-based analysis of atmospheric phenomena in model, observational, and remote sensing datasets.

+ + +
+ +
+ +::::::{grid} 2 +:gutter: 3 + +:::::{grid-item-card} +:link: /examples/Example_OLR_Tracking_satellite/Example_OLR_Tracking_satellite.html +:shadow: none +:class-card: example-gallery + +:::{div} example-img-plot-overlay +Track precipitating clouds with radar reflectivity +::: + +:::{image} ./images/Figure_linking.png +::: +::::: + +:::::{grid-item-card} +:link: /examples/Example_OLR_Tracking_satellite +:shadow: none +:class-card: example-gallery + +:::{div} example-img-plot-overlay +Forest Plot with ESS using `plot_forest` +::: + +:::{image} ./images/Figure_linking.png +::: +::::: + +:::::{grid-item-card} +:link: /examples/Example_OLR_Tracking_satellite +:shadow: none +:class-card: example-gallery + +:::{div} example-img-plot-overlay +Dist Plot using `plot_dist` +::: + +:::{image} ./images/Figure_linking.png +::: +::::: + +:::::{grid-item-card} +:link: /examples/Example_OLR_Tracking_satellite +:shadow: none +:class-card: example-gallery + +:::{div} example-img-plot-overlay +Density Plot (Comparison) using `plot_density` +::: + +:::{image} ./images/Figure_linking.png +::: +::::: + +:::::: + + + +
+
+ + + +# Key Features + +:::::{grid} 1 1 2 2 +:gutter: 5 + +::::{grid-item-card} +:shadow: none +:class-card: sd-border-0 + +:::{image} getting_started/images/cross.png +::: + +:::{div} key-features-text +Data Agnostic
+_tobac_ identifies and tracks atmospheric phenomena across different variables and different input datasets. + +::: +:::: + +::::{grid-item-card} +:shadow: none +:class-card: sd-border-0 + +:::{image} getting_started/images/cross.png +::: + +:::{div} key-features-text +Tracking in 2D and 3D
+_tobac_ tracks features in 2D spatial datasets or in 3D spatial datasets. +::: +:::: + +::::{grid-item-card} +:shadow: none +:class-card: sd-border-0 + +:::{image} getting_started/images/cross.png +::: + +:::{div} key-features-text +Fast
+_tobac_ is fast to start using, and runs quickly, even on large datasets +::: +:::: + +::::{grid-item-card} +:shadow: none +:class-card: sd-border-0 + +:::{image} getting_started/images/cross.png +::: + +:::{div} key-features-text +Flexible
+_tobac_ allows you to set _physical_ values to answer your science question +::: +:::: + +::::{grid-item-card} +:shadow: none +:class-card: sd-border-0 + +:::{image} getting_started/images/cross.png +::: + +:::{div} key-features-text +Built for Open Data
+With xarray and pandas support, _tobac_ data can be saved to be FAIR and compliant with open science principles. +::: +:::: + +::::{grid-item-card} +:shadow: none +:class-card: sd-border-0 + +:::{image} getting_started/images/cross.png +::: + +:::{div} key-features-text +Strong Heritage
+Used in a variety of projects and peer-reviewed publications and backed by a diverse international team. +::: +:::: +::::: + + +# *tobac* Use and Development + +::::{grid} 1 1 2 2 + +:::{grid-item} + +

Contributions

+ +Contributions and issue reports are very welcome at +[the GitHub repository](https://github.com/tobac-project/tobac). +We have a {ref}`developer guide ` to help you through the process. We also offer mentoring for new contributors; see the {ref}`developer guide ` for details. + +

Scientific Use

+ +_tobac_ has been used in over 30 peer-reviewed publications, a subset of which are listed on our {ref}`publications page `. + +::: +:::{grid-item} + +

Citation

+ +If you use *tobac* for scholarly work, please cite it using the software citation: [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.2577046.svg)](https://doi.org/10.5281/zenodo.2577046), the original paper: + +> Heikenfeld, M., Marinescu, P. J., Christensen, M., Watson-Parris, D., Senf, F., van den Heever, S. C., and Stier, P.: tobac 1.2: towards a flexible framework for tracking and analysis of clouds in diverse datasets, Geosci. Model Dev., 12, 4551–4570, https://doi.org/10.5194/gmd-12-4551-2019, 2019 + +or, if you are using features introduced from v1.5.0 or above, please also cite the v1.5.0 paper: +> Sokolowsky, G. A., Freeman, S. W., Jones, W. K., Kukulies, J., Senf, F., Marinescu, P. J., Heikenfeld, M., Brunner, K. N., Bruning, E. C., Collis, S. M., Jackson, R. C., Leung, G. R., Pfeifer, N., Raut, B. A., Saleeby, S. M., Stier, P., and van den Heever, S. C.: tobac v1.5: introducing fast 3D tracking, splits and mergers, and other enhancements for identifying and analysing meteorological phenomena, Geosci. Model Dev., 17, 5309–5330, https://doi.org/10.5194/gmd-17-5309-2024, 2024. + +::: + + +:::: + + + + +:::{toctree} +:maxdepth: 1 +:hidden: + +Getting Started +Example Gallery +User Guide +Developer Guide +API +::: \ No newline at end of file diff --git a/doc/index.rst b/doc/index_old.rst similarity index 100% rename from doc/index.rst rename to doc/index_old.rst diff --git a/doc/requirements.txt b/doc/requirements.txt index 443a0ccd..aa1a7bf6 100644 --- a/doc/requirements.txt +++ b/doc/requirements.txt @@ -3,4 +3,6 @@ nbsphinx numpy sphinx_rtd_theme sphinx-gallery -pydata_sphinx_theme \ No newline at end of file +pydata_sphinx_theme +myst-parser +sphinx-design \ No newline at end of file From 8e01602c58947a9cd772979c1c346b6a71a75662 Mon Sep 17 00:00:00 2001 From: Sean Freeman Date: Thu, 19 Dec 2024 10:13:58 -0600 Subject: [PATCH 5/8] updated API docs; deleted old homepage placeholder --- .gitignore | 1 + doc/_templates/autosummary/module.rst | 29 +++++ doc/api/index.rst | 25 +++++ doc/conf.py | 15 +++ doc/index.md | 4 +- doc/index_old.rst | 43 -------- doc/tobac.rst | 148 -------------------------- 7 files changed, 72 insertions(+), 193 deletions(-) create mode 100644 doc/_templates/autosummary/module.rst create mode 100644 doc/api/index.rst delete mode 100644 doc/index_old.rst delete mode 100644 doc/tobac.rst diff --git a/.gitignore b/.gitignore index 117e3485..99b639f1 100644 --- a/.gitignore +++ b/.gitignore @@ -11,4 +11,5 @@ examples/climate-processes-tobac_example_data-b3e69ee .ipynb_checkpoints .DS_Store *.egg-info +doc/api/generated/* diff --git a/doc/_templates/autosummary/module.rst b/doc/_templates/autosummary/module.rst new file mode 100644 index 00000000..76d1c8e1 --- /dev/null +++ b/doc/_templates/autosummary/module.rst @@ -0,0 +1,29 @@ +{{ fullname | escape | underline }} + +.. rubric:: Description + +.. automodule:: {{ fullname }} + +.. currentmodule:: {{ fullname }} + +{% if classes %} +.. rubric:: Classes + +.. autosummary:: + :toctree: . + {% for class in classes %} + {{ class }} + {% endfor %} + +{% endif %} + +{% if functions %} +.. rubric:: Functions + +.. autosummary:: + :toctree: . + {% for function in functions %} + {{ function }} + {% endfor %} + +{% endif %} \ No newline at end of file diff --git a/doc/api/index.rst b/doc/api/index.rst new file mode 100644 index 00000000..466d7847 --- /dev/null +++ b/doc/api/index.rst @@ -0,0 +1,25 @@ +.. _API-Reference: + +API Reference +============= + +:Release: |version| +:Date: |today| + +This guide provides documentation for all modules, function, methods, +and classes within *tobac* for those in the public API. + +Documentation is broken down by directory and module. + +.. currentmodule:: tobac + +.. autosummary:: + :toctree: generated/ + + feature_detection + tracking + segmentation + merge_split + utils.bulk_statistics + utils.general + plotting diff --git a/doc/conf.py b/doc/conf.py index b03f342b..b7bbada4 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -11,6 +11,7 @@ # What Sphinx extensions do we need extensions = [ "sphinx.ext.autodoc", + "sphinx.ext.autosummary", "sphinx.ext.doctest", "sphinx.ext.todo", "sphinx.ext.coverage", @@ -34,6 +35,20 @@ source_suffix = {".rst": "restructuredtext", ".md": "restructuredtext"} myst_enable_extensions = ["colon_fence"] +html_context = { + "api_dir": "api/generated", +} + + +# Generate the api documentation when building +autoclass_content = "both" + +autosummary_generate = True +autosummary_imported_members = True +autodoc_typehints = "description" + +templates_path = ["_templates"] + html_theme_options = { "logo": { diff --git a/doc/index.md b/doc/index.md index 5b9ff26f..e5e9ed23 100644 --- a/doc/index.md +++ b/doc/index.md @@ -2,7 +2,7 @@ html_theme.sidebar_secondary.remove: sd_hide_title: true --- - +