├── .github └── workflows │ └── lint.yml ├── LICENSES ├── LICENSE ├── napari-LICENSE └── widget-ts-cookiecutter-LICENSE ├── README.md ├── TODO ├── cookiecutter.json ├── imgs ├── releases1.png └── releases2.png └── {{cookiecutter.github_project_name}} ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── config.yml │ ├── documentation.md │ └── feature_request.md └── workflows │ ├── lint.yml │ ├── publish.yml │ └── test.yml ├── .gitignore ├── LICENSE ├── README.md ├── docs ├── API.rst ├── Contributing.rst ├── Makefile ├── _static │ └── images │ │ └── front-page-image.png ├── conf.py ├── index.rst └── make.bat ├── examples ├── README.rst └── example.py ├── pyproject.toml ├── readthedocs.yml ├── setup.cfg ├── setup.py └── {{cookiecutter.python_package_name}} ├── __init__.py ├── _version.py ├── example.py └── tests ├── __init__.py └── test_example.py /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: Lint 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | 9 | 10 | jobs: 11 | codespell: 12 | name: Check for spelling errors 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v2 16 | - uses: codespell-project/actions-codespell@master 17 | with: 18 | check_filenames: true 19 | -------------------------------------------------------------------------------- /LICENSES/LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2021, Ian Hunt-Isaak 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | -------------------------------------------------------------------------------- /LICENSES/napari-LICENSE: -------------------------------------------------------------------------------- 1 | The setup.cfg is heavily based on the version from Napari 2 | 3 | BSD 3-Clause License 4 | 5 | Copyright (c) 2018, Napari 6 | All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions are met: 10 | 11 | * Redistributions of source code must retain the above copyright notice, this 12 | list of conditions and the following disclaimer. 13 | 14 | * Redistributions in binary form must reproduce the above copyright notice, 15 | this list of conditions and the following disclaimer in the documentation 16 | and/or other materials provided with the distribution. 17 | 18 | * Neither the name of the copyright holder nor the names of its 19 | contributors may be used to endorse or promote products derived from 20 | this software without specific prior written permission. 21 | 22 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 23 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 25 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 26 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 28 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 29 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | -------------------------------------------------------------------------------- /LICENSES/widget-ts-cookiecutter-LICENSE: -------------------------------------------------------------------------------- 1 | For the parts of the cookiecutter taken from https://github.com/jupyter-widgets/widget-ts-cookiecutter 2 | 3 | Copyright (c) 2017 Project Jupyter Contributors 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Matplotlib 3rd Party Package Cookiecutter 2 | 3 | Turn your matplotlib scripts into a shareable python package using this 4 | [cookiecutter](https://cookiecutter.readthedocs.io/en/1.7.2/) recipe: 5 | 6 | ``` 7 | pip install cookiecutter 8 | cookiecutter gh:matplotlib/matplotlib-extension-cookiecutter 9 | ``` 10 | 11 | Add your code to `yourname/yourname/yourcode.py` and you can do 12 | ```python 13 | from yourname import yourcode 14 | ``` 15 | 16 | ## But why? 17 | 18 | Sharing your code on public distribution channels like PyPi requires some infrastructure in terms of setup files that take time and can be annoying to get right. The cookiecutter takes care of this for you, and also sets up a testing and documentation building environment: 19 | 20 | - Github actions work 21 | - Issue templates 22 | - Properly set up packaging 23 | - A setup for docs with: 24 | - `sphinx-gallery` 25 | - `autodoc` 26 | - The set up for `pytest-mpl` 27 | 28 | 29 | ## Building docs 30 | ``` 31 | cd docs 32 | make watch 33 | ``` 34 | 35 | ## Setting up readthedocs 36 | 37 | Readthedocs is a website that hosts the docs for many projects in the Python ecosystem. You can integrate them with your repo by following the instructions here: https://docs.readthedocs.io/en/stable/webhooks.html 38 | 39 | You can also have readthedocs make test builds on PRs by following the instructions here: https://docs.readthedocs.io/en/latest/pull-requests.html 40 | ## Setting up tests 41 | 42 | The best way to do testing for a Matplotlib extension is to use [pytest-mpl](https://github.com/matplotlib/pytest-mpl#about). This project includes a basic test, but does not pregenerate any baselines images. To make the example test work you first need to generate the baseline with: 43 | 44 | ``` 45 | pytest --mpl-generate-path=/tests/baseline 46 | ``` 47 | 48 | For full instructions see: https://github.com/matplotlib/pytest-mpl#using 49 | 50 | ## Publicizing your package 51 | 52 | Once you've made your package other people will likely want to use your hard work, and maybe even contribute to it! But for this to happen they need to know about it. The Matplotlib devs also want you to share your package and like to amplify your advertising. So some great steps to take in order to share your package are: 53 | 54 | 1. Make a PR to add it to Matplotlib's 3rd party packages page: 55 | - https://matplotlib.org/mpl-third-party/ 56 | 2. Tweet about your package and and mention `@matplotlib` for a retweet. 57 | 58 | 59 | ## Miscellaneous Advice 60 | 61 | Do not use Matplotlib private methods. If you really need the functionality then consider opening a feature request to have Matplotlib provide a public API for what you want. 62 | 63 | There is some discussion of how to use Matplotlib docstrings on discourse: https://discourse.matplotlib.org/t/docs-for-a-method-wrapping-a-matplotlib-method/21055 64 | 65 | https://colcarroll.github.io/yourplotlib/ is a great read for how to make an extension to Matplotlib. 66 | 67 | ## LICENSE Advice 68 | 69 | You may end up using portions of Matplotlib's code or copying docstrings when making a Matplotlib extension. 70 | 71 | As a practical rule: If you end up copying a non-trivial amount of code or docs the safest course of action is to add the Matplotlib license to your project as a derived work. For example see how Matplotlib does it https://github.com/matplotlib/matplotlib/tree/master/LICENSE. 72 | 73 | > But what counts as non-trivial? 74 | 75 | 76 | A good rule of thumb is to ask yourself: 77 | 78 | If it were homework and you didn't acknowledge would it be cheating? 79 | 80 | If the answer is yes, then you should leave a comment in the code and include a license file in a top level `LICENSE` folder. 81 | 82 | 83 | 84 | 85 | ## Releasing to PyPi 86 | ### Manually 87 | First set ensure you have the right packages installed: 88 | ``` 89 | pip install build twine 90 | ``` 91 | 92 | Then generate an `sdist` and a `wheel`: 93 | 94 | 1. bump version in `_version.py` 95 | 2. `git add <...>/_version.py` 96 | 3. `commit -m 'version bump'` 97 | 4. `git tag ` 98 | 5. `git push --tags` 99 | 6. `python -m build -s -w` 100 | 7. `twine upload dist/*` 101 | 102 | 103 | 104 | ### Using Github Actions 105 | If you use Github as your Git repository then you can also automate steps 4-7 by using the Github action included in the cookiecutter. 106 | 107 | To do this you will need to generate a PyPI api token and add it to your repository's secrets. 108 | 109 | **Generating an api token** 110 | 111 | Go to you [PyPI account settings](https://pypi.org/manage/account/), scroll down to the API tokens section and select "Add API token". 112 | 113 | **Adding api token to Github Secrets** 114 | Once you've have copied the token from PyPI go the `Secrets` section of your Github repo's settings and add the token with the name `PYPI_API_TOKEN` 115 | 116 | 117 | With that set up all you need to do to create a release is: 118 | 1. bump version in `_version.py` 119 | 2. `git add <...>/_version.py` 120 | 3. `git commit -m 'version bump' && git push` 121 | 4. Make a release using the github release tool. 122 | 123 | To make the release go the the `Releases` section in the repo sidebar: 124 | 125 | ![Arrow pointing to Releases section](imgs/releases1.png) 126 | 127 | then draft a new release: 128 | 129 | ![Arrow pointing to draft release button](imgs/releases2.png) 130 | 131 | After you fill out the information the Github action will create a new tag for you, build the wheel, and upload it to PyPI. 132 | 133 | 134 | 135 | ## Credit 136 | 137 | This cookiecutter is partially based on the following cookiecutters 138 | - https://github.com/jupyter-widgets/widget-ts-cookiecutter 139 | - The `setup.cfg` from https://github.com/napari/napari 140 | 141 | ---- 142 | Happy Plotting! 143 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | - MANIFEST.in 2 | - instructions in top level readme 3 | - pre-commit? -------------------------------------------------------------------------------- /cookiecutter.json: -------------------------------------------------------------------------------- 1 | { 2 | "author_name": "", 3 | "author_email": "", 4 | "github_organization_name": "", 5 | "github_project_name": "", 6 | "python_package_name": "{{ cookiecutter.github_project_name | replace('-', '_') }}", 7 | "project_short_description": "A 3rd party package for Matplotlib", 8 | "year": "2021", 9 | "_copy_without_render": [ 10 | ".github/workflows/*" 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /imgs/releases1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matplotlib/matplotlib-extension-cookiecutter/93486375b29bdef621de7f04109a0f00d6940b54/imgs/releases1.png -------------------------------------------------------------------------------- /imgs/releases2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matplotlib/matplotlib-extension-cookiecutter/93486375b29bdef621de7f04109a0f00d6940b54/imgs/releases2.png -------------------------------------------------------------------------------- /{{cookiecutter.github_project_name}}/.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 🐛 Bug Report 3 | about: Report a bug 4 | # based on matplotlib issue template 5 | --- 6 | 7 | 8 | 9 | 10 | ### Bug report 11 | 12 | **Bug summary** 13 | 14 | 15 | 16 | **Code for reproduction** 17 | 18 | 31 | 32 | **Expected outcome** 33 | 34 | 35 | 36 | 37 | **Version Info** 38 | 39 | * Operating system: 40 | * Matplotlib version: 41 | * Matplotlib backend (`print(matplotlib.get_backend())`): 42 | * Python version: 43 | * Jupyter version (if applicable): 44 | * Other libraries: 45 | -------------------------------------------------------------------------------- /{{cookiecutter.github_project_name}}/.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | # Ref: https://help.github.com/en/github/building-a-strong-community/configuring-issue-templates-for-your-repository#configuring-the-template-chooser 2 | blank_issues_enabled: true # default 3 | contact_links: 4 | - name: ❓ Question/Support/Other 5 | url: https://discourse.matplotlib.org/c/3rdparty/18 6 | about: If you have a usage question 7 | -------------------------------------------------------------------------------- /{{cookiecutter.github_project_name}}/.github/ISSUE_TEMPLATE/documentation.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 📖 Documentation improvement 3 | about: Report parts of the docs that are wrong or unclear 4 | labels: documentation, bug 5 | --- 6 | 7 | 8 | 9 | 10 | ### Problem 11 | 12 | 19 | 20 | 21 | ### Suggested Improvement 22 | 23 | 30 | -------------------------------------------------------------------------------- /{{cookiecutter.github_project_name}}/.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 🚀 Enhancement/Feature Request 3 | about: Suggest something that could be improved or a New Feature to add 4 | labels: enhancement 5 | --- 6 | 7 | 13 | 14 | ### Problem 15 | 16 | 21 | 22 | ### Proposed Solution 23 | 24 | 28 | 29 | ### Additional context 30 | 31 | 35 | 36 | -------------------------------------------------------------------------------- /{{cookiecutter.github_project_name}}/.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: Lint 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | 9 | jobs: 10 | lint: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v2 14 | - uses: actions/setup-python@v2 15 | - uses: psf/black@stable 16 | with: 17 | options: "--check" 18 | src: "." 19 | - name: docstrings 20 | run: | 21 | pip install flit 22 | pushd $(mktemp -d) 23 | git clone https://github.com/Carreau/velin.git --single-branch --depth 1 24 | cd velin 25 | flit install 26 | popd 27 | velin . --check 28 | -------------------------------------------------------------------------------- /{{cookiecutter.github_project_name}}/.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | # heavily based on https://github.com/jupyterlab/jupyterlab-git/blob/v0.22.2/.github/workflows/publish.yml 2 | name: Publish Package 3 | 4 | on: 5 | release: 6 | types: [published] 7 | 8 | 9 | jobs: 10 | deploy: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v2 14 | - name: Install Python 15 | uses: actions/setup-python@v2 16 | with: 17 | python-version: '3.x' 18 | - name: Install dependencies 19 | run: | 20 | python -m pip install --upgrade pip 21 | pip install packaging setuptools twine wheel build 22 | - name: Publish the Python package 23 | env: 24 | TWINE_USERNAME: __token__ 25 | TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }} 26 | run: | 27 | python -m build -s -w 28 | twine upload dist/* 29 | -------------------------------------------------------------------------------- /{{cookiecutter.github_project_name}}/.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | schedule: 9 | - cron: "0 16 * * 1" # monday at noon est 10 | 11 | jobs: 12 | test: 13 | name: Python ${{ matrix.python-version }} - mpl ${{ matrix.mpl-version }} 14 | runs-on: ubuntu-latest 15 | strategy: 16 | matrix: 17 | python-version: ['3.8.x', '3.9.x'] 18 | mpl-version: ['3.4', 'latest'] 19 | steps: 20 | - name: Checkout 21 | uses: actions/checkout@v2 22 | 23 | - name: Setup Python ${{ matrix.python-version }} 24 | uses: actions/setup-python@v2 25 | with: 26 | python-version: ${{ matrix.python-version }} 27 | architecture: 'x64' 28 | 29 | - name: Get pip cache dir 30 | id: pip-cache 31 | run: | 32 | echo "::set-output name=dir::$(pip cache dir)" 33 | 34 | - name: pip cache 35 | uses: actions/cache@v2 36 | with: 37 | path: ${{ steps.pip-cache.outputs.dir }} 38 | key: ${{ runner.os }}-pip-${{ matrix.python-version }}-${{ hashFiles('**/setup.py') }} 39 | restore-keys: | 40 | ${{ runner.os }}-pip-${{ matrix.python-version }}- 41 | ${{ runner.os }}-pip- 42 | 43 | - if: matrix.mpl-version=='latest' 44 | name: Install dev Matplotlib 45 | run: pip install git+https://github.com/matplotlib/matplotlib.git 46 | 47 | - if: matrix.mpl-version!='latest' 48 | name: Install matplotlib pinned 49 | run: pip install --upgrade --pre --index-url https://pypi.anaconda.org/scipy-wheels-nightly/simple --extra-index-url https://pypi.org/simple matplotlib 50 | 51 | - name: Install 52 | run: | 53 | pip install ".[test]" 54 | 55 | - name: Tests 56 | run: | 57 | pytest --mpl --color=yes 58 | -------------------------------------------------------------------------------- /{{cookiecutter.github_project_name}}/.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | share/python-wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | MANIFEST 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .nox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *.cover 49 | *.py,cover 50 | .hypothesis/ 51 | .pytest_cache/ 52 | cover/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | .pybuilder/ 76 | target/ 77 | 78 | # Jupyter Notebook 79 | .ipynb_checkpoints 80 | 81 | # IPython 82 | profile_default/ 83 | ipython_config.py 84 | 85 | # pyenv 86 | # For a library or package, you might want to ignore these files since the code is 87 | # intended to run in multiple environments; otherwise, check them in: 88 | # .python-version 89 | 90 | # pipenv 91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 94 | # install all needed dependencies. 95 | #Pipfile.lock 96 | 97 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 98 | __pypackages__/ 99 | 100 | # Celery stuff 101 | celerybeat-schedule 102 | celerybeat.pid 103 | 104 | # SageMath parsed files 105 | *.sage.py 106 | 107 | # Environments 108 | .env 109 | .venv 110 | env/ 111 | venv/ 112 | ENV/ 113 | env.bak/ 114 | venv.bak/ 115 | 116 | # Spyder project settings 117 | .spyderproject 118 | .spyproject 119 | 120 | # Rope project settings 121 | .ropeproject 122 | 123 | # mkdocs documentation 124 | /site 125 | 126 | # mypy 127 | .mypy_cache/ 128 | .dmypy.json 129 | dmypy.json 130 | 131 | # Pyre type checker 132 | .pyre/ 133 | 134 | # pytype static type analyzer 135 | .pytype/ 136 | 137 | # Cython debug symbols 138 | cython_debug/ 139 | 140 | # mac stuff 141 | .DS_store 142 | 143 | # editors 144 | 145 | ## vim 146 | [._]*.s[a-v][a-z] 147 | !*.svg # comment out if you don't need vector files 148 | [._]*.sw[a-p] 149 | [._]s[a-rt-v][a-z] 150 | [._]ss[a-gi-z] 151 | [._]sw[a-p] 152 | [._]*.un~ 153 | 154 | ## vscode 155 | .vscode -------------------------------------------------------------------------------- /{{cookiecutter.github_project_name}}/LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) {{ cookiecutter.year }}, {{ cookiecutter.author_name }} 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its contributors 17 | may be used to endorse or promote products derived from this software 18 | without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /{{cookiecutter.github_project_name}}/README.md: -------------------------------------------------------------------------------- 1 | # {{ cookiecutter.github_project_name }} 2 | 3 | {{ cookiecutter.project_short_description }} 4 | 5 | ## Installation 6 | 7 | You can install using `pip`: 8 | 9 | ```bash 10 | pip install {{ cookiecutter.python_package_name }} 11 | ``` 12 | 13 | ## Development Installation 14 | 15 | 16 | ```bash 17 | pip install -e ".[dev]" 18 | ``` 19 | 20 | -------------------------------------------------------------------------------- /{{cookiecutter.github_project_name}}/docs/API.rst: -------------------------------------------------------------------------------- 1 | === 2 | API 3 | === 4 | 5 | Example Module 6 | --------------- 7 | 8 | The example module just contains one function - which is just an example 9 | function to extend matplotlib functionality. 10 | 11 | .. currentmodule:: {{ cookiecutter.python_package_name}}.example 12 | .. autosummary:: 13 | :toctree: autoapi 14 | :nosignatures: 15 | :recursive: 16 | 17 | example_function 18 | -------------------------------------------------------------------------------- /{{cookiecutter.github_project_name}}/docs/Contributing.rst: -------------------------------------------------------------------------------- 1 | ============ 2 | Contributing 3 | ============ 4 | 5 | Thanks for thinking of a way to help improve this library! Remember that contributions come in all 6 | shapes and sizes beyond writing bug fixes. Contributing to documentation, opening new `issues `_, 7 | asking for clarification on things you find unclear, and requesting new features, are all super valuable contributions. 8 | 9 | Code Improvements 10 | ----------------- 11 | 12 | All development for this library happens at https://github.com/{{ cookiecutter.github_organization_name }}/{{ cookiecutter.github_project_name }}, 13 | 14 | First set up a dev environment. The instructions here use `mamba `_ which is open source 15 | implementation of `conda` that offers significant speed ups. You can substitute ``conda`` for ``mamba`` or use ``venv`` without any ill-effects. 16 | 17 | .. code-block:: bash 18 | 19 | mamba create -n {{ cookiecutter.python_package_name}}-dev python 20 | conda activate {{ cookiecutter.python_package_name}}-dev 21 | 22 | Now clone your fork of the Git repository and make an editable (``-e``) install. 23 | 24 | .. code-block:: bash 25 | 26 | git clone 27 | cd {{ cookiecutter.github_project_name }} 28 | pip install -e ".[dev]" 29 | 30 | 31 | Working with Git 32 | ^^^^^^^^^^^^^^^^ 33 | 34 | Using Git/Github can confusing (https://xkcd.com/1597/) so if you're new to Git, you may find 35 | it helpful to use a program like `Github Desktop `_ and to follow 36 | a `guide `_. 37 | 38 | Also feel free to ask for help/advice on the relevant Github `issue `_. 39 | 40 | Documentation 41 | ------------- 42 | 43 | Following changes to the source files, you can view recent adjustments by building the documentation. 44 | 45 | 1. Make sure you have installed the requirements for building the documentation: 46 | 47 | .. code-block:: bash 48 | 49 | cd {{ cookiecutter.github_project_name }} 50 | pip install -e ".[doc]" 51 | 52 | 2. Run the following commands: 53 | 54 | .. code-block:: bash 55 | 56 | cd docs 57 | make html 58 | 59 | If you open the ``_build/html/index.html`` file in your browser you should now be able to see the rendered documentation. 60 | 61 | Autobuild the documentation 62 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ 63 | 64 | Alternatively, you can use `sphinx-autobuild `_ to continuously watch the documentation for changes and rebuild it for you. 65 | Sphinx-autobuild will be installed automatically by the above ``pip`` command, and we've added it to the ``Makefile``. All you need to do is: 66 | 67 | .. code-block:: bash 68 | 69 | cd docs 70 | make watch 71 | 72 | In a few seconds your web browser should open up the documentation. Now whenever you save a file 73 | the documentation will automatically regenerate and the webpage will refresh for you! 74 | -------------------------------------------------------------------------------- /{{cookiecutter.github_project_name}}/docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = . 9 | BUILDDIR = _build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | watch: 18 | sphinx-autobuild . _build/html --open-browser --watch ../examples 19 | 20 | # Catch-all target: route all unknown targets to Sphinx using the new 21 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 22 | %: Makefile 23 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) -------------------------------------------------------------------------------- /{{cookiecutter.github_project_name}}/docs/_static/images/front-page-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matplotlib/matplotlib-extension-cookiecutter/93486375b29bdef621de7f04109a0f00d6940b54/{{cookiecutter.github_project_name}}/docs/_static/images/front-page-image.png -------------------------------------------------------------------------------- /{{cookiecutter.github_project_name}}/docs/conf.py: -------------------------------------------------------------------------------- 1 | # Configuration file for the Sphinx documentation builder. 2 | # 3 | # This file only contains a selection of the most common options. For a full 4 | # list see the documentation: 5 | # https://www.sphinx-doc.org/en/master/usage/configuration.html 6 | 7 | # -- Path setup -------------------------------------------------------------- 8 | 9 | # If extensions (or modules to document with autodoc) are in another directory, 10 | # add these directories to sys.path here. If the directory is relative to the 11 | # documentation root, use os.path.abspath to make it absolute, like shown here. 12 | # 13 | import os 14 | import sys 15 | 16 | sys.path.insert(0, os.path.abspath('../{{ cookiecutter.python_package_name }}')) 17 | 18 | 19 | # -- Project information ----------------------------------------------------- 20 | 21 | project = '{{ cookiecutter.python_package_name }}' 22 | copyright = '{{ cookiecutter.year }}, {{ cookiecutter.author_name }}' 23 | author = '{{ cookiecutter.author_name }}' 24 | 25 | # The full version, including alpha/beta/rc tags 26 | from _version import __version__ as release 27 | 28 | 29 | # -- General configuration --------------------------------------------------- 30 | 31 | # Add any Sphinx extension module names here, as strings. They can be 32 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 33 | # ones. 34 | extensions = [ 35 | "sphinx_copybutton", 36 | "sphinx_gallery.gen_gallery", 37 | "sphinx.ext.napoleon", 38 | "numpydoc", 39 | 'sphinx.ext.autodoc', 40 | 'sphinx.ext.inheritance_diagram', 41 | 'autoapi.sphinx', 42 | ] 43 | 44 | sphinx_gallery_conf = { 45 | "examples_dirs": "../examples", # path to your example scripts 46 | "gallery_dirs": "examples", # path to where to save gallery generated output 47 | "filename_pattern": "/.*", 48 | "ignore_pattern": "/_.*", # https://www.debuggex.com/ 49 | } 50 | 51 | 52 | # Add any paths that contain templates here, relative to this directory. 53 | templates_path = ['_templates'] 54 | 55 | # List of patterns, relative to source directory, that match files and 56 | # directories to ignore when looking for source files. 57 | # This pattern also affects html_static_path and html_extra_path. 58 | exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] 59 | 60 | 61 | # -- Options for HTML output ------------------------------------------------- 62 | 63 | # The theme to use for HTML and HTML Help pages. See the documentation for 64 | # a list of builtin themes. 65 | # 66 | html_theme = 'alabaster' 67 | 68 | # Add any paths that contain custom static files (such as style sheets) here, 69 | # relative to this directory. They are copied after the builtin static files, 70 | # so a file named "default.css" will overwrite the builtin "default.css". 71 | html_static_path = ['_static'] 72 | -------------------------------------------------------------------------------- /{{cookiecutter.github_project_name}}/docs/index.rst: -------------------------------------------------------------------------------- 1 | Welcome to {{ cookiecutter.python_package_name }}'s documentation! 2 | =================================================================== 3 | 4 | A library makes for making awesome plots like this one: 5 | 6 | .. image:: _static/images/front-page-image.png 7 | 8 | 9 | Installation 10 | ^^^^^^^^^^^^^ 11 | 12 | .. code-block:: bash 13 | 14 | pip install {{ cookiecutter.python_package_name }} 15 | 16 | Getting Help 17 | ^^^^^^^^^^^^ 18 | 19 | If you have a question on how to do something with ``{{ cookiecutter.python_package_name }}`` a great place 20 | to ask it is: https://discourse.matplotlib.org/c/3rdparty/18. 21 | 22 | 23 | .. toctree:: 24 | :maxdepth: 3 25 | 26 | examples/index 27 | API 28 | Contributing 29 | 30 | 31 | 32 | Indices and tables 33 | ================== 34 | 35 | * :ref:`genindex` 36 | * :ref:`modindex` 37 | * :ref:`search` 38 | -------------------------------------------------------------------------------- /{{cookiecutter.github_project_name}}/docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=. 11 | set BUILDDIR=_build 12 | 13 | if "%1" == "" goto help 14 | 15 | %SPHINXBUILD% >NUL 2>NUL 16 | if errorlevel 9009 ( 17 | echo. 18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 19 | echo.installed, then set the SPHINXBUILD environment variable to point 20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 21 | echo.may add the Sphinx directory to PATH. 22 | echo. 23 | echo.If you don't have Sphinx installed, grab it from 24 | echo.http://sphinx-doc.org/ 25 | exit /b 1 26 | ) 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /{{cookiecutter.github_project_name}}/examples/README.rst: -------------------------------------------------------------------------------- 1 | --------------- 2 | Example Gallery 3 | --------------- 4 | 5 | Some explanatory text. See https://sphinx-gallery.github.io/stable/index.html for how to configure this page. 6 | -------------------------------------------------------------------------------- /{{cookiecutter.github_project_name}}/examples/example.py: -------------------------------------------------------------------------------- 1 | """ 2 | ------------ 3 | Example Name 4 | ------------ 5 | 6 | A short example showcasing how to use the library. The docstrings will be 7 | converted to RST by sphinx-gallery. 8 | """ 9 | 10 | import numpy as np 11 | import matplotlib.pyplot as plt 12 | from {{ cookiecutter.python_package_name }} import example_function 13 | 14 | 15 | # make some fake data 16 | rng = np.random.default_rng(0) 17 | data = rng.standard_normal((1000, 2)) 18 | 19 | fig, ax = plt.subplots() 20 | scatter = example_function(ax, data, above_color='b') 21 | plt.show() 22 | -------------------------------------------------------------------------------- /{{cookiecutter.github_project_name}}/pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.black] 2 | skip-string-normalization = true 3 | 4 | [tool.pytest.ini_options] 5 | testpaths = [ 6 | "{{ cookiecutter.python_package_name }}/tests" 7 | ] 8 | 9 | [build-system] 10 | requires = ["setuptools>=42", "wheel"] 11 | build-backend = "setuptools.build_meta" 12 | -------------------------------------------------------------------------------- /{{cookiecutter.github_project_name}}/readthedocs.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | python: 3 | version: 3.8 4 | install: 5 | - method: pip 6 | path: . 7 | extra_requirements: 8 | - doc 9 | 10 | # Build documentation in the docs/ directory with Sphinx 11 | sphinx: 12 | configuration: docs/conf.py 13 | 14 | -------------------------------------------------------------------------------- /{{cookiecutter.github_project_name}}/setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | name={{ cookiecutter.python_package_name }} 3 | author={{ cookiecutter.author_name }} 4 | author_email={{ cookiecutter.author_email }} 5 | url = https://github.com/{{ cookiecutter.github_organization_name }}/{{ cookiecutter.github_project_name }} 6 | license=BSD 3-Clause 7 | long_description = file: README.md 8 | long_description_content_type = text/markdown 9 | 10 | [options] 11 | packages = find: 12 | 13 | install_requires = 14 | matplotlib 15 | 16 | classifiers = 17 | Intended Audience :: Developers 18 | Intended Audience :: Science/Research 19 | License :: OSI Approved :: BSD License 20 | Programming Language :: Python 21 | Programming Language :: Python :: 3 22 | Framework :: Matplotlib 23 | 24 | [options.extras_require] 25 | test = 26 | black 27 | pytest 28 | pytest-mpl 29 | doc = 30 | sphinx 31 | numpydoc 32 | sphinx_rtd_theme 33 | sphinx-copybutton 34 | sphinx-autobuild 35 | sphinx_gallery>=0.8.2 36 | autoapi 37 | dev = 38 | %(test)s 39 | %(doc)s 40 | -------------------------------------------------------------------------------- /{{cookiecutter.github_project_name}}/setup.py: -------------------------------------------------------------------------------- 1 | from os import path 2 | 3 | from setuptools import find_packages, setup 4 | 5 | # extract version 6 | path = path.realpath("{{ cookiecutter.python_package_name }}/_version.py") 7 | version_ns = {} 8 | with open(path, encoding="utf8") as f: 9 | exec(f.read(), {}, version_ns) 10 | version = version_ns["__version__"] 11 | 12 | setup_args = dict( 13 | version=version, 14 | ) 15 | 16 | if __name__ == "__main__": 17 | setup(**setup_args) 18 | -------------------------------------------------------------------------------- /{{cookiecutter.github_project_name}}/{{cookiecutter.python_package_name}}/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding: utf-8 3 | 4 | # Copyright (c) {{ cookiecutter.author_name }}. 5 | # Distributed under the terms of the Modified BSD License. 6 | 7 | # Must import __version__ first to avoid errors importing this file during the build process. 8 | # See https://github.com/pypa/setuptools/issues/1724#issuecomment-627241822 9 | from ._version import __version__ 10 | 11 | from .example import example_function 12 | -------------------------------------------------------------------------------- /{{cookiecutter.github_project_name}}/{{cookiecutter.python_package_name}}/_version.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding: utf-8 3 | 4 | # Copyright (c) {{ cookiecutter.author_name }}. 5 | # Distributed under the terms of the Modified BSD License. 6 | 7 | version_info = (0, 1, 0) 8 | __version__ = ".".join(map(str, version_info)) 9 | -------------------------------------------------------------------------------- /{{cookiecutter.github_project_name}}/{{cookiecutter.python_package_name}}/example.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding: utf-8 3 | 4 | # Copyright (c) {{ cookiecutter.author_name }}. 5 | # Distributed under the terms of the Modified BSD License. 6 | 7 | __all__ = [ 8 | "example_function", 9 | ] 10 | import numpy as np 11 | 12 | 13 | def example_function(ax, data, above_color="r", below_color="k", **kwargs): 14 | """ 15 | An example function that makes a scatter plot with points colored differently 16 | depending on if they are above or below `y=0`. 17 | 18 | Parameters 19 | ---------- 20 | ax : matplotlib axis 21 | The axis to plot on. 22 | data : (N, 2) array-like 23 | The data to make a plot from 24 | above_color : color-like, default: 'r' 25 | The color of points with `y>0` 26 | below_color : color-like, default: 'k' 27 | The color of points with `y<0` 28 | **kwargs 29 | Passed through to `ax.scatter` 30 | 31 | Returns 32 | ------- 33 | MarkerCollection 34 | """ 35 | colors = np.array([above_color] * data.shape[0]) 36 | colors[data[:, 1] < 0] = below_color 37 | return ax.scatter(data[:, 0], data[:, 1], c=colors, **kwargs) 38 | -------------------------------------------------------------------------------- /{{cookiecutter.github_project_name}}/{{cookiecutter.python_package_name}}/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matplotlib/matplotlib-extension-cookiecutter/93486375b29bdef621de7f04109a0f00d6940b54/{{cookiecutter.github_project_name}}/{{cookiecutter.python_package_name}}/tests/__init__.py -------------------------------------------------------------------------------- /{{cookiecutter.github_project_name}}/{{cookiecutter.python_package_name}}/tests/test_example.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding: utf-8 3 | 4 | # Copyright (c) {{ cookiecutter.author_name }}. 5 | # Distributed under the terms of the Modified BSD License. 6 | 7 | from ..example import example_function 8 | 9 | 10 | import pytest 11 | import matplotlib.pyplot as plt 12 | import numpy as np 13 | 14 | 15 | @pytest.mark.mpl_image_compare(filename="test_example.png") 16 | def test_example(): 17 | fig, ax = plt.subplots() 18 | # data = np.hstack([np.linspace(-10, 10)[:, None], np.linspace(10, -10)[:, None]]) 19 | example_function(ax, data, above_color='b', below_color='g') 20 | return fig 21 | --------------------------------------------------------------------------------