diff --git a/.appveyor.yml b/.appveyor.yml index 668c5391de65..10109c9f80f7 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -1,7 +1,7 @@ # With infos from # http://tjelvarolsson.com/blog/how-to-continuously-test-your-python-code-on-windows-using-appveyor/ # https://packaging.python.org/en/latest/appveyor/ -# https://github.com/rmcgibbo/python-appveyor-conda-example +--- # Backslashes in quotes need to be escaped: \ -> "\\" branches: @@ -9,109 +9,89 @@ branches: - /auto-backport-.*/ - /^v\d+\.\d+\.[\dx]+-doc$/ +skip_commits: + message: /\[ci doc\]/ + files: + - doc/ + - galleries/ + clone_depth: 50 +image: Visual Studio 2022 + environment: global: PYTHONFAULTHANDLER: 1 PYTHONIOENCODING: UTF-8 - PYTEST_ARGS: -raR --numprocesses=auto --timeout=300 --durations=25 + PYTEST_ARGS: -rfEsXR --numprocesses=auto --timeout=300 --durations=25 --cov-report= --cov=lib --log-level=DEBUG matrix: - # In theory we could use a single CONDA_INSTALL_LOCN because we construct - # the envs anyway. But using one for the right python version hopefully - # making things faster due to package caching. - - PYTHON_VERSION: "3.6" - CONDA_INSTALL_LOCN: "C:\\Miniconda36-x64" - TEST_ALL: "no" - EXTRAREQS: "-r requirements/testing/travis_extra.txt" - - PYTHON_VERSION: "3.7" - CONDA_INSTALL_LOCN: "C:\\Miniconda37-x64" - TEST_ALL: "no" + - PYTHON_VERSION: "3.12" # We always use a 64-bit machine, but can build x86 distributions # with the PYTHON_ARCH variable platform: - - x64 - -# all our python builds have to happen in tests_script... -build: false + - x64 cache: - '%LOCALAPPDATA%\pip\Cache' - '%USERPROFILE%\.cache\matplotlib' init: - - echo %PYTHON_VERSION% %CONDA_INSTALL_LOCN% + - ps: + Invoke-Webrequest + -URI https://micro.mamba.pm/api/micromamba/win-64/latest + -OutFile C:\projects\micromamba.tar.bz2 + - ps: C:\PROGRA~1\7-Zip\7z.exe x C:\projects\micromamba.tar.bz2 -aoa -oC:\projects\ + - ps: C:\PROGRA~1\7-Zip\7z.exe x C:\projects\micromamba.tar -ttar -aoa -oC:\projects\ + - 'set PATH=C:\projects\Library\bin;%PATH%' + - micromamba shell init --shell cmd.exe + - micromamba config set always_yes true + - micromamba config prepend channels conda-forge + - micromamba info install: - - set PATH=%CONDA_INSTALL_LOCN%;%CONDA_INSTALL_LOCN%\scripts;%PATH%; - - conda config --set always_yes true - - conda config --set show_channel_urls yes - - conda config --prepend channels conda-forge - - # For building, use a new environment - - conda create -q -n test-environment python=%PYTHON_VERSION% tk - - activate test-environment - - echo %PYTHON_VERSION% %TARGET_ARCH% - # Install dependencies from PyPI. - - python -mpip install --upgrade -r requirements/testing/travis_all.txt %EXTRAREQS% %PINNEDVERS% - # Install optional dependencies from PyPI. - # Sphinx is needed to run sphinxext tests - - python -mpip install --upgrade sphinx - - # Apply patch to `subprocess` on Python versions > 2 and < 3.6.3 - # https://github.com/matplotlib/matplotlib/issues/9176 - - python -c "import sys; sys.exit(not (3,) < sys.version_info < (3,6,3))" && ( - curl -sL https://github.com/python/cpython/pull/1224.patch | - patch -fsup 1 -d %CONDA_PREFIX% ) || cmd /c "exit /b 0" - - # Show the installed packages + versions - - conda list + - set EXTRA_PACKAGES=pywin32 codecov + # These are optional dependencies so that we don't skip so many tests... + - set EXTRA_PACKAGES=%EXTRA_PACKAGES% ffmpeg inkscape + # miktex is available on conda, but seems to fail with permission errors. + # missing packages on conda-forge for imagemagick + # This install sometimes failed randomly :-( + # - choco install imagemagick -test_script: + - micromamba env create -f environment.yml python=%PYTHON_VERSION% %EXTRA_PACKAGES% + - micromamba activate mpl-dev + +build_script: # Now build the thing.. - set LINK=/LIBPATH:%cd%\lib - - pip install -ve . + - pip install -v --no-build-isolation --editable .[dev] # this should show no freetype dll... - set "DUMPBIN=%VS140COMNTOOLS%\..\..\VC\bin\dumpbin.exe" - '"%DUMPBIN%" /DEPENDENTS lib\matplotlib\ft2font*.pyd | findstr freetype.*.dll && exit /b 1 || exit /b 0' - # this are optional dependencies so that we don't skip so many tests... - - if x%TEST_ALL% == xyes conda install -q ffmpeg inkscape miktex - # missing packages on conda-forge for imagemagick - # This install sometimes failed randomly :-( - #- choco install imagemagick - +test_script: # Test import of tkagg backend - - python -c "import matplotlib as m; m.use('tkagg'); import matplotlib.pyplot as plt; print(plt.get_backend())" + - python -c + "import matplotlib as m; m.use('tkagg'); + import matplotlib.pyplot as plt; + print(plt.get_backend())" # tests - echo The following args are passed to pytest %PYTEST_ARGS% - pytest %PYTEST_ARGS% -after_test: - # After the tests were a success, build wheels. - # Hide the output, the copied files really clutter the build log... - - 'python setup.py bdist_wheel > NUL:' - - dir dist\ - - echo finished... - artifacts: - - path: dist\* - name: packages - - path: result_images\* name: result_images - type: zip + type: Zip on_finish: - - pip install codecov - - codecov -e PYTHON_VERSION PLATFORM + - codecov -e PYTHON_VERSION PLATFORM -n "%PYTHON_VERSION% Windows" on_failure: - # Generate a html for visual tests + # Generate an html for visual tests - python tools/visualize_tests.py --no-browser - echo zipping images after a failure... - 7z a result_images.zip result_images\ | grep -v "Compressing" diff --git a/.circleci/config.yml b/.circleci/config.yml index e471b8d8be53..85622ffa7013 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,159 +1,253 @@ # Circle CI configuration file # https://circleci.com/docs/ - +--- version: 2.1 -########################################### -# Define some common steps as YAML anchors. -# - -apt-run: &apt-install - name: Install apt packages - command: | - sudo apt -qq update - sudo apt install -y \ - inkscape \ - ffmpeg \ - dvipng \ - lmodern \ - cm-super \ - texlive-latex-base \ - texlive-latex-extra \ - texlive-fonts-recommended \ - texlive-latex-recommended \ - texlive-pictures \ - texlive-xetex \ - graphviz \ - fonts-crosextra-carlito \ - fonts-freefont-otf \ - fonts-humor-sans - -fonts-run: &fonts-install - name: Install custom fonts - command: | - mkdir -p ~/.local/share/fonts - wget -nc https://github.com/google/fonts/blob/master/ofl/felipa/Felipa-Regular.ttf?raw=true -O ~/.local/share/fonts/Felipa-Regular.ttf || true - fc-cache -f -v - save_cache: - key: fonts-2 - paths: - - ~/.local/share/fonts/ - restore_cache: - key: fonts-2 - -pip-run: &pip-install - # Upgrade pip and setuptools and wheel to get as clean an install as possible - name: Upgrade pip, setuptools, wheel - command: | - python -mpip install --upgrade --user pip - python -mpip install --upgrade --user wheel - python -mpip install --upgrade --user setuptools - -deps-run: &deps-install - name: Install Python dependencies - command: | - python -mpip install --user numpy${NUMPY_VERSION} codecov coverage - python -mpip install --user -r requirements/doc/doc-requirements.txt - -mpl-run: &mpl-install - name: Install Matplotlib - command: python -mpip install --user -ve . - -doc-run: &doc-build - name: Build documentation - command: | - # Set epoch to date of latest tag. - export SOURCE_DATE_EPOCH="$(git log -1 --format=%at $(git describe --abbrev=0))" - make html O=-T - rm -r build/html/_sources - working_directory: doc - -doc-bundle-run: &doc-bundle - name: Bundle sphinx-gallery documentation artifacts - command: tar cf doc/build/sphinx-gallery-files.tar.gz doc/api/_as_gen doc/gallery doc/tutorials - when: always - - -########################################## -# Here is where the real jobs are defined. +####################################### +# Define some common steps as commands. # -jobs: - docs-python36: - docker: - - image: circleci/python:3.6 +commands: + check-skip: steps: - - checkout - - - run: *apt-install - - run: *fonts-install - - run: *pip-install - run: - <<: *deps-install - environment: - NUMPY_VERSION: "==1.13.0" - - run: *mpl-install - - - run: *doc-build - - - run: *doc-bundle + name: Check-skip + command: | + export git_log=$(git log --max-count=1 --pretty=format:"%B" | tr "\n" " ") + echo "Got commit message:" + echo "${git_log}" + if [[ -v CIRCLE_PULL_REQUEST ]] && + [[ $git_log =~ (\[skip circle\]|\[circle skip\]|\[skip doc\]|\[doc skip\]) ]]; then + echo "Skip detected, exiting job ${CIRCLE_JOB} for PR ${CIRCLE_PULL_REQUEST}." + circleci-agent step halt; + fi + + merge: + steps: + - run: + name: Merge with upstream + command: | + if ! git remote -v | grep upstream; then + git remote add upstream https://github.com/matplotlib/matplotlib.git + fi + git fetch upstream + if [[ "$CIRCLE_BRANCH" != "main" ]] && \ + [[ "$CIRCLE_PR_NUMBER" != "" ]]; then + echo "Merging ${CIRCLE_PR_NUMBER}" + git pull --ff-only upstream "refs/pull/${CIRCLE_PR_NUMBER}/merge" + fi + + apt-install: + steps: + - run: + name: Install apt packages + command: | + sudo apt-get -qq update + sudo apt-get install -yy --no-install-recommends \ + cm-super \ + dvipng \ + ffmpeg \ + fonts-crosextra-carlito \ + fonts-freefont-otf \ + fonts-noto-cjk \ + fonts-wqy-zenhei \ + graphviz \ + inkscape \ + lmodern \ + ninja-build \ + optipng \ + texlive-fonts-recommended \ + texlive-latex-base \ + texlive-latex-extra \ + texlive-latex-recommended \ + texlive-pictures \ + texlive-xetex + + fonts-install: + steps: + - restore_cache: + key: fonts-5 + - run: + name: Install custom fonts + command: | + mkdir -p ~/.local/share/fonts + wget -nc \ + https://github.com/google/fonts/blob/master/ofl/felipa/Felipa-Regular.ttf?raw=true \ + -O ~/.local/share/fonts/Felipa-Regular.ttf || true + wget -nc \ + https://github.com/ipython/xkcd-font/blob/master/xkcd-script/font/xkcd-script.ttf?raw=true \ + -O ~/.local/share/fonts/xkcd-Script.ttf || true + fc-cache -f -v + - save_cache: + key: fonts-5 + paths: + - ~/.local/share/fonts/ + + pip-install: + description: Upgrade pip and setuptools and wheel to get as clean an install as possible + steps: + - run: + name: Upgrade pip, setuptools, wheel + command: | + python -m pip install --upgrade --user pip + python -m pip install --upgrade --user wheel + python -m pip install --upgrade --user 'setuptools!=60.6.0' + + doc-deps-install: + parameters: + numpy_version: + type: string + default: "" + steps: + - run: + name: Install Python dependencies + command: | + python -m pip install --user --group build + python -m pip install --user \ + numpy<< parameters.numpy_version >> \ + --group doc + python -m pip install --no-deps --user \ + git+https://github.com/matplotlib/mpl-sphinx-theme.git + + mpl-install: + steps: + - run: + name: Install Matplotlib + command: | + if [[ "$CIRCLE_BRANCH" == v*-doc ]]; then + # The v*-doc branches must build against the specified release. + version=${CIRCLE_BRANCH%-doc} + version=${version#v} + python -m pip install matplotlib==${version} + else + python -m pip install --user --verbose \ + --no-build-isolation --editable .[dev] + fi + - save_cache: + key: build-deps-3 + paths: + - subprojects/packagecache + + doc-build: + steps: + - restore_cache: + keys: + - sphinx-env-v1-{{ .BuildNum }}-{{ .Environment.CIRCLE_JOB }} + - sphinx-env-v1-{{ .Environment.CIRCLE_PREVIOUS_BUILD_NUM }}-{{ .Environment.CIRCLE_JOB }} + - run: + name: Build documentation + command: | + # Set epoch to date of latest tag. + export SOURCE_DATE_EPOCH="$(git log -1 --format=%at $(git describe --abbrev=0))" + # Set release mode only when deploying to devdocs. + if [ "$CIRCLE_PROJECT_USERNAME" = "matplotlib" ] && \ + [ "$CIRCLE_BRANCH" = "main" ] && \ + [ "$CIRCLE_PR_NUMBER" = "" ]; then + export RELEASE_TAG='-t release' + fi + mkdir -p logs + make html O="-T $RELEASE_TAG -j4 -w /tmp/sphinxerrorswarnings.log" + rm -r build/html/_sources + working_directory: doc + - save_cache: + key: sphinx-env-v1-{{ .BuildNum }}-{{ .Environment.CIRCLE_JOB }} + paths: + - doc/build/doctrees + + doc-show-errors-warnings: + steps: + - run: + name: Extract possible build errors and warnings + command: | + (grep "WARNING\|ERROR" /tmp/sphinxerrorswarnings.log || + echo "No errors or warnings") + # Save logs as an artifact, and convert from absolute paths to + # repository-relative paths. + sed "s~$PWD/~~" /tmp/sphinxerrorswarnings.log > \ + doc/logs/sphinx-errors-warnings.log + when: always - store_artifacts: - path: doc/build/sphinx-gallery-files.tar.gz + path: doc/logs/sphinx-errors-warnings.log + doc-show-deprecations: + steps: + - run: + name: Extract possible deprecation warnings in examples and tutorials + command: | + (grep -rl DeprecationWarning doc/build/html/gallery || + echo "No deprecation warnings in gallery") + (grep -rl DeprecationWarning doc/build/html/plot_types || + echo "No deprecation warnings in plot_types") + (grep -rl DeprecationWarning doc/build/html/tutorials || + echo "No deprecation warnings in tutorials") + # Save deprecations that are from this absolute directory, and + # convert to repository-relative paths. + (grep -Ero --no-filename "$PWD/.+DeprecationWarning.+$" \ + doc/build/html/{gallery,plot_types,tutorials} || echo) | \ + sed "s~$PWD/~~" > doc/logs/sphinx-deprecations.log + when: always - store_artifacts: - path: doc/build/html + path: doc/logs/sphinx-deprecations.log - docs-python37: - docker: - - image: circleci/python:3.7 + doc-bundle: steps: - - checkout - - - run: *apt-install - - run: *fonts-install - - run: *pip-install - - - run: *deps-install - - run: *mpl-install - - - run: *doc-build - - - run: *doc-bundle + - run: + name: Bundle sphinx-gallery documentation artifacts + command: > + tar cf doc/build/sphinx-gallery-files.tar.gz + doc/api/_as_gen + doc/gallery + doc/plot_types + doc/tutorials + when: always - store_artifacts: path: doc/build/sphinx-gallery-files.tar.gz - - store_artifacts: - path: doc/build/html + deploy-docs: + steps: + - run: + name: "Deploy new docs" + command: ./.circleci/deploy-docs.sh + + +########################################## +# Here is where the real jobs are defined. +# - docs-python38: +jobs: + docs-python3: docker: - - image: circleci/python:3.8 + - image: cimg/python:3.12 + resource_class: large steps: - checkout + - check-skip + - merge - - run: *apt-install - - run: *fonts-install - - run: *pip-install + - apt-install + - fonts-install + - pip-install - - run: *deps-install - - run: *mpl-install + - doc-deps-install + - mpl-install - - run: *doc-build + - doc-build + - doc-show-errors-warnings + - doc-show-deprecations - - run: *doc-bundle - - store_artifacts: - path: doc/build/sphinx-gallery-files.tar.gz + - doc-bundle - store_artifacts: path: doc/build/html + - store_test_results: + path: doc/build/test-results - add_ssh_keys: fingerprints: - - "78:13:59:08:61:a9:e5:09:af:df:3a:d8:89:c2:84:c0" - - deploy: - name: "Deploy new docs" - command: ./.circleci/deploy-docs.sh + - "be:c3:c1:d8:fb:a1:0e:37:71:72:d7:a3:40:13:8f:14" + + - deploy-docs ######################################### # Defining workflows gets us parallelism. @@ -163,6 +257,6 @@ workflows: version: 2 build: jobs: - - docs-python36 - - docs-python37 - - docs-python38 + # NOTE: If you rename this job, then you must update the `if` condition + # and `circleci-jobs` option in `.github/workflows/circleci.yml`. + - docs-python3 diff --git a/.circleci/deploy-docs.sh b/.circleci/deploy-docs.sh index e6a51e58d8ad..8801d5fd073e 100755 --- a/.circleci/deploy-docs.sh +++ b/.circleci/deploy-docs.sh @@ -2,8 +2,13 @@ set -e -if [ "$CIRCLE_PROJECT_USERNAME" != "matplotlib" -o "$CIRCLE_BRANCH" != "master" -o "$CIRCLE_PULL_REQUEST" != "" ]; then - echo "Not uploading docs from non-master branch or non-Matplotlib org." +if [ "$CIRCLE_PROJECT_USERNAME" != "matplotlib" ] || \ + [ "$CIRCLE_BRANCH" != "main" ] || \ + [[ "$CIRCLE_PULL_REQUEST" == https://github.com/matplotlib/matplotlib/pull/* ]]; then + echo "Not uploading docs for ${CIRCLE_SHA1}"\ + "from non-main branch (${CIRCLE_BRANCH})"\ + "or pull request (${CIRCLE_PULL_REQUEST})"\ + "or non-Matplotlib org (${CIRCLE_PROJECT_USERNAME})." exit fi diff --git a/.circleci/fetch_doc_logs.py b/.circleci/fetch_doc_logs.py new file mode 100644 index 000000000000..0a5552a7721c --- /dev/null +++ b/.circleci/fetch_doc_logs.py @@ -0,0 +1,66 @@ +""" +Download artifacts from CircleCI for a documentation build. + +This is run by the :file:`.github/workflows/circleci.yml` workflow in order to +get the warning/deprecation logs that will be posted on commits as checks. Logs +are downloaded from the :file:`docs/logs` artifact path and placed in the +:file:`logs` directory. + +Additionally, the artifact count for a build is produced as a workflow output, +by appending to the file specified by :env:`GITHUB_OUTPUT`. + +If there are no logs, an "ERROR" message is printed, but this is not fatal, as +the initial 'status' workflow runs when the build has first started, and there +are naturally no artifacts at that point. + +This script should be run by passing the CircleCI build URL as its first +argument. In the GitHub Actions workflow, this URL comes from +``github.event.target_url``. +""" +import json +import os +from pathlib import Path +import sys +from urllib.parse import urlparse +from urllib.request import URLError, urlopen + + +if len(sys.argv) != 2: + print('USAGE: fetch_doc_results.py CircleCI-build-url') + sys.exit(1) + +target_url = urlparse(sys.argv[1]) +*_, organization, repository, build_id = target_url.path.split('/') +print(f'Fetching artifacts from {organization}/{repository} for {build_id}') + +artifact_url = ( + f'https://circleci.com/api/v2/project/gh/' + f'{organization}/{repository}/{build_id}/artifacts' +) +print(artifact_url) +try: + with urlopen(artifact_url) as response: + artifacts = json.load(response) +except URLError: + artifacts = {'items': []} +artifact_count = len(artifacts['items']) +print(f'Found {artifact_count} artifacts') + +with open(os.environ['GITHUB_OUTPUT'], 'w+') as fd: + fd.write(f'count={artifact_count}\n') + +logs = Path('logs') +logs.mkdir(exist_ok=True) + +found = False +for item in artifacts['items']: + path = item['path'] + if path.startswith('doc/logs/'): + path = Path(path).name + print(f'Downloading {path} from {item["url"]}') + with urlopen(item['url']) as response: + (logs / path).write_bytes(response.read()) + found = True + +if not found: + print('ERROR: Did not find any artifact logs!') diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 000000000000..64263ec96b7b --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,36 @@ +--- +# clang-tidy configuration for matplotlib's src/ directory. +# +# Philosophy: enable checks that find real bugs (memory safety, undefined +# behaviour, security) and suppress checks that are high-noise style rules +# inappropriate for a C/C++ codebase that interfaces heavily with C APIs +# (CPython, FreeType, libagg) via pybind11. +# +# Run with: +# clang-tidy -p --config-file=src/.clang-tidy + +Checks: > + bugprone-*, + clang-analyzer-*, + objc-*, + performance-move-const-arg, + performance-move-constructor-init, + performance-no-automatic-move, + portability-*, + -bugprone-assignment-in-if-condition, + -bugprone-easily-swappable-parameters, + -bugprone-implicit-widening-of-multiplication-result, + -bugprone-macro-parentheses, + -bugprone-narrowing-conversions, + -bugprone-reserved-identifier, + -bugprone-throwing-static-initialization, + -clang-analyzer-optin.cplusplus.UninitializedObject, + -clang-analyzer-optin.performance.Padding, + +# Only report findings in matplotlib's own src/ headers, not in pybind11, +# Python.h, agg, or other vendored includes. +HeaderFilterRegex: '.*/matplotlib/src/.*' + +WarningsAsErrors: '' + +CheckOptions: [] diff --git a/.coveragerc b/.coveragerc index cd41bdd06a92..f8d90f93e600 100644 --- a/.coveragerc +++ b/.coveragerc @@ -7,7 +7,10 @@ omit = matplotlib/_version.py [report] exclude_lines = + pragma: no cover raise NotImplemented def __str__ def __repr__ if __name__ == .__main__.: + if TYPE_CHECKING: + if typing.TYPE_CHECKING: diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 000000000000..ddec2754d03a --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,38 @@ +{ + "hostRequirements": { + "memory": "8gb", + "cpus": 4 + }, + "image": "mcr.microsoft.com/devcontainers/universal:2", + "features": { + "ghcr.io/devcontainers/features/desktop-lite:1": {}, + "ghcr.io/rocker-org/devcontainer-features/apt-packages:1": { + "packages": "inkscape,ffmpeg,dvipng,lmodern,cm-super,texlive-latex-base,texlive-latex-extra,texlive-fonts-recommended,texlive-latex-recommended,texlive-pictures,texlive-xetex,fonts-wqy-zenhei,graphviz,fonts-crosextra-carlito,fonts-freefont-otf,fonts-comic-neue,fonts-noto-cjk,optipng" + } + }, + "onCreateCommand": ".devcontainer/setup.sh", + "postCreateCommand": "", + "forwardPorts": [6080], + "portsAttributes": { + "6080": { + "label": "desktop" + } + }, + "customizations": { + "vscode": { + "extensions": [ + "ms-python.python", + "yy0931.mplstyle", + "eamodio.gitlens", + "ms-vscode.live-server" + ], + "settings": {} + }, + "codespaces": { + "openFiles": [ + "README.md", + "doc/devel/codespaces.md" + ] + } + } +} diff --git a/.devcontainer/setup.sh b/.devcontainer/setup.sh new file mode 100755 index 000000000000..88da5baf69e2 --- /dev/null +++ b/.devcontainer/setup.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +set -e + +"${SHELL}" <(curl -Ls micro.mamba.pm/install.sh) < /dev/null + +conda init --all +micromamba shell init -s bash +micromamba env create -f environment.yml --yes +# Note that `micromamba activate mpl-dev` doesn't work, it must be run by the +# user (same applies to `conda activate`) +echo "envs_dirs: + - /home/codespace/micromamba/envs" > /opt/conda/.condarc diff --git a/.flake8 b/.flake8 deleted file mode 100644 index 23692c208d3f..000000000000 --- a/.flake8 +++ /dev/null @@ -1,284 +0,0 @@ -[flake8] -max-line-length = 79 -select = - # flake8 default - C90, E, F, W, - # docstring-convention=numpy - D100, D101, D102, D103, D104, D105, D106, - D200, D201, D202, D204, D205, D206, D207, D208, - D209, D210, D211, D214, D215, - D300, D301, D302, - D400, D401, D403, D404, D405, D406, D407, D408, - D409, D410, D411, D412, D414, - # matplotlib-specific extra pydocstyle errors - D213, -ignore = - # flake8 default - E121,E123,E126,E226,E24,E704,W503,W504, - # Additional ignores: - E122, E127, E131, - E265, E266, - E305, E306, - E722, E741, - F841, - # Some new flake8 ignores: - N801, N802, N803, N806, N812, - # pydocstyle - D100, D101, D102, D103, D104, D105, D106, D107, - D200, D202, D203, D204, D205, D207, D212, - D301, - D400, D401, D402, D403, D404, D413, - -exclude = - .git - build - doc/gallery - doc/tutorials - # External files. - versioneer.py - tools/gh_api.py - tools/github_stats.py - .tox - .eggs - -per-file-ignores = - setup.py: E402 - setupext.py: E501 - tests.py: F401 - - tools/subset.py: E221, E251, E261, E302, E501 - - lib/matplotlib/__init__.py: F401 - lib/matplotlib/_cm.py: E202, E203, E302 - lib/matplotlib/_mathtext_data.py: E203, E261 - lib/matplotlib/animation.py: F401 - lib/matplotlib/axes/__init__.py: F401, F403 - lib/matplotlib/axes/_axes.py: F401 - lib/matplotlib/backends/backend_*.py: F401 - lib/matplotlib/backends/qt_editor/formlayout.py: F401, F403 - lib/matplotlib/cbook/__init__.py: F401 - lib/matplotlib/font_manager.py: E221, E251, E501 - lib/matplotlib/image.py: F401, F403 - lib/matplotlib/lines.py: F401 - lib/matplotlib/mathtext.py: E221, E251 - lib/matplotlib/pylab.py: F401, F403 - lib/matplotlib/pyplot.py: F401, F811 - lib/matplotlib/rcsetup.py: E501 - lib/matplotlib/style/__init__.py: F401 - lib/matplotlib/testing/conftest.py: F401 - lib/matplotlib/testing/compare.py: F401 - lib/matplotlib/testing/decorators.py: F401 - lib/matplotlib/tests/conftest.py: F401 - lib/matplotlib/tests/test_backend_qt.py: F401 - lib/matplotlib/tests/test_mathtext.py: E501 - lib/matplotlib/text.py: F401 - lib/matplotlib/transforms.py: E201, E202, E203 - lib/matplotlib/tri/__init__.py: F401, F403 - lib/matplotlib/tri/triinterpolate.py: E201, E221 - lib/mpl_toolkits/axes_grid/*: F401, F403 - lib/mpl_toolkits/axes_grid1/__init__.py: F401 - lib/mpl_toolkits/axes_grid1/axes_size.py: E272 - lib/mpl_toolkits/axisartist/__init__.py: F401 - lib/mpl_toolkits/axisartist/angle_helper.py: E221 - lib/mpl_toolkits/axisartist/axes_divider.py: F401 - lib/mpl_toolkits/axisartist/axes_rgb.py: F401 - lib/mpl_toolkits/axisartist/axislines.py: F401 - lib/mpl_toolkits/mplot3d/__init__.py: F401 - lib/mpl_toolkits/tests/conftest.py: F401 - lib/pylab.py: F401, F403 - - doc/conf.py: E402, E501 - tutorials/advanced/path_tutorial.py: E402 - tutorials/advanced/patheffects_guide.py: E402 - tutorials/advanced/transforms_tutorial.py: E402, E501 - tutorials/colors/colormaps.py: E501 - tutorials/colors/colors.py: E402 - tutorials/colors/colormap-manipulation.py: E402 - tutorials/intermediate/artists.py: E402 - tutorials/intermediate/constrainedlayout_guide.py: E402 - tutorials/intermediate/gridspec.py: E402 - tutorials/intermediate/legend_guide.py: E402 - tutorials/intermediate/tight_layout_guide.py: E402 - tutorials/introductory/customizing.py: E501 - tutorials/introductory/images.py: E402, E501 - tutorials/introductory/pyplot.py: E402, E501 - tutorials/introductory/sample_plots.py: E501 - tutorials/introductory/usage.py: E501 - tutorials/text/annotations.py: E501 - tutorials/text/text_intro.py: E402 - tutorials/text/text_props.py: E501 - tutorials/text/usetex.py: E501 - tutorials/toolkits/axes_grid.py: E501 - tutorials/toolkits/axisartist.py: E501 - - examples/animation/frame_grabbing_sgskip.py: E402 - examples/axes_grid1/inset_locator_demo.py: E402 - examples/axes_grid1/scatter_hist_locatable_axes.py: E402 - examples/axisartist/demo_curvelinear_grid.py: E402 - examples/color/color_by_yvalue.py: E402 - examples/color/color_cycle_default.py: E402 - examples/color/color_cycler.py: E402 - examples/color/color_demo.py: E402 - examples/color/colorbar_basics.py: E402 - examples/color/colormap_reference.py: E402 - examples/color/custom_cmap.py: E402 - examples/color/named_colors.py: E402 - examples/images_contours_and_fields/affine_image.py: E402 - examples/images_contours_and_fields/barb_demo.py: E402 - examples/images_contours_and_fields/barcode_demo.py: E402 - examples/images_contours_and_fields/contour_corner_mask.py: E402 - examples/images_contours_and_fields/contour_demo.py: E402 - examples/images_contours_and_fields/contour_image.py: E402 - examples/images_contours_and_fields/contourf_demo.py: E402 - examples/images_contours_and_fields/contourf_hatching.py: E402 - examples/images_contours_and_fields/contourf_log.py: E402 - examples/images_contours_and_fields/demo_bboximage.py: E402 - examples/images_contours_and_fields/image_antialiasing.py: E402 - examples/images_contours_and_fields/image_clip_path.py: E402 - examples/images_contours_and_fields/image_demo.py: E402 - examples/images_contours_and_fields/image_masked.py: E402 - examples/images_contours_and_fields/image_transparency_blend.py: E402 - examples/images_contours_and_fields/image_zcoord.py: E402 - examples/images_contours_and_fields/interpolation_methods.py: E402 - examples/images_contours_and_fields/irregulardatagrid.py: E402 - examples/images_contours_and_fields/layer_images.py: E402 - examples/images_contours_and_fields/matshow.py: E402 - examples/images_contours_and_fields/multi_image.py: E402 - examples/images_contours_and_fields/pcolor_demo.py: E402 - examples/images_contours_and_fields/plot_streamplot.py: E402 - examples/images_contours_and_fields/quadmesh_demo.py: E402 - examples/images_contours_and_fields/quiver_demo.py: E402 - examples/images_contours_and_fields/quiver_simple_demo.py: E402 - examples/images_contours_and_fields/shading_example.py: E402 - examples/images_contours_and_fields/specgram_demo.py: E402 - examples/images_contours_and_fields/spy_demos.py: E402 - examples/images_contours_and_fields/tricontour_demo.py: E201, E402 - examples/images_contours_and_fields/tricontour_smooth_delaunay.py: E402 - examples/images_contours_and_fields/tricontour_smooth_user.py: E402 - examples/images_contours_and_fields/trigradient_demo.py: E402 - examples/images_contours_and_fields/triinterp_demo.py: E402 - examples/images_contours_and_fields/tripcolor_demo.py: E201, E402 - examples/images_contours_and_fields/triplot_demo.py: E201, E402 - examples/images_contours_and_fields/watermark_image.py: E402 - examples/lines_bars_and_markers/errorbar_limits_simple.py: E402 - examples/lines_bars_and_markers/fill.py: E402 - examples/lines_bars_and_markers/fill_between_demo.py: E402 - examples/lines_bars_and_markers/filled_step.py: E402 - examples/lines_bars_and_markers/horizontal_barchart_distribution.py: E402 - examples/lines_bars_and_markers/joinstyle.py: E402 - examples/lines_bars_and_markers/scatter_hist.py: E402 - examples/lines_bars_and_markers/scatter_piecharts.py: E402 - examples/lines_bars_and_markers/scatter_with_legend.py: E402 - examples/lines_bars_and_markers/span_regions.py: E402 - examples/lines_bars_and_markers/stem_plot.py: E402 - examples/lines_bars_and_markers/step_demo.py: E402 - examples/lines_bars_and_markers/timeline.py: E402 - examples/lines_bars_and_markers/xcorr_acorr_demo.py: E402 - examples/misc/agg_buffer.py: E402 - examples/misc/histogram_path.py: E402 - examples/misc/print_stdout_sgskip.py: E402 - examples/misc/svg_filter_line.py: E402 - examples/misc/svg_filter_pie.py: E402 - examples/misc/table_demo.py: E201 - examples/mplot3d/surface3d.py: E402 - examples/pie_and_polar_charts/bar_of_pie.py: E402 - examples/pie_and_polar_charts/nested_pie.py: E402 - examples/pie_and_polar_charts/pie_and_donut_labels.py: E402 - examples/pie_and_polar_charts/pie_demo2.py: E402 - examples/pie_and_polar_charts/pie_features.py: E402 - examples/pie_and_polar_charts/polar_bar.py: E402 - examples/pie_and_polar_charts/polar_demo.py: E402 - examples/pie_and_polar_charts/polar_legend.py: E402 - examples/pie_and_polar_charts/polar_scatter.py: E402 - examples/pyplots/align_ylabels.py: E402 - examples/pyplots/annotate_transform.py: E251, E402 - examples/pyplots/annotation_basic.py: E402 - examples/pyplots/annotation_polar.py: E402 - examples/pyplots/auto_subplots_adjust.py: E302, E402 - examples/pyplots/axline.py: E402 - examples/pyplots/boxplot_demo_pyplot.py: E402 - examples/pyplots/dollar_ticks.py: E402 - examples/pyplots/fig_axes_customize_simple.py: E402 - examples/pyplots/fig_axes_labels_simple.py: E402 - examples/pyplots/fig_x.py: E402 - examples/pyplots/pyplot_formatstr.py: E402 - examples/pyplots/pyplot_mathtext.py: E402 - examples/pyplots/pyplot_scales.py: E402 - examples/pyplots/pyplot_simple.py: E402 - examples/pyplots/pyplot_text.py: E402 - examples/pyplots/pyplot_three.py: E402 - examples/pyplots/pyplot_two_subplots.py: E402 - examples/pyplots/text_commands.py: E402 - examples/pyplots/text_layout.py: E402 - examples/pyplots/whats_new_1_subplot3d.py: E402 - examples/pyplots/whats_new_98_4_fill_between.py: E402 - examples/pyplots/whats_new_98_4_legend.py: E402 - examples/pyplots/whats_new_99_axes_grid.py: E402 - examples/pyplots/whats_new_99_mplot3d.py: E402 - examples/pyplots/whats_new_99_spines.py: E402 - examples/scales/power_norm.py: E402 - examples/scales/scales.py: E402 - examples/shapes_and_collections/artist_reference.py: E402 - examples/shapes_and_collections/collections.py: E402 - examples/shapes_and_collections/compound_path.py: E402 - examples/shapes_and_collections/dolphin.py: E402 - examples/shapes_and_collections/donut.py: E402 - examples/shapes_and_collections/ellipse_collection.py: E402 - examples/shapes_and_collections/ellipse_demo.py: E402 - examples/shapes_and_collections/fancybox_demo.py: E402 - examples/shapes_and_collections/hatch_demo.py: E402 - examples/shapes_and_collections/line_collection.py: E402 - examples/shapes_and_collections/marker_path.py: E402 - examples/shapes_and_collections/patch_collection.py: E402 - examples/shapes_and_collections/path_patch.py: E402 - examples/shapes_and_collections/quad_bezier.py: E402 - examples/shapes_and_collections/scatter.py: E402 - examples/showcase/anatomy.py: E402 - examples/showcase/bachelors_degrees_by_gender.py: E402 - examples/showcase/firefox.py: E501 - examples/specialty_plots/anscombe.py: E402 - examples/specialty_plots/radar_chart.py: E402 - examples/specialty_plots/sankey_basics.py: E402 - examples/specialty_plots/sankey_links.py: E402 - examples/specialty_plots/sankey_rankine.py: E402 - examples/specialty_plots/skewt.py: E402 - examples/style_sheets/bmh.py: E501 - examples/style_sheets/ggplot.py: E501 - examples/style_sheets/plot_solarizedlight2.py: E501 - examples/subplots_axes_and_figures/axes_margins.py: E402 - examples/subplots_axes_and_figures/axes_zoom_effect.py: E402 - examples/subplots_axes_and_figures/custom_figure_class.py: E402 - examples/subplots_axes_and_figures/demo_constrained_layout.py: E402 - examples/subplots_axes_and_figures/demo_tight_layout.py: E402 - examples/subplots_axes_and_figures/secondary_axis.py: E402 - examples/subplots_axes_and_figures/two_scales.py: E402 - examples/subplots_axes_and_figures/zoom_inset_axes.py: E402 - examples/text_labels_and_annotations/date_index_formatter.py: E402 - examples/text_labels_and_annotations/demo_text_rotation_mode.py: E402 - examples/text_labels_and_annotations/custom_legends.py: E402 - examples/text_labels_and_annotations/fancyarrow_demo.py: E402 - examples/text_labels_and_annotations/font_family_rc_sgskip.py: E402 - examples/text_labels_and_annotations/font_file.py: E402 - examples/text_labels_and_annotations/legend.py: E402 - examples/text_labels_and_annotations/line_with_text.py: E402 - examples/text_labels_and_annotations/mathtext_asarray.py: E402 - examples/text_labels_and_annotations/tex_demo.py: E402 - examples/text_labels_and_annotations/watermark_text.py: E402 - examples/ticks_and_spines/custom_ticker1.py: E402 - examples/ticks_and_spines/date_concise_formatter.py: E402 - examples/ticks_and_spines/major_minor_demo.py: E402 - examples/ticks_and_spines/tick-formatters.py: E402 - examples/ticks_and_spines/tick_labels_from_values.py: E402 - examples/user_interfaces/canvasagg.py: E402 - examples/user_interfaces/embedding_in_gtk3_panzoom_sgskip.py: E402 - examples/user_interfaces/embedding_in_gtk3_sgskip.py: E402 - examples/user_interfaces/embedding_in_qt_sgskip.py: E402 - examples/user_interfaces/gtk_spreadsheet_sgskip.py: E402 - examples/user_interfaces/mathtext_wx_sgskip.py: E402 - examples/user_interfaces/mpl_with_glade3_sgskip.py: E402 - examples/user_interfaces/pylab_with_gtk_sgskip.py: E302, E402 - examples/user_interfaces/toolmanager_sgskip.py: E402 - examples/userdemo/connectionstyle_demo.py: E402 - examples/userdemo/custom_boxstyle01.py: E402 - examples/userdemo/pgf_preamble_sgskip.py: E402 - examples/widgets/textbox.py: E402 diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs new file mode 100644 index 000000000000..611431e707ab --- /dev/null +++ b/.git-blame-ignore-revs @@ -0,0 +1,17 @@ +# style: end-of-file-fixer pre-commit hook +c1a33a481b9c2df605bcb9bef9c19fe65c3dac21 + +# style: trailing-whitespace pre-commit hook +213061c0804530d04bbbd5c259f10dc8504e5b2b + +# style: check-docstring-first pre-commit hook +046533797725293dfc2a6edb9f536b25f08aa636 + +# chore: fix spelling errors +686c9e5a413e31c46bb049407d5eca285bcab76d + +# chore: pyupgrade --py39-plus +4d306402bb66d6d4c694d8e3e14b91054417070e + +# style: docstring parameter indentation +68daa962de5634753205cba27f21d6edff7be7a2 diff --git a/.git_archival.txt b/.git_archival.txt new file mode 100644 index 000000000000..3994ec0a83ea --- /dev/null +++ b/.git_archival.txt @@ -0,0 +1,4 @@ +node: $Format:%H$ +node-date: $Format:%cI$ +describe-name: $Format:%(describe:tags=true)$ +ref-names: $Format:%D$ diff --git a/.gitattributes b/.gitattributes index 8a1657abfab3..a0c2c8627af7 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,5 +1,6 @@ * text=auto +*.m diff=objc *.ppm binary *.svg binary *.svg linguist-language=true -lib/matplotlib/_version.py export-subst +.git_archival.txt export-subst diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index c4198cdcdf14..cb27bbf19d46 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -1 +1 @@ -Please refer to the [developers guide](https://matplotlib.org/devel/index.html). +Please refer to the [contributing guide](https://matplotlib.org/devel/index.html). diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 2bef7ab95a56..a474d51d6f64 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,3 +1,4 @@ +--- # These are supported funding model platforms -github: [numfocus] +github: [matplotlib, numfocus] custom: https://numfocus.org/donate-to-matplotlib diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md deleted file mode 100644 index 617cabbc720a..000000000000 --- a/.github/ISSUE_TEMPLATE.md +++ /dev/null @@ -1,49 +0,0 @@ - - - -### Bug report - -**Bug summary** - - - -**Code for reproduction** - - - -```python -# Paste your code here -# -# -``` - -**Actual outcome** - - - -``` -# If applicable, paste the console output here -# -# -``` - -**Expected outcome** - - - - -**Matplotlib version** - - * Operating system: - * Matplotlib version: - * Matplotlib backend (`print(matplotlib.get_backend())`): - * Python version: - * Jupyter version (if applicable): - * Other libraries: - - - - diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 000000000000..f3595d2b7865 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,89 @@ +--- +name: Bug Report +description: Report a bug or issue with Matplotlib. +title: "[Bug]: " +body: + - type: textarea + id: summary + attributes: + label: Bug summary + description: Describe the bug in 1-2 short sentences + validations: + required: true + - type: textarea + id: reproduction + attributes: + label: Code for reproduction + description: >- + If possible, please provide a minimum self-contained example. If you + have used generative AI as an aid see + https://matplotlib.org/devdocs/devel/contribute.html#restrictions-on-generative-ai-usage + placeholder: Paste your code here. This field is automatically formatted as Python code. + render: Python + validations: + required: true + - type: textarea + id: actual + attributes: + label: Actual outcome + description: >- + Paste the output produced by the code provided above, e.g. + console output, images/videos produced by the code, any relevant screenshots/screencasts, etc. + validations: + required: true + - type: textarea + id: expected + attributes: + label: Expected outcome + description: Describe (or provide a visual example of) the expected outcome from the code snippet. + validations: + required: true + - type: textarea + id: details + attributes: + label: Additional information + description: | + - What are the conditions under which this bug happens? input parameters, edge cases, etc? + - Has this worked in earlier versions? + - Do you know why this bug is happening? + - Do you maybe even know a fix? + - type: input + id: operating-system + attributes: + label: Operating system + description: Windows, OS/X, Arch, Debian, Ubuntu, etc. + - type: input + id: matplotlib-version + attributes: + label: Matplotlib Version + description: "From Python prompt: `import matplotlib; print(matplotlib.__version__)`" + validations: + required: true + - type: input + id: matplotlib-backend + attributes: + label: Matplotlib Backend + description: "From Python prompt: `import matplotlib; print(matplotlib.get_backend())`" + - type: input + id: python-version + attributes: + label: Python version + description: "In console: `python --version`" + - type: input + id: jupyter-version + attributes: + label: Jupyter version + description: "In console: `jupyter notebook --version` or `jupyter lab --version`" + - type: dropdown + id: install + attributes: + label: Installation + description: How did you install matplotlib? + options: + - pip + - conda + - pixi + - uv + - Linux package manager + - from source (.tar.gz) + - git checkout diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 000000000000..635f11028226 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,11 @@ +# Reference: +# https://help.github.com/en/github/building-a-strong-community/configuring-issue-templates-for-your-repository#configuring-the-template-chooser +--- +blank_issues_enabled: true # default +contact_links: + - name: Question/Support/Other + url: https://discourse.matplotlib.org + about: If you have a usage question + - name: Chat with devs + url: https://discourse.matplotlib.org/chat/c/matplotlib/2 + about: Ask short questions about contributing to Matplotlib diff --git a/.github/ISSUE_TEMPLATE/documentation.yml b/.github/ISSUE_TEMPLATE/documentation.yml new file mode 100644 index 000000000000..5f7a0d6c7176 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/documentation.yml @@ -0,0 +1,33 @@ +--- +name: Documentation +description: Create a report to help us improve the documentation +title: "[Doc]: " +labels: [Documentation] +body: + - type: input + id: link + attributes: + label: Documentation Link + description: >- + Link to any documentation or examples that you are referencing. Suggested improvements should be based + on [the development version of the docs](https://matplotlib.org/devdocs/) + placeholder: https://matplotlib.org/devdocs/... + - type: textarea + id: problem + attributes: + label: Problem + description: What is missing, unclear, or wrong in the documentation? + placeholder: | + * I found [...] to be unclear because [...] + * [...] made me think that [...] when really it should be [...] + * There is no example showing how to do [...] + validations: + required: true + - type: textarea + id: improvement + attributes: + label: Suggested improvement + placeholder: | + * This line should be be changed to say [...] + * Include a paragraph explaining [...] + * Add a figure showing [...] diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 000000000000..e174fb8994aa --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,27 @@ +--- +name: Feature Request +description: Suggest something to add to Matplotlib! +title: "[ENH]: " +labels: [New feature] +body: + - type: markdown + attributes: + value: >- + Please search the [issues](https://github.com/matplotlib/matplotlib/issues) for relevant feature + requests before creating a new feature request. + - type: textarea + id: problem + attributes: + label: Problem + description: Briefly describe the problem this feature will solve. (2-4 sentences) + placeholder: | + * I'm always frustrated when [...] because [...] + * I would like it if [...] happened when I [...] because [...] + * Here is a sample image of what I am asking for [...] + validations: + required: true + - type: textarea + id: solution + attributes: + label: Proposed solution + description: Describe a way to accomplish the goals of this feature request. diff --git a/.github/ISSUE_TEMPLATE/maintenance.yml b/.github/ISSUE_TEMPLATE/maintenance.yml new file mode 100644 index 000000000000..6ebb64c0c3e9 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/maintenance.yml @@ -0,0 +1,18 @@ +--- +name: Maintenance +description: Help improve performance, usability and/or consistency. +title: "[MNT]: " +labels: [Maintenance] +body: + - type: textarea + id: summary + attributes: + label: Summary + description: Please provide 1-2 short sentences that succinctly describes what could be improved. + validations: + required: true + - type: textarea + id: fix + attributes: + label: Proposed fix + description: Please describe how you think this could be improved. diff --git a/.github/ISSUE_TEMPLATE/tag_proposal.yml b/.github/ISSUE_TEMPLATE/tag_proposal.yml new file mode 100644 index 000000000000..2bb856d26be6 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/tag_proposal.yml @@ -0,0 +1,28 @@ +--- +name: Tag Proposal +description: Suggest a new tag or subcategory for the gallery of examples +title: "[Tag]: " +labels: ["Documentation: tags"] +body: + - type: markdown + attributes: + value: >- + Please search the [tag glossary]() for relevant tags before creating a new tag proposal. + - type: textarea + id: need + attributes: + label: Need + description: Briefly describe the need this tag will fill. (1-4 sentences) + placeholder: | + * A tag is needed for examples that share [...] + * Existing tags do not work because [...] + * Current gallery examples that would use this tag include [...] + * Indicate which subcategory this tag falls under, or whether a new subcategory is proposed. + validations: + required: true + - type: textarea + id: solution + attributes: + label: Proposed solution + description: >- + What should the tag be? All tags are in the format `subcategory: tag` diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 677baee590db..e66cac52f9c9 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,41 +1,39 @@ -## PR Summary - -## PR Checklist - -- [ ] Has Pytest style unit tests -- [ ] Code is [Flake 8](http://flake8.pycqa.org/en/latest/) compliant -- [ ] New features are documented, with examples if plot related -- [ ] Documentation is sphinx and numpydoc compliant -- [ ] Added an entry to doc/users/next_whats_new/ if major new feature (follow instructions in README.rst there) -- [ ] Documented in doc/api/api_changes.rst if API changed in a backward-incompatible way - -- A development guide is available at https://matplotlib.org/devdocs/devel/index.html. +## PR summary + + +## AI Disclosure + -- The summary should provide at least 1-2 sentences describing the pull request - in detail (Why is this change required? What problem does it solve?) and - link to any relevant issues. +## PR checklist + -- If you are contributing fixes to docstrings, please pay attention to - http://matplotlib.org/devel/documenting_mpl.html#formatting. In particular, - note the difference between using single backquotes, double backquotes, and - asterisks in the markup. +- [ ] "closes #0000" is in the body of the PR description to [link the related issue](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue) +- [ ] new and changed code is [tested](https://matplotlib.org/devdocs/devel/testing.html) +- [ ] *Plotting related* features are demonstrated in an [example](https://matplotlib.org/devdocs/devel/document.html#write-examples-and-tutorials) +- [ ] *New Features* and *API Changes* are noted with a [directive and release note](https://matplotlib.org/devdocs/devel/api_changes.html#announce-changes-deprecations-and-new-features) +- [ ] Documentation complies with [general](https://matplotlib.org/devdocs/devel/document.html#write-rest-pages) and [docstring](https://matplotlib.org/devdocs/devel/document.html#write-docstrings) guidelines -We understand that PRs can sometimes be overwhelming, especially as the + +back on your PR.--> diff --git a/.github/codecov.yml b/.github/codecov.yml new file mode 100644 index 000000000000..00e7612bd1e6 --- /dev/null +++ b/.github/codecov.yml @@ -0,0 +1,33 @@ +# codecov used to be able to find this anywhere, now we have to manually +# tell it where to look +--- +comment: false + +codecov: + notify: + require_ci_to_pass: false + +coverage: + status: + patch: + default: + target: 50% + if_no_uploads: error + if_not_found: success + if_ci_failed: error + project: + default: false + library: + target: 50% + if_no_uploads: error + if_not_found: success + if_ci_failed: error + paths: + - '!lib/.*/tests/.*' + tests: + target: auto + if_no_uploads: error + if_not_found: success + if_ci_failed: error + paths: + - 'lib/.*/tests/.*' diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000000..0a6d627d8bb1 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,37 @@ +--- +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + cooldown: + default-days: 7 + groups: + actions: + patterns: + - "*" + labels: + - "PR: dependencies" + - package-ecosystem: "pip" + directory: "/" + schedule: + interval: "weekly" + cooldown: + default-days: 7 + exclude-paths: + - "ci/minver-requirements.txt" + labels: + - "PR: dependencies" + - package-ecosystem: "pre-commit" + directory: "/" + schedule: + interval: "monthly" + cooldown: + default-days: 7 + groups: + pre-commit: + patterns: + - "*" + labels: + - "PR: dependencies" diff --git a/.github/labeler.yml b/.github/labeler.yml new file mode 100644 index 000000000000..77b79146b47f --- /dev/null +++ b/.github/labeler.yml @@ -0,0 +1,284 @@ +--- +"CI: Run cibuildwheel": + - changed-files: + - any-glob-to-any-file: + - '.github/workflows/cibuildwheel.yml' + - '.github/workflows/wasm.yml' +"CI: Run cygwin": + - changed-files: + - any-glob-to-any-file: ['.github/workflows/cygwin.yml'] + +"backend: agg": + - changed-files: + - any-glob-to-any-file: + - 'extern/agg24-svn/' + - 'lib/matplotlib/backends/_backend_agg.pyi' + - 'lib/matplotlib/backends/backend_agg.py*' + - 'src/_backend_agg*' +"backend: cairo": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/backends/backend_*cairo.py*' +"backend: pdf": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/backends/_backend_pdf_ps.py' + - 'lib/matplotlib/backends/backend_pdf.py' +"backend: pgf": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/backends/backend_pgf.py' +"backend: ps": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/backends/_backend_pdf_ps.py' + - 'lib/matplotlib/backends/backend_ps.py' +"backend: svg": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/backends/backend_svg.py' + +"GUI: gtk": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/backends/_backend_gtk.py*' + - 'lib/matplotlib/backends/backend_gtk*' +"GUI: MacOSX": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/backends/*_macosx.py*' + - 'src/_macosx.m' +"GUI: nbagg": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/backends/*_nbagg*.py*' + - 'lib/matplotlib/backends/web_backend/js/nbagg_mpl.js' +"GUI: Qt": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/backends/backend_qt*' + - 'lib/matplotlib/backends/qt_compat.py' + - 'lib/matplotlib/backends/qt_editor/**' +"GUI: tk": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/backends/*backend_tk*' + - 'lib/matplotlib/backends/_tkagg.pyi' + - 'src/_tkagg.cpp' + - 'src/_tkmini.h' +"GUI: webagg": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/backends/*_webagg*.py*' + - 'lib/matplotlib/backends/web_backend/**' +"GUI: wx": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/backends/backend_wx*.py*' + +"Documentation: API": + - all: + - changed-files: + - any-glob-to-any-file: + # Also files in lib/**, but we can't be sure those are only documentation. + - 'doc/api/**' + - all-globs-to-all-files: + - '!doc/api/next_api_changes/**' + +"Documentation: build": + - changed-files: + - any-glob-to-any-file: + - 'doc/conf.py' + - 'doc/Makefile' + - 'doc/make.bat' + - 'doc/sphinxext/**' +"Documentation: devdocs": + - changed-files: + - any-glob-to-any-file: + - 'doc/devel/**' +"Documentation: examples": + - changed-files: + - any-glob-to-any-file: + - 'galleries/examples/**' +"Documentation: plot types": + - changed-files: + - any-glob-to-any-file: + - 'galleries/plot_types/**' +"Documentation: tutorials": + - changed-files: + - any-glob-to-any-file: + - 'galleries/tutorials/**' +"Documentation: user guide": + - all: + - changed-files: + - any-glob-to-any-file: + - 'doc/users/**' + - 'galleries/users_explain/**' + - all-globs-to-all-files: + - '!doc/users/next_whats_new/**' + +"topic: animation": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/animation.py*' + - 'lib/matplotlib/_animation_data.py*' +"topic: axes": + - changed-files: + - any-glob-to-any-file: + # Note, axes.py is not included here because it contains many plotting + # methods, for which changes would not be considered on topic. + - 'lib/matplotlib/axes/_base.py*' +"topic: canvas and figure manager": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/backend_bases.py*' +"topic: categorical": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/category.py*' +"topic: collections and mappables": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/collections.py*' +"topic: color/color & colormaps": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/colorbar.py*' + - 'lib/matplotlib/colors.py*' + - 'lib/matplotlib/_color_data.py*' + - 'lib/matplotlib/cm.py*' + - 'lib/matplotlib/_cm.py*' + - 'lib/matplotlib/_cm_listed.py*' +"topic: contour": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/contour.py*' + - 'src/_qhull_wrapper.cpp' +"topic: date handling": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/dates.py*' +"topic: figures and subfigures": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/figure.py*' +"topic: geometry manager": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/_constrained_layout.py*' + - 'lib/matplotlib/_layoutgrid.py*' + - 'lib/matplotlib/_tight_bbox.py*' + - 'lib/matplotlib/_tight_layout.py*' + - 'lib/matplotlib/gridspec.py*' + - 'lib/matplotlib/layout_engine.py*' +"topic: hatch": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/hatch.py*' +"topic: images": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/image.py*' + - 'lib/matplotlib/_image.pyi' + - 'src/_image_*' +"topic: legend": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/legend.py*' + - 'lib/matplotlib/legend_handler.py*' +"topic: markers": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/markers.py*' +"topic: mpl_toolkit": + - all: + - changed-files: + - any-glob-to-any-file: + - 'lib/mpl_toolkits/**' + - all-globs-to-all-files: + - '!lib/mpl_toolkits/mplot3d/**' +"topic: mplot3d": + - changed-files: + - any-glob-to-any-file: + - 'lib/mpl_toolkits/mplot3d/**' +"topic: path handling": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/path.py*' + - 'lib/matplotlib/patheffects.py*' + - 'lib/matplotlib/_path.pyi' + - 'src/*path*' +"topic: polar": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/projections/polar.py*' +"topic: pyplot API": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/pyplot.py' + - 'lib/matplotlib/_pylab_helpers.py*' +"topic: rcparams": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/rcsetup.py*' +"topic: sankey": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/sankey.py*' +"topic: sphinx extension": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/sphinxext/**' +"topic: styles": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/mpl-data/stylelib/**' + - 'lib/matplotlib/style/**' +"topic: table": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/table.py*' +"topic: text": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/text.py*' + - 'lib/matplotlib/textpath.py*' +"topic: text/fonts": + - changed-files: + - any-glob-to-any-file: + - 'src/checkdep_freetype2.c' + - 'src/ft2font*' +"topic: text/mathtext": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/mathtext.py*' + - 'lib/matplotlib/_mathtext.py*' + - 'lib/matplotlib/_mathtext_data.py*' +"topic: ticks axis labels": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/axis.py*' + - 'lib/matplotlib/ticker.py*' +"topic: toolbar": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/backend_managers.py*' + - 'lib/matplotlib/backend_tools.py*' +"topic: transforms and scales": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/scale.py*' + - 'lib/matplotlib/transforms.py*' +"topic: tri": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/tri/**' + - 'src/tri/**' +"topic: units and array ducktypes": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/units.py*' +"topic: widgets/UI": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/widgets.py*' diff --git a/.github/workflows/autoclose_comment.yml b/.github/workflows/autoclose_comment.yml new file mode 100644 index 000000000000..4d18d82a801f --- /dev/null +++ b/.github/workflows/autoclose_comment.yml @@ -0,0 +1,80 @@ +--- +name: autoclose comment +# Post comment on PRs when labeled with "status: autoclose candidate". +# Based on scikit-learn's autoclose bot at +# https://github.com/scikit-learn/scikit-learn/blob/main/.github/workflows/autoclose-comment.yml + +permissions: + contents: read + pull-requests: write + +on: + pull_request_target: + types: + - labeled + +env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_REPO: ${{ github.repository }} + PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }} + +jobs: + post_comment: + name: post_comment + if: "${{ contains(github.event.label.name, 'status: autoclose candidate') }}" + runs-on: ubuntu-latest + + steps: + + - name: comment on potential autoclose + run: | + gh api \ + --method POST \ + -H "Accept: application/vnd.github+json" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + /repos/$GH_REPO/issues/$PULL_REQUEST_NUMBER/comments \ + -f "body=$BODY" + env: + BODY: > + â° This pull request might be automatically closed in two weeks from now. + + + Thank you for your contribution to Matplotlib and for the effort you + have put into this PR. This pull request does not yet meet the + quality and clarity standards needed for an effective review. + Project maintainers have limited time for code reviews, and our goal + is to prioritize well-prepared contributions to keep Matplotlib + maintainable. + + + Matplotlib maintainers cannot provide one-to-one guidance on this PR. + However, if you ask focused, well-researched questions, a community + member may be willing to help. 💬 + + + To increase the chance of a productive review: + + - Use [the template provided in the PR + description](https://github.com/matplotlib/matplotlib/blob/main/.github/PULL_REQUEST_TEMPLATE.md) + and fill it out as completely as possible, especially the summary and AI Disclosure sections. + + - Make sure your PR conforms to our [PR + checklist](https://matplotlib.org/devdocs/devel/pr_guide.html#summary-for-pull-request-authors). + + + As the author, you are responsible for driving this PR, which entails doing + necessary background research as well as presenting its context and your + thought process. If you are a new contributor, or do not know how to + fulfill these requirements, we recommend that you familiarize + yourself with Matplotlib's + [development conventions](https://matplotlib.org/devdocs/devel/index.html) + or engage with the community via our [Discourse](https://discourse.matplotlib.org/) + or one of our [meetings](https://scientific-python.org/calendars/) + before submitting code. + + + If you substantially improve this PR within two weeks, leave a comment + and a team member may remove the `status: autoclose candidate` label and the + PR stays open. Cosmetic changes or incomplete fixes will not be + sufficient. Maintainers will assess improvements on their own + schedule. Please do not ping (`@`) maintainers. diff --git a/.github/workflows/autoclose_schedule.yml b/.github/workflows/autoclose_schedule.yml new file mode 100644 index 000000000000..a4eba770699c --- /dev/null +++ b/.github/workflows/autoclose_schedule.yml @@ -0,0 +1,36 @@ +--- +name: autoclose schedule +# Autoclose PRs labeled with "status: autoclose candidate" after 2 weeks. +# Based on scikit-learn's implementation at +# https://github.com/scikit-learn/scikit-learn/blob/main/.github/workflows/autoclose-schedule.yml + +permissions: + contents: read + pull-requests: write + +on: + schedule: + - cron: '0 2 * * *' # runs daily at 02:00 UTC + workflow_dispatch: + +env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + +jobs: + + autoclose: + name: autoclose labeled PRs + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 + with: + python-version: '3.13' + - name: Install PyGithub + run: pip install -Uq PyGithub + + - name: Close PRs labeled more than 14 days ago + run: | + python tools/autoclose_prs.py diff --git a/.github/workflows/cibuildwheel.yml b/.github/workflows/cibuildwheel.yml new file mode 100644 index 000000000000..36ec0e404f1f --- /dev/null +++ b/.github/workflows/cibuildwheel.yml @@ -0,0 +1,183 @@ +--- +name: Build CI wheels + +on: + # Save CI by only running this on release branches or tags. + push: + branches: + - main + - v[0-9]+.[0-9]+.x + tags: + - v* + # Also allow running this action on PRs if requested by applying the + # "Run cibuildwheel" label. + pull_request: + types: + - opened + - synchronize + - reopened + - labeled + +permissions: {} + +jobs: + build_sdist: + if: >- + github.repository == 'matplotlib/matplotlib' && ( + github.event_name == 'push' || + github.event_name == 'pull_request' && ( + ( + github.event.action == 'labeled' && + github.event.label.name == 'CI: Run cibuildwheel' + ) || + contains(github.event.pull_request.labels.*.name, + 'CI: Run cibuildwheel') + ) + ) + name: Build sdist + runs-on: ubuntu-latest + permissions: + contents: read + outputs: + SDIST_NAME: ${{ steps.sdist.outputs.SDIST_NAME }} + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + fetch-depth: 0 + persist-credentials: false + + - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 + name: Install Python + with: + python-version: '3.12' + + # Something changed somewhere that prevents the downloaded-at-build-time + # licenses from being included in built wheels, so pre-download them so + # that they exist before the build and are included. + - name: Pre-download bundled licenses + run: > + curl -Lo LICENSE/LICENSE_QHULL + https://github.com/qhull/qhull/raw/2020.2/COPYING.txt + + - name: Install dependencies + run: python -m pip install build twine + + - name: Build sdist + id: sdist + run: | + python -m build --sdist + python ci/export_sdist_name.py + + - name: Check README rendering for PyPI + run: twine check dist/* + + - name: Upload sdist result + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: cibw-sdist + path: dist/*.tar.gz + if-no-files-found: error + + build_wheels: + if: >- + github.repository == 'matplotlib/matplotlib' && ( + github.event_name == 'push' || + github.event_name == 'pull_request' && ( + ( + github.event.action == 'labeled' && + github.event.label.name == 'CI: Run cibuildwheel' + ) || + contains(github.event.pull_request.labels.*.name, + 'CI: Run cibuildwheel') + ) + ) + needs: build_sdist + name: Build wheels on ${{ matrix.os }} for ${{ matrix.cibw_archs }} + permissions: + contents: read + runs-on: ${{ matrix.os }} + env: + CIBW_BEFORE_BUILD: >- + rm -rf {package}/build + CIBW_BEFORE_BUILD_WINDOWS: >- + pip install delvewheel && + rm -rf {package}/build + CIBW_REPAIR_WHEEL_COMMAND_WINDOWS: >- + delvewheel repair -w {dest_dir} {wheel} + CIBW_AFTER_BUILD: >- + twine check {wheel} && + python {package}/ci/check_wheel_licenses.py {wheel} + # On Windows, we explicitly request MSVC compilers (as GitHub Action runners have + # MinGW on PATH that would be picked otherwise), switch to a static build for + # runtimes, but use dynamic linking for `VCRUNTIME140.dll`, `VCRUNTIME140_1.dll`, + # and the UCRT. This avoids requiring specific versions of `MSVCP140.dll`, while + # keeping shared state with the rest of the Python process/extensions. + CIBW_CONFIG_SETTINGS_WINDOWS: >- + setup-args="--vsenv" + setup-args="-Db_vscrt=mt" + setup-args="-Dcpp_link_args=['ucrt.lib','vcruntime.lib','/nodefaultlib:libucrt.lib','/nodefaultlib:libvcruntime.lib']" + CIBW_MANYLINUX_X86_64_IMAGE: manylinux2014 + CIBW_SKIP: "*-musllinux_aarch64" + CIBW_TEST_COMMAND: >- + python {package}/ci/check_version_number.py + MACOSX_DEPLOYMENT_TARGET: "10.12" + strategy: + matrix: + include: + - os: ubuntu-latest + cibw_archs: "x86_64" + - os: ubuntu-24.04-arm + cibw_archs: "aarch64" + - os: windows-latest + cibw_archs: "AMD64" + - os: windows-11-arm + cibw_archs: "ARM64" + - os: macos-15-intel + cibw_archs: "x86_64" + - os: macos-14 + cibw_archs: "arm64" + + steps: + - name: Download sdist + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: cibw-sdist + path: dist/ + + - name: Purge Strawberry Perl + if: startsWith(matrix.os, 'windows-') + run: Remove-Item -Recurse C:\Strawberry + + - name: Build wheels for CPython 3.14 + uses: pypa/cibuildwheel@8d2b08b68458a16aeb24b64e68a09ab1c8e82084 # v3.4.1 + with: + package-dir: dist/${{ needs.build_sdist.outputs.SDIST_NAME }} + env: + CIBW_BUILD: "cp314-* cp314t-*" + CIBW_ENABLE: "cpython-freethreading cpython-prerelease" + CIBW_ARCHS: ${{ matrix.cibw_archs }} + CIBW_MANYLINUX_X86_64_IMAGE: manylinux_2_28 + + - name: Build wheels for CPython 3.13 + uses: pypa/cibuildwheel@8d2b08b68458a16aeb24b64e68a09ab1c8e82084 # v3.4.1 + with: + package-dir: dist/${{ needs.build_sdist.outputs.SDIST_NAME }} + env: + CIBW_BUILD: "cp313-* cp313t-*" + CIBW_ENABLE: cpython-freethreading + CIBW_ARCHS: ${{ matrix.cibw_archs }} + + - name: Build wheels for CPython 3.12 + uses: pypa/cibuildwheel@8d2b08b68458a16aeb24b64e68a09ab1c8e82084 # v3.4.1 + with: + package-dir: dist/${{ needs.build_sdist.outputs.SDIST_NAME }} + env: + CIBW_BUILD: "cp312-*" + CIBW_ARCHS: ${{ matrix.cibw_archs }} + + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: cibw-wheels-${{ runner.os }}-${{ matrix.cibw_archs }} + path: ./wheelhouse/*.whl + if-no-files-found: error diff --git a/.github/workflows/circleci.yml b/.github/workflows/circleci.yml index f11792486640..49dc4ea3b3ec 100644 --- a/.github/workflows/circleci.yml +++ b/.github/workflows/circleci.yml @@ -1,12 +1,78 @@ +--- +name: "CircleCI artifact handling" on: [status] + +permissions: {} + jobs: circleci_artifacts_redirector_job: + if: "${{ github.event.context == 'ci/circleci: docs-python3' }}" + permissions: + statuses: write runs-on: ubuntu-latest name: Run CircleCI artifacts redirector steps: - name: GitHub Action step - uses: larsoner/circleci-artifacts-redirector-action@master + uses: + scientific-python/circleci-artifacts-redirector-action@5d358ff96e96429a5c64a969bb4a574555439f4f # v1.3.1 with: repo-token: ${{ secrets.GITHUB_TOKEN }} + api-token: ${{ secrets.CIRCLECI_TOKEN }} artifact-path: 0/doc/build/html/index.html - circleci-jobs: docs-python36,docs-python37,docs-python38 + circleci-jobs: docs-python3 + job-title: View the built docs + + post_warnings_as_review: + if: "${{ github.event.context == 'ci/circleci: docs-python3' }}" + permissions: + contents: read + checks: write + pull-requests: write + runs-on: ubuntu-latest + name: Post warnings/errors as review + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + + - name: Fetch result artifacts + id: fetch-artifacts + env: + target_url: "${{ github.event.target_url }}" + run: | + python .circleci/fetch_doc_logs.py "${target_url}" + + - name: Set up reviewdog + if: "${{ steps.fetch-artifacts.outputs.count != 0 }}" + uses: reviewdog/action-setup@d8a7baabd7f3e8544ee4dbde3ee41d0011c3a93f # v1.5.0 + with: + reviewdog_version: latest + + - name: Post review + if: "${{ steps.fetch-artifacts.outputs.count != 0 }}" + env: + REVIEWDOG_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} + REVIEWDOG_SKIP_DOGHOUSE: "true" + CI_COMMIT: ${{ github.event.sha }} + CI_REPO_OWNER: ${{ github.event.repository.owner.login }} + CI_REPO_NAME: ${{ github.event.repository.name }} + run: | + # The 'status' event does not contain information in the way that + # reviewdog expects, so we unset those so it reads from the + # environment variables we set above. + unset GITHUB_ACTIONS GITHUB_EVENT_PATH + cat logs/sphinx-errors-warnings.log | \ + reviewdog \ + -efm '%f\:%l: %tEBUG: %m' \ + -efm '%f\:%l: %tNFO: %m' \ + -efm '%f\:%l: %tARNING: %m' \ + -efm '%f\:%l: %tRROR: %m' \ + -efm '%f\:%l: %tEVERE: %m' \ + -efm '%f\:%s: %tARNING: %m' \ + -efm '%f\:%s: %tRROR: %m' \ + -name=sphinx -tee -fail-on-error=false \ + -reporter=github-check -filter-mode=nofilter + cat logs/sphinx-deprecations.log | \ + reviewdog \ + -efm '%f\:%l: %m' \ + -name=examples -tee -reporter=github-check -filter-mode=nofilter diff --git a/.github/workflows/clean_pr.yml b/.github/workflows/clean_pr.yml new file mode 100644 index 000000000000..75f6a451c7ee --- /dev/null +++ b/.github/workflows/clean_pr.yml @@ -0,0 +1,55 @@ +--- +name: PR cleanliness +on: [pull_request] + +permissions: {} + +jobs: + pr_clean: + runs-on: ubuntu-latest + permissions: + contents: read + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + fetch-depth: '0' + persist-credentials: false + - name: Check for added-and-deleted files + run: | + git fetch --quiet origin "$GITHUB_BASE_REF" + base="$(git merge-base "origin/$GITHUB_BASE_REF" 'HEAD^2')" + ad="$(git log "$base..HEAD^2" --pretty=tformat: --name-status --diff-filter=AD | + cut --fields 2 | sort | uniq --repeated)" + if [[ -n "$ad" ]]; then + printf 'The following files were both added and deleted in this PR:\n%s\n' "$ad" + exit 1 + fi + - name: Check for added-and-modified images + run: | + git fetch --quiet origin "$GITHUB_BASE_REF" + base="$(git merge-base "origin/$GITHUB_BASE_REF" 'HEAD^2')" + am="$(git log "$base..HEAD^2" --pretty=tformat: --name-status --diff-filter=AM | + cut --fields 2 | sort | uniq --repeated | + grep -E '\.(png|pdf|ps|eps|svg)' || true)" + if [[ -n "$am" ]]; then + printf 'The following images were both added and modified in this PR:\n%s\n' "$am" + exit 1 + fi + - name: Check for invalid backports to -doc branches + if: endsWith(github.base_ref, '-doc') + run: | + git fetch --quiet origin "$GITHUB_BASE_REF" + base="$(git merge-base "origin/$GITHUB_BASE_REF" 'HEAD^2')" + lib="$(git log "$base..HEAD^2" --pretty=tformat: --name-status -- lib src | + cut --fields 2 | sort || true)" + if [[ -n "$lib" ]]; then + printf 'Changes to the following files have no effect and should not be backported:\n%s\n' "$lib" + exit 1 + fi + - name: Check for branches opened against main + if: github.ref_name == 'main' + run: | + echo 'PR branch should not be main.' + echo 'See https://matplotlib.org/devdocs/devel/development_workflow.html#make-a-new-feature-branch' + exit 1 diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 000000000000..3dc935180f6e --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,48 @@ +--- +name: "CodeQL" + +on: + push: + branches: [main, v*.x] + pull_request: + # The branches below must be a subset of the branches above + branches: [main] + schedule: + - cron: '45 19 * * 1' + +permissions: {} + +jobs: + analyze: + if: github.repository == 'matplotlib/matplotlib' + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: ['c-cpp', 'javascript', 'python'] + + steps: + - name: Checkout repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + + - name: Initialize CodeQL + uses: github/codeql-action/init@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4.36.0 + with: + languages: ${{ matrix.language }} + + - name: Build compiled code + if: matrix.language == 'c-cpp' + run: | + pip install --user --upgrade pip + pip install --user -v . + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4.36.0 diff --git a/.github/workflows/conflictcheck.yml b/.github/workflows/conflictcheck.yml new file mode 100644 index 000000000000..e353e47bfb79 --- /dev/null +++ b/.github/workflows/conflictcheck.yml @@ -0,0 +1,26 @@ +--- +name: "Maintenance" +on: + # So that PRs touching the same files as the push are updated + push: + # So that the `dirtyLabel` is removed if conflicts are resolve + # We recommend `pull_request_target` so that github secrets are available. + # In `pull_request` we wouldn't be able to change labels of fork PRs + pull_request_target: + types: [synchronize] + +permissions: {} + +jobs: + main: + if: github.repository == 'matplotlib/matplotlib' + runs-on: ubuntu-latest + permissions: + pull-requests: write + steps: + - name: Check if PRs have merge conflicts + uses: eps1lon/actions-label-merge-conflict@0273be72a0bbd58fcd71d0d6c02c209b50d1e5e1 # v3.1.0 + with: + dirtyLabel: "status: needs rebase" + repoToken: "${{ secrets.GITHUB_TOKEN }}" + retryMax: 10 diff --git a/.github/workflows/cygwin.yml b/.github/workflows/cygwin.yml new file mode 100644 index 000000000000..8e970ea1120c --- /dev/null +++ b/.github/workflows/cygwin.yml @@ -0,0 +1,241 @@ +--- +name: Cygwin Tests +concurrency: + group: ${{ github.workflow }}-${{ github.event.number }}-${{ github.event.ref }} + cancel-in-progress: true + +on: + push: + branches: + - main + - v[0-9]+.[0-9]+.[0-9x]+ + tags: + - v* + paths: + - 'src/**' + - '.github/workflows/cygwin.yml' + pull_request: + types: + - opened + - synchronize + - reopened + - labeled + branches-ignore: + - v[0-9]+.[0-9]+.[0-9x]+-doc + paths: + - 'src/**' + - '.github/workflows/cygwin.yml' + schedule: + # 5:47 UTC on Saturdays + - cron: "47 5 * * 6" + workflow_dispatch: + +permissions: {} + +env: + NO_AT_BRIDGE: 1 # Necessary for GTK3 interactive test. + OPENBLAS_NUM_THREADS: 1 + PYTHONFAULTHANDLER: 1 + SHELLOPTS: igncr + CYGWIN_NOWINPATH: 1 + CHERE_INVOKING: 1 + TMP: /tmp + TEMP: /tmp + +jobs: + + test-cygwin: + runs-on: windows-latest + permissions: + contents: read + name: Python 3.${{ matrix.python-minor-version }} on Cygwin + # Enable these when Cygwin has Python 3.12. + if: >- + github.event_name == 'workflow_dispatch' || + (false && github.event_name == 'schedule') || + ( + false && + github.repository == 'matplotlib/matplotlib' && + !contains(github.event.head_commit.message, '[ci skip]') && + !contains(github.event.head_commit.message, '[skip ci]') && + !contains(github.event.head_commit.message, '[skip github]') && + !contains(github.event.head_commit.message, '[ci doc]') && + ( + github.event_name == 'push' || + github.event_name == 'pull_request' && + ( + ( + github.event.action == 'labeled' && + github.event.label.name == 'CI: Run cygwin' + ) || + contains(github.event.pull_request.labels.*.name, 'CI: Run cygwin') + ) + ) + ) + strategy: + matrix: + python-minor-version: [12] + + steps: + - name: Fix line endings + run: git config --global core.autocrlf input + + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + fetch-depth: 0 + persist-credentials: false + + - uses: cygwin/cygwin-install-action@711d29f3da23c9f4a1798e369a6f01198c13b11a # v6 + with: + packages: >- + ccache gcc-g++ gdb git graphviz libcairo-devel libffi-devel + libgeos-devel libQt5Core-devel pkgconf libglib2.0-devel ninja + noto-cjk-fonts + python3${{ matrix.python-minor-version }}-devel + python3${{ matrix.python-minor-version }}-pip + python3${{ matrix.python-minor-version }}-wheel + python3${{ matrix.python-minor-version }}-setuptools + python3${{ matrix.python-minor-version }}-cycler + python3${{ matrix.python-minor-version }}-dateutil + python3${{ matrix.python-minor-version }}-fonttools + python3${{ matrix.python-minor-version }}-imaging + python3${{ matrix.python-minor-version }}-kiwisolver + python3${{ matrix.python-minor-version }}-numpy + python3${{ matrix.python-minor-version }}-packaging + python3${{ matrix.python-minor-version }}-pyparsing + python3${{ matrix.python-minor-version }}-sip + python3${{ matrix.python-minor-version }}-sphinx + python-cairo-devel + python3${{ matrix.python-minor-version }}-cairo + python3${{ matrix.python-minor-version }}-gi + python3${{ matrix.python-minor-version }}-matplotlib + xorg-server-extra libxcb-icccm4 libxcb-image0 + libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 + libxcb-xinerama0 + make autoconf autoconf2.5 automake automake1.10 libtool m4 + libqhull-devel libfreetype-devel + libjpeg-devel libwebp-devel + + - name: Set runner username to root and id to 0 + shell: bash.exe -eo pipefail -o igncr "{0}" + # GitHub Actions runs everything as Administrator. I don't + # know how to test for this, so set the uid for the CI job so + # that the existing unix root detection will work. + run: /bin/mkpasswd.exe -c | sed -e "s/$(id -u)/0/" >/etc/passwd + + - name: Mark test repo safe + shell: bash.exe -eo pipefail -o igncr "{0}" + run: | + git.exe config --global --add safe.directory /proc/cygdrive/d/a/matplotlib/matplotlib + git config --global --add safe.directory /cygdrive/d/a/matplotlib/matplotlib + C:/cygwin/bin/git.exe config --global --add safe.directory D:/a/matplotlib/matplotlib + /usr/bin/git config --global --add safe.directory /cygdrive/d/a/matplotlib/matplotlib + + - name: Use dash for /bin/sh + shell: bash.exe -eo pipefail -o igncr "{0}" + run: | + ls -l /bin/sh.exe /bin/bash.exe /bin/dash.exe + /bin/rm -f /bin/sh.exe || exit 1 + cp -sf /bin/dash.exe /bin/sh.exe || exit 1 + ls -l /bin/sh.exe /bin/bash.exe /bin/dash.exe + # FreeType build fails with bash, succeeds with dash + + - name: Cache pip + uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + with: + path: C:\cygwin\home\runneradmin\.cache\pip + key: Cygwin-py3.${{ matrix.python-minor-version }}-pip-${{ hashFiles('pyproject.toml') }} + restore-keys: ${{ matrix.os }}-py3.${{ matrix.python-minor-version }}-pip- + + - name: Cache ccache + uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + with: + path: C:\cygwin\home\runneradmin\.ccache + key: Cygwin-py3.${{ matrix.python-minor-version }}-ccache-${{ hashFiles('src/*') }} + restore-keys: Cygwin-py3.${{ matrix.python-minor-version }}-ccache- + + - name: Cache Matplotlib + uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + with: + path: | + C:\cygwin\home\runneradmin\.cache\matplotlib + !C:\cygwin\home\runneradmin\.cache\matplotlib\tex.cache + !C:\cygwin\home\runneradmin\.cache\matplotlib\test_cache + key: 1-Cygwin-py3.${{ matrix.python-minor-version }}-mpl-${{ github.ref }}-${{ github.sha }} + restore-keys: | + 1-Cygwin-py3.${{ matrix.python-minor-version }}-mpl-${{ github.ref }}- + 1-Cygwin-py3.${{ matrix.python-minor-version }}-mpl- + + - name: Ensure correct Python version + shell: bash.exe -eo pipefail -o igncr "{0}" + run: | + /usr/sbin/alternatives --set python /usr/bin/python3.${{ matrix.python-minor-version }} + /usr/sbin/alternatives --set python3 /usr/bin/python3.${{ matrix.python-minor-version }} + + - name: Install Python dependencies + shell: bash.exe -eo pipefail -o igncr "{0}" + run: | + python -m pip install --group build 'numpy>=1.25,<1.26' + export PATH="/usr/local/bin:$PATH" + python -m pip install --upgrade --group test sphinx ipython + python -m pip install --upgrade pycairo 'cairocffi>=0.8' PyGObject && + python -c 'import gi; gi.require_version("Gtk", "3.0"); from gi.repository import Gtk' && + echo 'PyGObject is available' || + echo 'PyGObject is not available' + python -m pip install --upgrade pyqt5 && + python -c 'import PyQt5.QtCore' && + echo 'PyQt5 is available' || + echo 'PyQt5 is not available' + python -m pip uninstall --yes wxpython || echo 'wxPython already uninstalled' + + - name: Install Matplotlib + shell: bash.exe -eo pipefail -o igncr "{0}" + env: + AUTOCONF: /usr/bin/autoconf-2.69 + MAKEFLAGS: dw + run: | + export PATH="/usr/local/bin:$PATH" + ccache -s + git describe + # All dependencies must have been pre-installed, so that the minver + # constraints are held. + python -m pip install --no-deps --no-build-isolation --verbose \ + --config-settings=setup-args="-DrcParams-backend=Agg" \ + --editable .[dev] + + - name: Find DLLs to rebase + shell: bash.exe -eo pipefail -o igncr "{0}" + run: | + find {/usr,/usr/local}/{bin,lib/python3.*/site-packages} /usr/lib/lapack . \ + -name \*.exe -o -name \*.dll -print >files_to_rebase.txt + + - name: Rebase DLL list + shell: ash.exe "{0}" + run: "rebase --database --filelist=files_to_rebase.txt" + # Inplace modification of DLLs to assign non-overlapping load + # addresses so fork() works as expected. Ash is used as it + # does not link against any Cygwin DLLs that might need to be + # rebased. + + - name: Check that Matplotlib imports + shell: bash.exe -eo pipefail -o igncr "{0}" + run: | + /usr/bin/python -c "import matplotlib as mpl; import matplotlib.pyplot as plt" + + - name: Set ffmpeg path + shell: bash.exe -eo pipefail -o igncr "{0}" + run: | + oldmplrc=$(python -c "from matplotlib import matplotlib_fname as mplrc_file; print(mplrc_file())") + echo "${oldmplrc}" + mkdir -p ~/.matplotlib/ + sed -E \ + -e 's~#animation\.ffmpeg_path:.+~animation.ffmpeg_path: /usr/bin/ffmpeg.exe~' \ + "${oldmplrc}" >~/.matplotlib/matplotlibrc + + - name: Run pytest + shell: bash.exe -eo pipefail -o igncr "{0}" + id: cygwin-run-pytest + run: | + xvfb-run pytest-3.${{ matrix.python-minor-version }} -rfEsXR -n auto \ + --maxfail=50 --timeout=300 --durations=25 \ + --cov-report=term --cov=lib --log-level=DEBUG --color=yes diff --git a/.github/workflows/do_not_merge.yml b/.github/workflows/do_not_merge.yml new file mode 100644 index 000000000000..0c263623942b --- /dev/null +++ b/.github/workflows/do_not_merge.yml @@ -0,0 +1,31 @@ +--- +name: Do Not Merge + +# action to block merging on specific labels +on: + pull_request: + types: [synchronize, opened, reopened, labeled, unlabeled] + +permissions: {} + +jobs: + do-not-merge: + name: Prevent Merging + runs-on: ubuntu-latest + env: + has_tag: >- + ${{contains(github.event.pull_request.labels.*.name, 'status: needs comment/discussion') || + contains(github.event.pull_request.labels.*.name, 'status: waiting for other PR') || + contains(github.event.pull_request.labels.*.name, 'DO NOT MERGE') }} + steps: + - name: Check for label + if: ${{'true' == env.has_tag}} + run: | + echo "This PR cannot be merged because it has one of the following labels: " + echo "* status: needs comment/discussion" + echo "* status: waiting for other PR" + echo "* DO NOT MERGE" + exit 1 + - name: Allow merging + if: ${{'false' == env.has_tag}} + run: exit 0 diff --git a/.github/workflows/good-first-issue.yml b/.github/workflows/good-first-issue.yml new file mode 100644 index 000000000000..6543f05a0837 --- /dev/null +++ b/.github/workflows/good-first-issue.yml @@ -0,0 +1,36 @@ +--- +name: Add comment on good first issues +on: + issues: + types: + - labeled + +permissions: {} + +jobs: + add-comment: + if: github.event.label.name == 'Good first issue' + runs-on: ubuntu-latest + permissions: + issues: write + steps: + - name: Add comment + uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v5.0.0 + with: + issue-number: ${{ github.event.issue.number }} + body: | + ### Good first issue - notes for new contributors + + This issue is suited to new contributors because it does not require + understanding of the Matplotlib internals. This is a non-urgent task + intended for human contributors to learn how to contribute; therefore please + do not try to automate a solution using AI. To get started, please see our + [contributing guide](https://matplotlib.org/stable/devel/index). + + **We do not assign issues**. Check the *Development* section in the sidebar + for linked pull requests (PRs). If there are none, feel free to start + working on it. If there is an open PR, please collaborate on the work by + reviewing it rather than duplicating it in a competing PR. + + If something is unclear, please reach out on any of our [communication + channels](https://matplotlib.org/stable/devel/contributing.html#get-connected). diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml new file mode 100644 index 000000000000..600e7fc34a95 --- /dev/null +++ b/.github/workflows/labeler.yml @@ -0,0 +1,17 @@ +--- +name: "Pull Request Labeler" +on: + - pull_request_target + +permissions: {} + +jobs: + labeler: + permissions: + contents: read + pull-requests: write + runs-on: ubuntu-latest + steps: + - uses: actions/labeler@f27b608878404679385c85cfa523b85ccb86e213 # v6.1.0 + with: + sync-labels: true diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml new file mode 100644 index 000000000000..407ac44258c0 --- /dev/null +++ b/.github/workflows/linting.yml @@ -0,0 +1,135 @@ +--- +name: Linting +on: [pull_request] + +permissions: {} + +jobs: + pre-commit: + name: precommit + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + fetch-depth: 0 + persist-credentials: false + - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 + with: + python-version: "3.x" + - uses: j178/prek-action@bdca6f102f98e2b4c7029491a53dfd366469e33d # v2.0.4 + with: + extra-args: --hook-stage manual --all-files + + ruff: + name: ruff + runs-on: ubuntu-latest + permissions: + contents: read + checks: write + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + + - name: Set up Python 3 + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 + with: + python-version: '3.12' + + - name: Install ruff + run: pip3 install ruff + + - name: Set up reviewdog + uses: reviewdog/action-setup@d8a7baabd7f3e8544ee4dbde3ee41d0011c3a93f # v1.5.0 + + - name: Run ruff + env: + REVIEWDOG_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + set -o pipefail + ruff check --output-format rdjson | \ + reviewdog -f=rdjson \ + -tee -reporter=github-check -filter-mode nofilter + mypy: + name: mypy + runs-on: ubuntu-latest + permissions: + contents: read + checks: write + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + + - name: Set up Python 3 + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 + with: + python-version: '3.12' + + - name: Install mypy + run: pip3 install --group build --group typing + + - name: Set up reviewdog + uses: reviewdog/action-setup@d8a7baabd7f3e8544ee4dbde3ee41d0011c3a93f # v1.5.0 + + - name: Run mypy + env: + REVIEWDOG_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + set -o pipefail + mypy --config pyproject.toml | \ + reviewdog -f=mypy -name=mypy \ + -tee -reporter=github-check -filter-mode nofilter + + + clang-tidy: + name: clang-tidy (macOS / Objective-C) + runs-on: macos-latest # run on macOS so we can lint the objectiveC file + permissions: + contents: read + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + + - name: Set up Python 3 + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 + with: + python-version: '3.14' + + - name: Install OS dependencies + run: brew install llvm + + - name: Install build dependencies + run: pip3 install meson ninja pybind11 setuptools-scm + + - name: Run clang-tidy + run: | + set -o pipefail + LLVM_PREFIX=$(brew --prefix llvm) + export CC=$LLVM_PREFIX/bin/clang + export CXX=$LLVM_PREFIX/bin/clang++ + export OBJC=$LLVM_PREFIX/bin/clang + export PATH=$LLVM_PREFIX/bin:$PATH + python tools/run_clang_tidy.py + + eslint: + name: eslint + runs-on: ubuntu-latest + permissions: + contents: read + checks: write + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + + - name: eslint + uses: reviewdog/action-eslint@556a3fdaf8b4201d4d74d406013386aa4f7dab96 # v1.34.0 + with: + filter_mode: nofilter + github_token: ${{ secrets.GITHUB_TOKEN }} + reporter: github-check + workdir: 'lib/matplotlib/backends/web_backend/' diff --git a/.github/workflows/mypy-stubtest.yml b/.github/workflows/mypy-stubtest.yml new file mode 100644 index 000000000000..da3ff7610901 --- /dev/null +++ b/.github/workflows/mypy-stubtest.yml @@ -0,0 +1,47 @@ +--- +name: Mypy Stubtest +on: [pull_request] + +permissions: {} + +jobs: + mypy-stubtest: + name: mypy-stubtest + runs-on: ubuntu-latest + permissions: + contents: read + checks: write + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + + - name: Set up Python 3 + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 + with: + python-version: '3.12' + + - name: Set up reviewdog + uses: reviewdog/action-setup@d8a7baabd7f3e8544ee4dbde3ee41d0011c3a93f # v1.5.0 + + - name: Install tox + run: python -m pip install tox + + - name: Run mypy stubtest + env: + REVIEWDOG_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + set -o pipefail + tox -e stubtest | \ + sed -e "s!.tox/stubtest/lib/python3.12/site-packages!lib!g" | \ + reviewdog \ + -efm '%Eerror: %m' \ + -efm '%CStub: in file %f:%l' \ + -efm '%CStub: in file %f' \ + -efm '%+CRuntime:%.%#' \ + -efm '%+CMISSING' \ + -efm '%+Cdef %.%#' \ + -efm '%+C<%.%#>' \ + -efm '%Z' \ + -reporter=github-check -tee -name=mypy-stubtest \ + -filter-mode=nofilter diff --git a/.github/workflows/nightlies.yml b/.github/workflows/nightlies.yml new file mode 100644 index 000000000000..47d1de50781c --- /dev/null +++ b/.github/workflows/nightlies.yml @@ -0,0 +1,66 @@ +--- +name: Upload nightly wheels to Anaconda Cloud + +on: + # Run daily at 1:23 UTC to upload nightly wheels to Anaconda Cloud + schedule: + - cron: '23 1 * * *' + # Run on demand with workflow dispatch + workflow_dispatch: + +permissions: {} + +jobs: + upload_nightly_wheels: + name: Upload nightly wheels to Anaconda Cloud + runs-on: ubuntu-latest + defaults: + run: + # The login shell is necessary for the setup-micromamba setup + # to work in subsequent jobs. + # https://github.com/mamba-org/setup-micromamba#about-login-shells + shell: bash -e -l {0} + permissions: + actions: read + if: github.repository_owner == 'matplotlib' + + steps: + # https://github.com/actions/download-artifact/issues/3#issuecomment-1017141067 + - name: Download wheel artifacts from last build on 'main' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + PROJECT_REPO="matplotlib/matplotlib" + BRANCH="main" + ARTIFACT_PATTERN="cibw-wheels-*" + + for WORKFLOW_NAME in cibuildwheel.yml wasm.yml; do + gh run --repo "${PROJECT_REPO}" \ + list --branch "${BRANCH}" \ + --workflow "${WORKFLOW_NAME}" \ + --json event,status,conclusion,databaseId > runs.json + RUN_ID=$( + jq --compact-output \ + '[ + .[] | + # Filter on "push" events to main (merged PRs) ... + select(.event == "push") | + # that have completed successfully ... + select(.status == "completed" and .conclusion == "success") + ] | + # and get ID of latest build of wheels. + sort_by(.databaseId) | reverse | .[0].databaseId' runs.json + ) + gh run --repo "${PROJECT_REPO}" view "${RUN_ID}" + gh run --repo "${PROJECT_REPO}" download "${RUN_ID}" --pattern "${ARTIFACT_PATTERN}" + done + + mkdir dist + mv ${ARTIFACT_PATTERN}/*.whl dist/ + ls -l dist/ + + - name: Upload wheels to Anaconda Cloud as nightlies + uses: scientific-python/upload-nightly-action@e76cfec8a4611fd02808a801b0ff5a7d7c1b2d99 # 0.6.4 + with: + artifacts_path: dist + anaconda_nightly_upload_token: ${{ secrets.ANACONDA_ORG_UPLOAD_TOKEN }} diff --git a/.github/workflows/pr_welcome.yml b/.github/workflows/pr_welcome.yml new file mode 100644 index 000000000000..f8b004dc5468 --- /dev/null +++ b/.github/workflows/pr_welcome.yml @@ -0,0 +1,52 @@ +--- +name: PR Greetings + +on: + pull_request_target: + types: opened + issues: + types: opened + +permissions: {} + +jobs: + greeting: + runs-on: ubuntu-latest + permissions: + issues: write + pull-requests: write + steps: + - uses: plbstl/first-contribution@2c36bdb58684587f60549a69aaa3ec00b9d5f4fe # v4.3.3 + with: + labels: first-contribution + skip-internal-contributors: false + pr-opened-msg: >+ + Thank you for opening your first PR into Matplotlib! + + + If you have not heard from us in a week or so, please leave a new + comment below and that should bring it to our attention. + Most of our reviewers are volunteers and sometimes things fall + through the cracks. We also ask that you please finish addressing + any review comments on this PR and wait for it to be merged (or + closed) before opening a new one, as it can be a valuable learning + experience to go through the review process. + + + You can also join us [on discourse + chat](https://discourse.matplotlib.org/chat/c/matplotlib/2) for + real-time discussion. + + + For details on testing, writing docs, and our review process, + please see [the developer + guide](https://matplotlib.org/devdocs/devel/index.html). + + **Please let us know if (and how) you use AI, it will help us give you + better feedback on your PR.** + + + We strive to be a welcoming and open project. Please follow our + [Code of + Conduct](https://github.com/matplotlib/matplotlib/blob/main/CODE_OF_CONDUCT.md). + issue-opened-msg: "" diff --git a/.github/workflows/reviewdog.yml b/.github/workflows/reviewdog.yml deleted file mode 100644 index d235cec9c2e5..000000000000 --- a/.github/workflows/reviewdog.yml +++ /dev/null @@ -1,45 +0,0 @@ -name: Linting -on: [pull_request] - -jobs: - flake8: - name: flake8 - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - - name: Set up Python 3 - uses: actions/setup-python@v1 - with: - python-version: 3.8 - - - name: Install flake8 - run: pip3 install -r requirements/testing/flake8.txt - - - name: Set up reviewdog - run: | - mkdir -p $HOME/bin - curl -sfL \ - https://github.com/reviewdog/reviewdog/raw/master/install.sh | \ - sh -s -- -b $HOME/bin - echo ::add-path::$HOME/bin - - - name: Run flake8 - env: - REVIEWDOG_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - flake8 --docstring-convention=all | \ - reviewdog -f=pep8 -name=flake8 -reporter=github-check - - eslint: - name: eslint - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - - name: eslint - uses: reviewdog/action-eslint@v1 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - reporter: github-check - workdir: 'lib/matplotlib/backends/web_backend/' diff --git a/.github/workflows/stale-tidy.yml b/.github/workflows/stale-tidy.yml new file mode 100644 index 000000000000..e7d8272bdf24 --- /dev/null +++ b/.github/workflows/stale-tidy.yml @@ -0,0 +1,28 @@ +--- +name: 'Close inactive issues' +on: + schedule: + - cron: '30 1 * * 2,4,6' + +permissions: {} + +jobs: + stale: + if: github.repository == 'matplotlib/matplotlib' + runs-on: ubuntu-latest + permissions: + issues: write + steps: + - uses: actions/stale@eb5cf3af3ac0a1aa4c9c45633dd1ae542a27a899 # v10.3.0 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + operations-per-run: 300 + days-before-stale: -1 + stale-pr-label: "status: inactive" + days-before-pr-close: -1 + stale-issue-label: "status: inactive" + close-issue-label: "status: closed as inactive" + days-before-issue-close: 30 + ascending: true + exempt-issue-labels: "keep,status: confirmed bug" + exempt-pr-labels: "keep,status: orphaned PR" diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml new file mode 100644 index 000000000000..4ebcdcee1f31 --- /dev/null +++ b/.github/workflows/stale.yml @@ -0,0 +1,44 @@ +--- +name: 'Label inactive PRs' +on: + schedule: + - cron: '30 1 * * 1' + +permissions: {} + +jobs: + stale: + if: github.repository == 'matplotlib/matplotlib' + runs-on: ubuntu-latest + permissions: + issues: write + pull-requests: write + steps: + - uses: actions/stale@eb5cf3af3ac0a1aa4c9c45633dd1ae542a27a899 # v10.3.0 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + operations-per-run: 20 + stale-pr-message: >- + Since this Pull Request has not been updated in 60 days, it has been marked "inactive." This does + not mean that it will be closed, though it may be moved to a "Draft" state. This helps maintainers + prioritize their reviewing efforts. You can pick the PR back up anytime - please ping us if you + need a review or guidance to move the PR forward! If you do not plan on continuing the work, please + let us know so that we can either find someone to take the PR over, or close it. + stale-pr-label: "status: inactive" + days-before-pr-stale: 60 + days-before-pr-close: -1 + stale-issue-message: >- + This issue has been marked "inactive" because it has been 365 days since the last comment. If this + issue is still present in recent Matplotlib releases, or the feature request is still wanted, + please leave a comment and this label will be removed. If there are no updates in another 30 days, + this issue will be automatically closed, but you are free to re-open or create a new issue if + needed. We value issue reports, and this procedure is meant to help us resurface and prioritize + issues that have not been addressed yet, not make them disappear. Thanks for your help! + stale-issue-label: "status: inactive" + close-issue-label: "status: closed as inactive" + days-before-issue-stale: 365 + days-before-issue-close: 30 + ascending: true + exempt-issue-labels: "keep" + exempt-pr-labels: "keep,status: orphaned PR" + sort-by: updated diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 000000000000..2142e908d5e9 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,417 @@ +--- +name: Tests +concurrency: + group: ${{ github.workflow }}-${{ github.event.number }}-${{ github.event.ref }} + cancel-in-progress: true + +on: + push: + branches-ignore: + - auto-backport-of-pr-[0-9]+ + - v[0-9]+.[0-9]+.[0-9x]+-doc + - dependabot/** + pull_request: + branches-ignore: + - v[0-9]+.[0-9]+.[0-9x]+-doc + paths-ignore: + # Skip running tests if changes are only in documentation directories + - 'doc/**' + - 'galleries/**' + schedule: + # 5:47 UTC on Saturdays + - cron: "47 5 * * 6" + workflow_dispatch: + +permissions: {} + +env: + NO_AT_BRIDGE: 1 # Necessary for GTK3 interactive test. + OPENBLAS_NUM_THREADS: 1 + PYTHONFAULTHANDLER: 1 + +jobs: + test: + if: >- + github.event_name == 'workflow_dispatch' || + ( + github.repository == 'matplotlib/matplotlib' && + !contains(github.event.head_commit.message, '[ci skip]') && + !contains(github.event.head_commit.message, '[skip ci]') && + !contains(github.event.head_commit.message, '[skip github]') && + !contains(github.event.head_commit.message, '[ci doc]') + ) + permissions: + contents: read + name: "Python ${{ matrix.python-version }} on ${{ matrix.os }} ${{ matrix.name-suffix }}" + runs-on: ${{ matrix.os }} + + strategy: + fail-fast: false + matrix: + include: + - name-suffix: "(Minimum Versions)" + os: ubuntu-22.04 + python-version: '3.12' + extra-requirements: '-c ci/minver-requirements.txt' + delete-font-cache: true + # https://github.com/matplotlib/matplotlib/issues/29844 + pygobject-ver: '<3.52.0' + - os: ubuntu-22.04 + python-version: '3.12' + CFLAGS: "-fno-lto" # Ensure that disabling LTO works. + extra-requirements: '--group test-extra' + # https://github.com/matplotlib/matplotlib/issues/29844 + pygobject-ver: '<3.52.0' + - name-suffix: "(Extra TeX packages)" + os: ubuntu-22.04 + python-version: '3.13' + extra-packages: 'texlive-fonts-extra texlive-lang-cyrillic' + # https://github.com/matplotlib/matplotlib/issues/29844 + pygobject-ver: '<3.52.0' + - name-suffix: "Free-threaded" + os: ubuntu-22.04 + python-version: '3.14t' + # https://github.com/matplotlib/matplotlib/issues/29844 + pygobject-ver: '<3.52.0' + - os: ubuntu-24.04 + python-version: '3.14' + - os: ubuntu-24.04-arm + python-version: '3.12' + - os: macos-14 # This runner is on M1 (arm64) chips. + python-version: '3.12' + # https://github.com/matplotlib/matplotlib/issues/29732 + pygobject-ver: '<3.52.0' + - os: macos-15 # This runner is on M1 (arm64) chips. + python-version: '3.13' + # https://github.com/matplotlib/matplotlib/issues/29732 + pygobject-ver: '<3.52.0' + - os: macos-15 # This runner is on M1 (arm64) chips. + python-version: '3.14' + # https://github.com/matplotlib/matplotlib/issues/29732 + pygobject-ver: '<3.52.0' + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + fetch-depth: 0 + persist-credentials: false + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 + with: + python-version: ${{ matrix.python-version }} + allow-prereleases: true + + - name: Install OS dependencies + run: | + case "${{ runner.os }}" in + Linux) + echo 'Acquire::Retries "3";' | sudo tee /etc/apt/apt.conf.d/80-retries + sudo apt-get update -yy + sudo apt-get install -yy --no-install-recommends \ + ccache \ + cm-super \ + dvipng \ + fonts-freefont-otf \ + fonts-noto-cjk \ + fonts-wqy-zenhei \ + gdb \ + gir1.2-gtk-3.0 \ + gir1.2-gtk-4.0 \ + graphviz \ + inkscape \ + language-pack-de \ + lcov \ + libcairo2 \ + libcairo2-dev \ + libffi-dev \ + libgeos-dev \ + libnotify4 \ + libsdl2-2.0-0 \ + libxkbcommon-x11-0 \ + libxcb-cursor0 \ + libxcb-icccm4 \ + libxcb-image0 \ + libxcb-keysyms1 \ + libxcb-randr0 \ + libxcb-render-util0 \ + libxcb-xinerama0 \ + lmodern \ + ninja-build \ + pkg-config \ + qtbase5-dev \ + texlive-fonts-recommended \ + texlive-latex-base \ + texlive-latex-extra \ + texlive-latex-recommended \ + texlive-luatex \ + texlive-pictures \ + texlive-xetex \ + ${{ matrix.extra-packages }} + if [[ "${{ matrix.name-suffix }}" != '(Minimum Versions)' ]]; then + sudo apt-get install -yy --no-install-recommends ffmpeg poppler-utils + fi + if [[ "${{ matrix.os }}" = ubuntu-22.04 ]]; then + sudo apt-get install -yy --no-install-recommends \ + libgirepository1.0-dev + else # ubuntu-24.04 + sudo apt-get install -yy --no-install-recommends \ + libgirepository-2.0-dev + fi + ;; + macOS) + brew update + # Periodically, Homebrew updates Python and fails to overwrite the + # existing not-managed-by-Homebrew copy without explicitly being told + # to do so. GitHub/Azure continues to avoid fixing their runner images: + # https://github.com/actions/runner-images/issues/9966 + # so force an overwrite even if there are no Python updates. + # We don't even care about Homebrew's Python because we use the one + # from actions/setup-python. + for python_package in $(brew list | grep python@); do + brew unlink ${python_package} + brew link --overwrite ${python_package} + done + # Workaround for https://github.com/actions/runner-images/issues/10984 + brew uninstall --ignore-dependencies --force pkg-config@0.29.2 + brew install ccache ffmpeg ghostscript gobject-introspection gtk4 imagemagick ninja + brew install --cask font-noto-sans-cjk font-noto-sans-cjk-sc inkscape + ;; + esac + + - name: Cache pip + uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + if: startsWith(runner.os, 'Linux') + with: + path: ~/.cache/pip + key: | + ${{ matrix.os }}-py${{ matrix.python-version }}-pip-${{ + hashFiles('pyproject.toml', 'ci/minver-requirements.txt') }} + restore-keys: | + ${{ matrix.os }}-py${{ matrix.python-version }}-pip- + - name: Cache pip + uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + if: startsWith(runner.os, 'macOS') + with: + path: ~/Library/Caches/pip + key: ${{ matrix.os }}-py${{ matrix.python-version }}-pip-${{ hashFiles('pyproject.toml') }} + restore-keys: | + ${{ matrix.os }}-py${{ matrix.python-version }}-pip- + - name: Cache ccache + uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + with: + path: | + ~/.ccache + key: ${{ matrix.os }}-py${{ matrix.python-version }}-ccache-${{ hashFiles('src/*') }} + restore-keys: | + ${{ matrix.os }}-py${{ matrix.python-version }}-ccache- + - name: Cache Matplotlib + uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + with: + path: | + ~/.cache/matplotlib + !~/.cache/matplotlib/tex.cache + !~/.cache/matplotlib/test_cache + key: 6-${{ matrix.os }}-py${{ matrix.python-version }}-mpl-${{ github.ref }}-${{ github.sha }} + restore-keys: | + 6-${{ matrix.os }}-py${{ matrix.python-version }}-mpl-${{ github.ref }}- + 6-${{ matrix.os }}-py${{ matrix.python-version }}-mpl- + + - name: Install Python dependencies + run: | + # Upgrade pip and setuptools and wheel to get as clean an install as + # possible. + python -m pip install --upgrade pip setuptools wheel + + # Install pre-release versions during our weekly upcoming dependency tests. + if [[ "${{ github.event_name }}" == 'schedule' + && "${{ matrix.name-suffix }}" != '(Minimum Versions)' ]]; then + PRE="--pre" + fi + + # Install dependencies from PyPI. + # Preinstall build requirements to enable no-build-isolation builds. + python -m pip install --upgrade $PRE --prefer-binary \ + --group build --group test ${{ matrix.extra-requirements }} + + # Install optional dependencies from PyPI. + # Sphinx is needed to run sphinxext tests + python -m pip install --upgrade sphinx!=6.1.2 + + if [[ "${{ matrix.python-version }}" != '3.14t' ]]; then + # GUI toolkits are pip-installable only for some versions of Python + # so don't fail if we can't install them. Make it easier to check + # whether the install was successful by trying to import the toolkit + # (sometimes, the install appears to be successful but shared + # libraries cannot be loaded at runtime, so an actual import is a + # better check). + python -m pip install --upgrade pycairo 'cairocffi>=0.8' 'PyGObject${{ matrix.pygobject-ver }}' && + ( + python -c 'import gi; gi.require_version("Gtk", "4.0"); from gi.repository import Gtk' && + echo 'PyGObject 4 is available' || echo 'PyGObject 4 is not available' + ) && ( + python -c 'import gi; gi.require_version("Gtk", "3.0"); from gi.repository import Gtk' && + echo 'PyGObject 3 is available' || echo 'PyGObject 3 is not available' + ) + + # PyQt5 does not have any wheels for ARM on Linux. + if [[ "${{ matrix.os }}" != 'ubuntu-24.04-arm' ]]; then + python -mpip install --upgrade --only-binary :all: pyqt5 && + python -c 'import PyQt5.QtCore' && + echo 'PyQt5 is available' || + echo 'PyQt5 is not available' + fi + python -mpip install --upgrade --only-binary :all: pyqt6 && + python -c 'import PyQt6.QtCore' && + echo 'PyQt6 is available' || + echo 'PyQt6 is not available' + python -mpip install --upgrade --only-binary :all: pyside6 && + python -c 'import PySide6.QtCore' && + echo 'PySide6 is available' || + echo 'PySide6 is not available' + + python -mpip install --upgrade --only-binary :all: \ + -f "https://extras.wxpython.org/wxPython4/extras/linux/gtk3/${{ matrix.os }}" \ + wxPython && + python -c 'import wx' && + echo 'wxPython is available' || + echo 'wxPython is not available' + + fi # Skip backends on Python 3.14t. + + - name: Install the nightly dependencies + # Only install the nightly dependencies during the scheduled event + if: github.event_name == 'schedule' && matrix.name-suffix != '(Minimum Versions)' + run: | + python -m pip install pytz tzdata # Must be installed for Pandas. + python -m pip install \ + --index-url https://pypi.anaconda.org/scientific-python-nightly-wheels/simple \ + --upgrade --only-binary=:all: numpy pandas + + - name: Install Matplotlib + run: | + ccache -s + git describe + + # Set flag in a delayed manner to avoid issues with installing other + # packages + if [[ "${{ runner.os }}" == 'macOS' ]]; then + export CPPFLAGS='-fprofile-instr-generate=default.%m.profraw' + export CPPFLAGS="$CPPFLAGS -fcoverage-mapping" + else + export CPPFLAGS='--coverage -fprofile-abs-path' + fi + + python -m pip install --no-deps --no-build-isolation --verbose \ + --config-settings=setup-args="-DrcParams-backend=Agg" \ + --editable .[dev] + + if [[ "${{ runner.os }}" != 'macOS' ]]; then + unset CPPFLAGS + fi + + - name: Clear font cache + run: | + rm -rf ~/.cache/matplotlib + if: matrix.delete-font-cache + + - name: Run pytest + run: | + if [[ "${{ matrix.python-version }}" == '3.14t' ]]; then + export PYTHON_GIL=0 + fi + pytest -rfEsXR -n auto \ + --maxfail=50 --timeout=300 --durations=25 \ + --cov-report=xml --cov=lib --log-level=DEBUG --color=yes + + - name: Cleanup non-failed image files + if: failure() + run: | + find ./result_images -name "*-expected*.png" | while read file; do + if [[ $file == *-expected_???.png ]]; then + extension=${file: -7:3} + base=${file%*-expected_$extension.png}_$extension + else + extension="png" + base=${file%-expected.png} + fi + if [[ ! -e ${base}-failed-diff.png ]]; then + indent="" + list=($file $base.png) + if [[ $extension != "png" ]]; then + list+=(${base%_$extension}-expected.$extension ${base%_$extension}.$extension) + fi + for to_remove in "${list[@]}"; do + if [[ -e $to_remove ]]; then + rm $to_remove + echo "${indent}Removed $to_remove" + fi + indent+=" " + done + fi + done + + if [ "$(find ./result_images -mindepth 1 -type d)" ]; then + find ./result_images/* -type d -empty -delete + fi + + - name: Filter C coverage + if: ${{ !cancelled() && github.event_name != 'schedule' }} + run: | + if [[ "${{ runner.os }}" != 'macOS' ]]; then + LCOV_IGNORE_ERRORS=',' # do not ignore any lcov errors by default + if [[ "${{ matrix.os }}" = ubuntu-24.04 || "${{ matrix.os }}" = ubuntu-24.04-arm ]]; then + # filter mismatch errors detected by lcov 2.x + LCOV_IGNORE_ERRORS='mismatch' + fi + lcov --rc lcov_branch_coverage=1 --ignore-errors $LCOV_IGNORE_ERRORS \ + --capture --directory . --exclude $PWD/subprojects --exclude $PWD/build \ + --output-file coverage.info + lcov --rc lcov_branch_coverage=1 --ignore-errors $LCOV_IGNORE_ERRORS \ + --output-file coverage.info --extract coverage.info $PWD/src/'*' + lcov --rc lcov_branch_coverage=1 --ignore-errors $LCOV_IGNORE_ERRORS \ + --list coverage.info + find . -name '*.gc*' -delete + else + xcrun llvm-profdata merge -sparse default.*.profraw \ + -o default.profdata + xcrun llvm-cov export -format="lcov" build/*/src/*.so \ + -instr-profile default.profdata > info.lcov + fi + - name: Upload code coverage + if: ${{ !cancelled() && github.event_name != 'schedule' }} + uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # v6.0.1 + with: + name: "${{ matrix.python-version }} ${{ matrix.os }} ${{ matrix.name-suffix }}" + token: ${{ secrets.CODECOV_TOKEN }} + + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + if: failure() + with: + name: "${{ matrix.python-version }} ${{ matrix.os }} ${{ matrix.name-suffix }} result images" + path: ./result_images + + # Separate dependent job to only upload one issue from the matrix of jobs + create-issue: + if: ${{ failure() && github.event_name == 'schedule' }} + needs: [test] + permissions: + issues: write + runs-on: ubuntu-latest + name: "Create issue on failure" + + steps: + - name: Create issue on failure + uses: imjohnbo/issue-bot@3188c6ce06249206709d3b1f274d0d4c5a521601 # v3.4.5 + with: + title: "[TST] Upcoming dependency test failures" + body: | + The weekly build with nightly wheels from numpy and pandas + has failed. Check the logs for any updates that need to be + made in matplotlib. + https://github.com/${{github.repository}}/actions/runs/${{github.run_id}} + + pinned: false + close-previous: false + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/triage_board.yml b/.github/workflows/triage_board.yml new file mode 100644 index 000000000000..3ef26369afeb --- /dev/null +++ b/.github/workflows/triage_board.yml @@ -0,0 +1,24 @@ +--- +name: 'Update PR Triage Board' + +on: + schedule: + - cron: '0 * * * *' # Run every hour + workflow_dispatch: + +permissions: {} + +jobs: + pr-triage: + if: github.repository == 'matplotlib/matplotlib' + runs-on: ubuntu-latest + steps: + - name: Update PR Triage Board + uses: jupyter/pr-triage-board-bot@dae1209c73e70224b2f2955590d0698832a5a076 # main @ Oct 26, 2025 + with: + organization: 'matplotlib' + project-number: '11' + gh-app-id: '3339145' + gh-app-installation-id: '122963236' + gh-app-private-key: ${{ secrets.GH_APP_PRIVATE_KEY }} + repositories: 'matplotlib' diff --git a/.github/workflows/wasm.yml b/.github/workflows/wasm.yml new file mode 100644 index 000000000000..e1668d99af60 --- /dev/null +++ b/.github/workflows/wasm.yml @@ -0,0 +1,63 @@ +--- +name: Build wasm wheels + +on: + # Save CI by only running this on release branches or tags. + push: + branches: + - main + - v[0-9]+.[0-9]+.x + tags: + - v* + # Also allow running this action on PRs if requested by applying the + # "Run cibuildwheel" label. + pull_request: + types: + - opened + - synchronize + - reopened + - labeled + +permissions: + contents: read + +jobs: + build_wasm: + if: >- + ( + github.event_name == 'push' || + github.event_name == 'pull_request' && ( + ( + github.event.action == 'labeled' && + github.event.label.name == 'CI: Run cibuildwheel' + ) || + contains(github.event.pull_request.labels.*.name, + 'CI: Run cibuildwheel') + ) + ) + name: Build wasm + runs-on: ubuntu-24.04 + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + fetch-depth: 0 + persist-credentials: false + + - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 + name: Install Python + with: + python-version: '3.13' + + - name: Build wheels for wasm + uses: pypa/cibuildwheel@8d2b08b68458a16aeb24b64e68a09ab1c8e82084 # v3.4.1 + env: + CIBW_BUILD: "cp312-*" + CIBW_PLATFORM: "pyodide" + CIBW_TEST_COMMAND: "true" + + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: cibw-wheels-wasm + path: ./wheelhouse/*.whl + if-no-files-found: error diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml deleted file mode 100644 index c8c280e92029..000000000000 --- a/.github/workflows/wheels.yml +++ /dev/null @@ -1,34 +0,0 @@ -on: - push: - tags: - - 'v[0-9]+.[0-9]+.[0-9]+*' -jobs: - trigger_wheel_builds: - runs-on: ubuntu-latest - name: Trigger macOS and manylinux wheel builds - if: github.repository == 'matplotlib/matplotlib' - steps: - - name: Checkout - uses: actions/checkout@v2 - with: - repository: MacPython/matplotlib-wheels - ssh-key: ${{ secrets.WHEEL_DEPLOY_KEY }} - fetch-depth: 0 - - name: Prepare build commit - id: commit - shell: bash - run: | - TAG="${GITHUB_REF#refs/tags/}" - BRANCH="$(echo ${TAG} | sed 's/^v\([0-9]\+\.[0-9]\+\)\.[0-9]\+.*$/build-\1.x/')" - echo "${BRANCH}" - echo "##[set-output name=branch;]${BRANCH}" - git branch ${BRANCH} master || true - git checkout ${BRANCH} - sed -i -e "s/\(- BUILD_COMMIT=\).\+/\1${TAG}/g" .travis.yml - git add .travis.yml - git config --global user.name 'Matplotlib Actions Bot' - git config --global user.email 'matplotlib@users.noreply.github.com' - git commit -m "REL: $TAG" - - name: Push to matplotlib-wheels - run: | - git push origin ${{ steps.commit.outputs.branch }} diff --git a/.github/workflows/zizmor.yml b/.github/workflows/zizmor.yml new file mode 100644 index 000000000000..f6e77b3d6000 --- /dev/null +++ b/.github/workflows/zizmor.yml @@ -0,0 +1,30 @@ +--- +name: zizmor + +on: + push: + branches: [main, v*.x] + pull_request: + branches: [main] + schedule: + - cron: '45 19 * * 1' + +permissions: {} + +jobs: + zizmor: + name: zizmor + if: github.repository == 'matplotlib/matplotlib' + runs-on: ubuntu-latest + permissions: + security-events: write + contents: read + + steps: + - name: Checkout repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + + - name: Run zizmor + uses: zizmorcore/zizmor-action@5f14fd08f7cf1cb1609c1e344975f152c7ee938d # v0.5.6 diff --git a/.github/zizmor.yml b/.github/zizmor.yml new file mode 100644 index 000000000000..ce9c30c01dbd --- /dev/null +++ b/.github/zizmor.yml @@ -0,0 +1,19 @@ +--- +rules: + dangerous-triggers: + ignore: + # These workflows use pull_request_target solely to obtain write access + # for API operations (labeling, commenting) on fork PRs. None of them + # check out or execute any PR-supplied code. + - autoclose_comment.yml:11 + - conflictcheck.yml:3 + - labeler.yml:3 + - pr_welcome.yml:4 + cache-poisoning: + ignore: + # cygwin.yml is a test-only workflow; no artifacts are published. + # This is triggering a low-confidence flag that the workflow_dispatch: + # trigger may imply artifact publishing + - cygwin.yml:144:9 + - cygwin.yml:151:9 + - cygwin.yml:158:9 diff --git a/.gitignore b/.gitignore index 491c72e229b5..0460152a792f 100644 --- a/.gitignore +++ b/.gitignore @@ -29,10 +29,11 @@ # Python files # ################ -# setup.py working directory +# meson-python working directory build +.mesonpy* -# setup.py dist directory +# meson-python/build frontend dist directory dist # Egg metadata *.egg-info @@ -41,7 +42,10 @@ dist pip-wheel-metadata/* # tox testing tool .tox -setup.cfg +# build subproject files +subprojects/*/ +subprojects/.* +!subprojects/packagefiles/ # OS generated files # ###################### @@ -54,10 +58,8 @@ Thumbs.db # Things specific to this project # ################################### -lib/matplotlib/mpl-data/matplotlib.conf -lib/matplotlib/mpl-data/matplotlibrc -tutorials/intermediate/CL01.png -tutorials/intermediate/CL02.png +galleries/tutorials/intermediate/CL01.png +galleries/tutorials/intermediate/CL02.png # Documentation generated files # ################################# @@ -67,18 +69,23 @@ doc/api/_as_gen # autogenerated by sphinx-gallery doc/examples doc/gallery -doc/tutorials doc/modules +doc/plot_types doc/pyplots/tex_demo.png +doc/tutorials +doc/users/explain lib/dateutil -examples/*/*.eps -examples/*/*.pdf -examples/*/*.png -examples/*/*.svg -examples/*/*.svgz -examples/tests/* -!examples/tests/backend_driver_sgskip.py +galleries/examples/*/*.bmp +galleries/examples/*/*.eps +galleries/examples/*/*.pdf +galleries/examples/*/*.png +galleries/examples/*/*.svg +galleries/examples/*/*.svgz result_images +doc/_static/constrained_layout*.png +doc/.mpl_skip_subdirs.yaml +doc/_tags +sg_execution_times.rst # Nose/Pytest generated files # ############################### @@ -86,8 +93,10 @@ result_images .cache/ .coverage .coverage.* +*.py,cover cover/ .noseids +__pycache__ # Conda files # ############### @@ -95,6 +104,20 @@ __conda_version__.txt lib/png.lib lib/z.lib +# uv files # +############ +uv.lock + +# Environments # +################ +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + # Jupyter files # ################# @@ -102,7 +125,7 @@ lib/z.lib # Vendored dependencies # ######################### - -jquery-ui-*/ lib/matplotlib/backends/web_backend/node_modules/ lib/matplotlib/backends/web_backend/package-lock.json + +LICENSE/LICENSE_QHULL diff --git a/.lgtm.yml b/.lgtm.yml deleted file mode 100644 index b48a4f003db0..000000000000 --- a/.lgtm.yml +++ /dev/null @@ -1,14 +0,0 @@ -path_classifiers: - examples: - # Exclude example files from analysis by tagging them. - # We intentionally use multiple imports and unused variables in the - # examples to make them more explicit. These generate a lot of alerts. - # Since lgtm does not yet support suppressing selected alerts per - # file, we currently deactivate analysis completely here. May be - # reactivated when we can selectively suppress - # - py/import-and-import-from - # - py/repeated-import - # - py/unused-local-variable - # - py/multiple-definition - - examples - - tutorials diff --git a/.mailmap b/.mailmap index 768541979e36..ad81a9f91430 100644 --- a/.mailmap +++ b/.mailmap @@ -1,16 +1,59 @@ +34j <34j.github@proton.me> <55338215+34j@users.noreply.github.com> + +Aasma Gupta AASMA GUPTA + +Adam Ormondroyd +Adam Ormondroyd <52655393+AdamOrmondroyd@users.noreply.github.com> + Adam Ortiz +Aditi Gautam <72432016+agautam478@users.noreply.github.com> + +Aditya Singh +Aditya Singh + Adrien F. Vincent Adrien F. Vincent +ALBIN BABU VARGHESE + +Aleksey Bilogur + +Alexander Rudy + +Alon Hershenhorn + Alvaro Sanchez +Aman Kushwaha + +Amisha Mehta +Amisha Mehta <115501608+amishamehta99@users.noreply.github.com> + +Ananya Devarakonda +Ananya Devarakonda <57040724+ananya314@users.noreply.github.com> + +Andreas C Mueller Andreas Mueller + +Andrés Gutierrez <12andresgutierrez04@gmail.com> + Andrew Dawson +Andrew Fennell + +Andrew Kim <110536383+aseriesof-tubes@users.noreply.github.com> dohyun + +Anna Mastori <72812754+AnnaMastori@users.noreply.github.com> + +Anton <138380708+r3kste@users.noreply.github.com> + anykraus Ariel Hernán Curiale +Atharva Kulkarni Atharva2012 +Atharva Kulkarni <103631956+Atharva2012@users.noreply.github.com> + Ben Cohen Ben Root Benjamin Root @@ -20,12 +63,36 @@ Benedikt Daurer Benjamin Congdon Benjamin Congdon bcongdon +Brandon Dusch + +Brian Lau +Brian Lau <103338659+beelauuu@users.noreply.github.com> + Bruno Zohreh +Carsten Schelp + Casper van der Wel +Chahak Mehta Chahak Mehta <201501422@daiict.ac.in> + +Chaoyi Hu <90495101+chaoyihu@users.noreply.github.com> + +Charisma Kausar <68203159+ckcherry23@users.noreply.github.com> + +CharlesHe16 + +Chirag Sharma +Chirag Sharma <160767827+Chirag3841@users.noreply.github.com> + +Cho Yin Yong + +Chris + Chris Holdgraf +Christine P. Chai + Christoph Gohlke cgohlke Christoph Gohlke C. Gohlke Christoph Gohlke @@ -34,19 +101,37 @@ Cimarron Mittelsteadt Cimarron cldssty +Constantinos Menelaou +Constantinos Menelaou <91343054+konmenel@users.noreply.github.com> + Conner R. Phillips +Dale Dai +Dale Dai <145884899+CouldNot@users.noreply.github.com> + Dan Hickstein Daniel Hyams Daniel Hyams Daniel Hyams +Daniel Weiss +Daniel Weiss <32396142+dkweiss31@users.noreply.github.com> + David Kua +David Matos +David Matos + +DerWeh + Devashish Deshpande +Diego Leal Petrola + Dietmar Schwertberger +Dora Fraeman Caswell + endolith Eric Dill @@ -56,6 +141,11 @@ Erik Bray Eric Ma Eric Ma +esvhd + +Eva Sibinga +Eva Sibinga <46283995+esibinga@users.noreply.github.com> + Filipe Fernandes Florian Le Bourdais @@ -64,18 +154,44 @@ Francesco Montesano montefra +G Karthik Koundinya +G Karthik Koundinya <144328549+G26karthik@users.noreply.github.com> + +Greg Lucas + Hajoon Choi hannah +Hannes Breytenbach + Hans Moritz Günther +Haoying Zhang +Haoying Zhang <38875181+stevezhang1999@users.noreply.github.com> +Haoying Zhang stevezhang + +Harshal Prakash Patankar + Harshit Patni +Harutaka Kawamura + +Hasan Rashid + +Hood Chatham Hood + +Husain Gadiwala +Husain Gadiwala <69296939+alphanoobie@users.noreply.github.com> + +Ian Hunt-Isaak + ImportanceOfBeingErnest J. Goutin JGoutin +Jakub Klus <48711526+deep-jkl@users.noreply.github.com> + Jack Kelly Jack Kelly @@ -85,8 +201,14 @@ Jake Vanderplas Jake Vanderplas Jake Vanderplas +Jacob Stevens-Haas <37048747+Jacob-Stevens-Haas@users.noreply.github.com> + James R. Evans +Jan-Hendrik Müller <44469195+kolibril13@users.noreply.github.com> + +jaya prajapati + Jeff Lutgen Jeffrey Bingham @@ -94,22 +216,39 @@ Jeffrey Bingham Jens Hedegaard Nielsen Jens Hedegaard Nielsen +Jerome F. Villegas + +JOD + +Joel Frederico <458871+joelfrederico@users.noreply.github.com> + +Johan von Forstner + John Hunter Jorrit Wronski +Jose Manuel Martí + Joseph Fox-Rabinovitz Mad Physicist Joseph Fox-Rabinovitz Joseph Fox-Rabinovitz Jouni K. Seppänen +Juanita Gomez + Julien Lhermitte Julien Schueller Julien Schueller +Kaustubh Desale +Kaustubh Desale <97254178+Kaustbh@users.noreply.github.com> + Kevin Davies +Khushikela29 <121342846+Khushikela29@users.noreply.github.com> + kikocorreoso Klara Gerlei @@ -117,6 +256,10 @@ Klara Gerlei klaragerlei Kristen M. Thyng +Kyle Sunden + +Kyra Cho + Leeonadoh Lennart Fricke @@ -127,22 +270,54 @@ Leon Yin Lion Krischer +Logan Pageler +Logan Pageler <48865621+Logan-Pageler@users.noreply.github.com> + +Lukas Hergt + +Lumberbot (aka Jack) <39504233+meeseeksmachine@users.noreply.github.com> + +luz paz + +Manan Kevadiya +Manan Kevadiya <43081866+manan2501@users.noreply.github.com> + +Manuel Nuno Melo + +Marat Kopytjuk + +Marco Gorelli +Marco Gorelli <33491632+MarcoGorelli@users.noreply.github.com> + Marek Rudnicki +Marten Henric van Kerkwijk + Martin Fitzpatrick +Marvin +Marvin <101656586+Marvvxi@users.noreply.github.com> + +Mathias Hauser + Matt Newville Matthew Emmett Matthew Emmett +Matthew Morrison <120498834+mattymo30@users.noreply.github.com> + Matthias Bussonnier +Matthias Bussonnier Matthias Lüthi Matthias Lüthi Matti Picus +Melissa Weber Mendonça +Melissa Weber Mendonça + Michael Droettboom Michael Droettboom Michael Droettboom @@ -152,9 +327,14 @@ Michiel de Hoon Michiel de Hoon Michiel de Hoon Michiel de Hoon Michiel de Hoon +Milan Gittler +Milan Gittler <55838375+Cemonix@users.noreply.github.com> + MinRK MinRK Min RK +Miriam Simone + Nelle Varoquaux Nic Eggert Nic Eggert @@ -162,9 +342,17 @@ Nic Eggert Nic Eggert Nicolas P. Rougier +N R Navaneet <156576749+nrnavaneet@users.noreply.github.com> + OceanWolf -Olivier +odile OdileVidrine <65249488+OdileVidrine@users.noreply.github.com> + +Olivier Castany <1868182+ocastany@users.noreply.github.com> +Olivier Castany <1868182+ocastany@users.noreply.github.com> +Olivier Castany <1868182+ocastany@users.noreply.github.com> + +Om Sitapara Patrick Chen @@ -174,10 +362,18 @@ Paul Ganssle Paul Hobson Paul Hobson vagrant +Paul Ivanov Paul Ivanov +Paul Ivanov + +Pedro Marques + +Pedro Peçanha <60028123+pedrompecanha@users.noreply.github.com> Per Parker +Péter Leéh + Peter Würtz Peter Würtz @@ -185,17 +381,62 @@ Phil Elson Phil Elson Phil Elson +Philipp Nagel + +Pirzada Ahmad Faraz +Pirzada Ahmad Faraz <136244856+pirzada-ahmadfaraz@users.noreply.github.com> + +photoniker <17592823+photoniker@users.noreply.github.com> + +Pranav Raghu +Pranav Raghu <73378019+Impaler343@users.noreply.github.com> + productivememberofsociety666 none +Quentin Peter + +Rahul Monani + +Raphael Quast + +Ratnabali Dutta + +Richard Penney + Rishikesh +Roman <121314722+GameRoMan@users.noreply.github.com> + +Ruth Comer <10599679+rcomer@users.noreply.github.com> + +Ruth Nainggolan Ruth G. N <32371319+ruthgn@users.noreply.github.com> + RyanPan +Richard Sheridan + +Samesh Lakhotia +Samesh Lakhotia <43701530+sameshl@users.noreply.github.com> ' + +Saumya Agrawal <145997182+saumyacoder1709@users.noreply.github.com> Saumya + Scott Lasley +Scott Shambaugh <14363975+scottshambaugh@users.noreply.github.com> + Sebastian Raschka Sebastian Raschka +ShawnChen1996 + +Shriya Kalakata +Shriya Kalakata <87483933+shriyakalakata@users.noreply.github.com> +Shriya Kalakata Shriya Kalakata +Shriya Kalakata Shriya Kalakata + +Sidharth Bansal +Sidharth Bansal <20972099+SidharthBansal@users.noreply.github.com> + Simon Cross Slav Basharov @@ -208,19 +449,48 @@ switham switham Taehoon Lee +Takumasa Nakamura + +Ted Drain + +Taras Kuzyo + +Terence Honles + +Thomas A Caswell Thomas A Caswell Thomas A Caswell Thomas A Caswell Thomas A Caswell Thomas A Caswell Thomas A Caswell <“tcaswell@gmail.comâ€> Thomas A Caswell Thomas A Caswell +Till Stensitzki + +Tim Hoffmann <2836374+timhoffm@users.noreply.github.com> + +Tine Zivic <43860297+tinezivic@users.noreply.github.com> + +Tobias Thrien tobias + +Tom Sarantis + Trish Gillett-Kawamoto Tuan Dung Tran +tybeller <73607363+tybeller@users.noreply.github.com> + +Valentin Bruch +Valentin Bruch <46252273+stiglers-eponym@users.noreply.github.com> + Víctor Zabalza Vidur Satija +Vishal Pankaj Chandratreya <19171016+tfpf@users.noreply.github.com> +Vishal Pankaj Chandratreya <19171016+tfpf@users.noreply.github.com> + +vittoboa <38300176+vittoboa@users.noreply.github.com> + WANG Aiyong Werner F Bruhin @@ -229,3 +499,7 @@ Yunfei Yang Yunfei Yang Yunfei Yang Zac Hatfield-Dodds + +Zhili (Jerry) Pan + +ZPyrolink <38cz74@gmail.com> <73246085+ZPyrolink@users.noreply.github.com> diff --git a/.matplotlib-repo b/.matplotlib-repo new file mode 100644 index 000000000000..0b1d699bcdb1 --- /dev/null +++ b/.matplotlib-repo @@ -0,0 +1,3 @@ +The existence of this file signals that the code is a matplotlib source repo +and not an installed version. We use this in __init__.py for gating version +detection. diff --git a/.meeseeksdev.yml b/.meeseeksdev.yml index 8bfd1b8e4257..f9d44d44cfdf 100644 --- a/.meeseeksdev.yml +++ b/.meeseeksdev.yml @@ -1,3 +1,4 @@ +--- users: Carreau: can: diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 000000000000..6f2b94141984 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,137 @@ +--- +ci: + autofix_prs: false + autoupdate_schedule: 'quarterly' +exclude: | + (?x)^( + extern| + subprojects/packagefiles| + LICENSE| + lib/matplotlib/mpl-data| + doc/devel/gitwash| + doc/release/prev| + doc/api/prev| + lib/matplotlib/tests/data/tinypages + ) +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: 3e8a8703264a2f4a69428a0aa4dcb512790b2c8c # frozen: v6.0.0 + hooks: + - id: check-added-large-files + - id: check-docstring-first + exclude: lib/matplotlib/typing.py # docstring used for attribute flagged by check + - id: end-of-file-fixer + exclude_types: [diff, svg] + - id: mixed-line-ending + - id: name-tests-test + args: ["--pytest-test-first"] + - id: no-commit-to-branch # Default is master and main. + - id: trailing-whitespace + exclude_types: [diff, svg] + - repo: https://github.com/pre-commit/mirrors-mypy + rev: d2823d321df3af8f878f7ee3414dc94d037145b9 # frozen: v2.1.0 + hooks: + - id: mypy + additional_dependencies: + - pandas-stubs + - types-pillow + - types-python-dateutil + - types-psutil + - types-docutils + - types-PyYAML + args: ["--config-file=pyproject.toml", "lib/matplotlib"] + files: lib/matplotlib # Only run when files in lib/matplotlib are changed. + pass_filenames: false + - repo: https://github.com/astral-sh/ruff-pre-commit + # Ruff version. + rev: 0671d8ab202c4ac093b78433ae5baf74f3fc7246 # frozen: v0.15.15 + hooks: + # Run the linter. + - id: ruff-check + args: [--fix, --show-fixes] + - repo: https://github.com/codespell-project/codespell + rev: 2ccb47ff45ad361a21071a7eedda4c37e6ae8c5a # frozen: v2.4.2 + hooks: + - id: codespell + files: ^.*\.(py|c|cpp|h|m|md|rst|yml)$ + args: + - "--ignore-words" + - "ci/codespell-ignore-words.txt" + - "--skip" + - "doc/project/credits.rst" + - repo: https://github.com/pycqa/isort + rev: a333737ed43df02b18e6c95477ea1b285b3de15a # frozen: 8.0.1 + hooks: + - id: isort + name: isort (python) + files: ^galleries/tutorials/|^galleries/examples/|^galleries/plot_types/ + - repo: https://github.com/rstcheck/rstcheck + rev: 77490ffa33bfc0928975ae3cf904219903db755d # frozen: v6.2.5 + hooks: + - id: rstcheck + additional_dependencies: + - rstcheck-core!=1.3 # https://github.com/rstcheck/rstcheck-core/pull/114#pullrequestreview-4239740896 + - sphinx>=1.8.1 + - repo: https://github.com/adrienverge/yamllint + rev: cba56bcde1fdd01c1deb3f945e69764c291a6530 # frozen: v1.38.0 + hooks: + - id: yamllint + args: ["--strict", "--config-file=.yamllint.yml"] + - repo: https://github.com/shellcheck-py/shellcheck-py + rev: 745eface02aef23e168a8afb6b5737818efbea95 # frozen: v0.11.0.1 + hooks: + - id: shellcheck + - repo: https://github.com/zizmorcore/zizmor-pre-commit + rev: a4727cbbcd26d7098e96b9cb738169b59711ae51 # frozen: v1.24.1 + hooks: + - id: zizmor + - repo: https://github.com/simple-icons/svglint + rev: 8402586b94f073686e46707a163082e270ee5768 # frozen: v4.2.1 + hooks: + - id: svglint + # Override the top-level exclude so that mpl-data/images/ toolbar + # icons are also linted. Exemptions for the intentional interactive + # SVG examples are handled in .svglintrc.mjs. + exclude: '^$' + - repo: https://github.com/python-jsonschema/check-jsonschema + rev: f805888065fdb6162e1f800e50bb9460cbd223d6 # frozen: 0.37.2 + hooks: + # TODO: Re-enable this when https://github.com/microsoft/azure-pipelines-vscode/issues/567 is fixed. + # - id: check-azure-pipelines + - id: check-dependabot + - id: check-github-workflows + # NOTE: If any of the below schema files need to be changed, be sure to + # update the `ci/vendor_schemas.py` script. + - id: check-jsonschema + name: "Validate AppVeyor config" + files: ^\.appveyor\.yml$ + args: ["--verbose", "--schemafile", "ci/schemas/appveyor.json"] + - id: check-jsonschema + name: "Validate CircleCI config" + files: ^\.circleci/config\.yml$ + args: ["--verbose", "--schemafile", "ci/schemas/circleciconfig.json"] + - id: check-jsonschema + name: "Validate GitHub funding file" + files: ^\.github/FUNDING\.yml$ + args: ["--verbose", "--schemafile", "ci/schemas/github-funding.json"] + - id: check-jsonschema + name: "Validate GitHub issue config" + files: ^\.github/ISSUE_TEMPLATE/config\.yml$ + args: ["--verbose", "--schemafile", "ci/schemas/github-issue-config.json"] + - id: check-jsonschema + name: "Validate GitHub issue templates" + files: ^\.github/ISSUE_TEMPLATE/.*\.yml$ + exclude: ^\.github/ISSUE_TEMPLATE/config\.yml$ + args: ["--verbose", "--schemafile", "ci/schemas/github-issue-forms.json"] + - id: check-jsonschema + name: "Validate CodeCov config" + files: ^\.github/codecov\.yml$ + args: ["--verbose", "--schemafile", "ci/schemas/codecov.json"] + - id: check-jsonschema + name: "Validate GitHub labeler config" + files: ^\.github/labeler\.yml$ + args: ["--verbose", "--schemafile", "ci/schemas/pull-request-labeler-5.json"] + - id: check-jsonschema + name: "Validate Conda environment file" + files: ^environment\.yml$ + args: ["--verbose", "--schemafile", "ci/schemas/conda-environment.json"] diff --git a/.svglintrc.mjs b/.svglintrc.mjs new file mode 100644 index 000000000000..7c6c3e194a64 --- /dev/null +++ b/.svglintrc.mjs @@ -0,0 +1,56 @@ +/** @type {import('svglint').Config} */ +const config = { + rules: { + // Ensure all SVGs are valid XML. + valid: true, + + // Block elements that can execute code or embed arbitrary content. + // + + + + 2026-03-25T12:33:41.331892 + image/svg+xml + + + Matplotlib v3.10.0, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + −3 + + + + + + + + + + −2 + + + + + + + + + + −1 + + + + + + + + + + 0 + + + + + + + + + + 1 + + + + + + + + + + 2 + + + + + + + + + + 3 + + + + + + + + + + + + + + + 0 + + + + + + + + + + 5 + + + + + + + + + + 10 + + + + + + + + + + 15 + + + + + + + + + + 20 + + + + + + + + + + 25 + + + + + + + + + + + + + + + + + From a web browser, click on the legend + marker to toggle the corresponding histogram. + + + + + + + Rabbits + + + + + + Frogs + + + + + + + + + + \ No newline at end of file diff --git a/doc/_static/svg_tooltip.svg b/doc/_static/svg_tooltip.svg new file mode 100644 index 000000000000..dd11c2d7782e --- /dev/null +++ b/doc/_static/svg_tooltip.svg @@ -0,0 +1,385 @@ + + + + + + 2026-03-25T12:36:20.674869 + image/svg+xml + + + Matplotlib v3.10.0, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/doc/_static/sviewgui_sample.png b/doc/_static/sviewgui_sample.png deleted file mode 100644 index e1489d313fb5..000000000000 Binary files a/doc/_static/sviewgui_sample.png and /dev/null differ diff --git a/doc/_static/switcher.json b/doc/_static/switcher.json new file mode 100644 index 000000000000..bd578d8c8ffc --- /dev/null +++ b/doc/_static/switcher.json @@ -0,0 +1,58 @@ +[ + { + "name": "3.11 (stable)", + "version": "3.11.0", + "url": "https://matplotlib.org/stable/", + "preferred": true + }, + { + "name": "3.12 (dev)", + "version": "dev", + "url": "https://matplotlib.org/devdocs/" + }, + { + "name": "3.10", + "version": "3.10.9", + "url": "https://matplotlib.org/3.10.9/" + }, + { + "name": "3.9", + "version": "3.9.3", + "url": "https://matplotlib.org/3.9.3/" + }, + { + "name": "3.8", + "version": "3.8.4", + "url": "https://matplotlib.org/3.8.4/" + }, + { + "name": "3.7", + "version": "3.7.5", + "url": "https://matplotlib.org/3.7.5/" + }, + { + "name": "3.6", + "version": "3.6.3", + "url": "https://matplotlib.org/3.6.3/" + }, + { + "name": "3.5", + "version": "3.5.3", + "url": "https://matplotlib.org/3.5.3/" + }, + { + "name": "3.4", + "version": "3.4.3", + "url": "https://matplotlib.org/3.4.3/" + }, + { + "name": "3.3", + "version": "3.3.4", + "url": "https://matplotlib.org/3.3.4/" + }, + { + "name": "2.2", + "version": "2.2.4", + "url": "https://matplotlib.org/2.2.4/" + } +] diff --git a/doc/_static/toolmanager.png b/doc/_static/toolmanager.png new file mode 100644 index 000000000000..14aeba48995d Binary files /dev/null and b/doc/_static/toolmanager.png differ diff --git a/doc/_static/transforms.png b/doc/_static/transforms.png deleted file mode 100644 index ab07fb575961..000000000000 Binary files a/doc/_static/transforms.png and /dev/null differ diff --git a/doc/_static/wcsaxes.jpg b/doc/_static/wcsaxes.jpg deleted file mode 100644 index 5312904f092e..000000000000 Binary files a/doc/_static/wcsaxes.jpg and /dev/null differ diff --git a/doc/_static/yellowbrick.png b/doc/_static/yellowbrick.png deleted file mode 100644 index 01013a1a03d2..000000000000 Binary files a/doc/_static/yellowbrick.png and /dev/null differ diff --git a/doc/_static/zenodo_cache/1004650.svg b/doc/_static/zenodo_cache/1004650.svg new file mode 100644 index 000000000000..8d70568301a7 --- /dev/null +++ b/doc/_static/zenodo_cache/1004650.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.1004650 + + + 10.5281/zenodo.1004650 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/10059757.svg b/doc/_static/zenodo_cache/10059757.svg new file mode 100644 index 000000000000..d5909613dd75 --- /dev/null +++ b/doc/_static/zenodo_cache/10059757.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.10059757 + + + 10.5281/zenodo.10059757 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/10150955.svg b/doc/_static/zenodo_cache/10150955.svg new file mode 100644 index 000000000000..132bc97ab61d --- /dev/null +++ b/doc/_static/zenodo_cache/10150955.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.10150955 + + + 10.5281/zenodo.10150955 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/10661079.svg b/doc/_static/zenodo_cache/10661079.svg new file mode 100644 index 000000000000..ac659bcc870f --- /dev/null +++ b/doc/_static/zenodo_cache/10661079.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.10661079 + + + 10.5281/zenodo.10661079 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/10916799.svg b/doc/_static/zenodo_cache/10916799.svg new file mode 100644 index 000000000000..ca9c0a454251 --- /dev/null +++ b/doc/_static/zenodo_cache/10916799.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.10916799 + + + 10.5281/zenodo.10916799 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/1098480.svg b/doc/_static/zenodo_cache/1098480.svg new file mode 100644 index 000000000000..93eb714978e4 --- /dev/null +++ b/doc/_static/zenodo_cache/1098480.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.1098480 + + + 10.5281/zenodo.1098480 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/11201097.svg b/doc/_static/zenodo_cache/11201097.svg new file mode 100644 index 000000000000..70f35a7a659f --- /dev/null +++ b/doc/_static/zenodo_cache/11201097.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.11201097 + + + 10.5281/zenodo.11201097 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/11451.svg b/doc/_static/zenodo_cache/11451.svg new file mode 100644 index 000000000000..87edde75d917 --- /dev/null +++ b/doc/_static/zenodo_cache/11451.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.11451 + + + 10.5281/zenodo.11451 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/1154287.svg b/doc/_static/zenodo_cache/1154287.svg new file mode 100644 index 000000000000..e19917debda9 --- /dev/null +++ b/doc/_static/zenodo_cache/1154287.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.1154287 + + + 10.5281/zenodo.1154287 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/1189358.svg b/doc/_static/zenodo_cache/1189358.svg new file mode 100644 index 000000000000..2792f3ef69b4 --- /dev/null +++ b/doc/_static/zenodo_cache/1189358.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.1189358 + + + 10.5281/zenodo.1189358 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/1202050.svg b/doc/_static/zenodo_cache/1202050.svg new file mode 100644 index 000000000000..45c04ceb3f8f --- /dev/null +++ b/doc/_static/zenodo_cache/1202050.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.1202050 + + + 10.5281/zenodo.1202050 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/1202077.svg b/doc/_static/zenodo_cache/1202077.svg new file mode 100644 index 000000000000..ec73136ad802 --- /dev/null +++ b/doc/_static/zenodo_cache/1202077.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.1202077 + + + 10.5281/zenodo.1202077 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/12287.svg b/doc/_static/zenodo_cache/12287.svg new file mode 100644 index 000000000000..799bcddc4fbc --- /dev/null +++ b/doc/_static/zenodo_cache/12287.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.12287 + + + 10.5281/zenodo.12287 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/12400.svg b/doc/_static/zenodo_cache/12400.svg new file mode 100644 index 000000000000..82cdfe33b7e2 --- /dev/null +++ b/doc/_static/zenodo_cache/12400.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.12400 + + + 10.5281/zenodo.12400 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/12652732.svg b/doc/_static/zenodo_cache/12652732.svg new file mode 100644 index 000000000000..cde5c5f37839 --- /dev/null +++ b/doc/_static/zenodo_cache/12652732.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.12652732 + + + 10.5281/zenodo.12652732 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/13308876.svg b/doc/_static/zenodo_cache/13308876.svg new file mode 100644 index 000000000000..749bc3c19026 --- /dev/null +++ b/doc/_static/zenodo_cache/13308876.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.13308876 + + + 10.5281/zenodo.13308876 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/1343133.svg b/doc/_static/zenodo_cache/1343133.svg new file mode 100644 index 000000000000..32a2f172ea87 --- /dev/null +++ b/doc/_static/zenodo_cache/1343133.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.1343133 + + + 10.5281/zenodo.1343133 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/1420605.svg b/doc/_static/zenodo_cache/1420605.svg new file mode 100644 index 000000000000..1655f9f66373 --- /dev/null +++ b/doc/_static/zenodo_cache/1420605.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.1420605 + + + 10.5281/zenodo.1420605 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/14249941.svg b/doc/_static/zenodo_cache/14249941.svg new file mode 100644 index 000000000000..f9165f17fdf0 --- /dev/null +++ b/doc/_static/zenodo_cache/14249941.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.14249941 + + + 10.5281/zenodo.14249941 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/14436121.svg b/doc/_static/zenodo_cache/14436121.svg new file mode 100644 index 000000000000..1e4a7cd5b7a4 --- /dev/null +++ b/doc/_static/zenodo_cache/14436121.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.14436121 + + + 10.5281/zenodo.14436121 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/14464227.svg b/doc/_static/zenodo_cache/14464227.svg new file mode 100644 index 000000000000..7126d239d6a5 --- /dev/null +++ b/doc/_static/zenodo_cache/14464227.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.14464227 + + + 10.5281/zenodo.14464227 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/1482098.svg b/doc/_static/zenodo_cache/1482098.svg new file mode 100644 index 000000000000..ba7adb122829 --- /dev/null +++ b/doc/_static/zenodo_cache/1482098.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.1482098 + + + 10.5281/zenodo.1482098 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/1482099.svg b/doc/_static/zenodo_cache/1482099.svg new file mode 100644 index 000000000000..2f9155ddb267 --- /dev/null +++ b/doc/_static/zenodo_cache/1482099.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.1482099 + + + 10.5281/zenodo.1482099 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/14940554.svg b/doc/_static/zenodo_cache/14940554.svg new file mode 100644 index 000000000000..6e7d5c37bf7b --- /dev/null +++ b/doc/_static/zenodo_cache/14940554.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.14940554 + + + 10.5281/zenodo.14940554 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/15375714.svg b/doc/_static/zenodo_cache/15375714.svg new file mode 100644 index 000000000000..d5e403138561 --- /dev/null +++ b/doc/_static/zenodo_cache/15375714.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.15375714 + + + 10.5281/zenodo.15375714 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/15423.svg b/doc/_static/zenodo_cache/15423.svg new file mode 100644 index 000000000000..bec3f657cf0c --- /dev/null +++ b/doc/_static/zenodo_cache/15423.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.15423 + + + 10.5281/zenodo.15423 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/16644850.svg b/doc/_static/zenodo_cache/16644850.svg new file mode 100644 index 000000000000..89910032da4e --- /dev/null +++ b/doc/_static/zenodo_cache/16644850.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.16644850 + + + 10.5281/zenodo.16644850 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/16999430.svg b/doc/_static/zenodo_cache/16999430.svg new file mode 100644 index 000000000000..44c448643e91 --- /dev/null +++ b/doc/_static/zenodo_cache/16999430.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.16999430 + + + 10.5281/zenodo.16999430 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/17298696.svg b/doc/_static/zenodo_cache/17298696.svg new file mode 100644 index 000000000000..9aa8d7c94349 --- /dev/null +++ b/doc/_static/zenodo_cache/17298696.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.17298696 + + + 10.5281/zenodo.17298696 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/17595503.svg b/doc/_static/zenodo_cache/17595503.svg new file mode 100644 index 000000000000..891bd118d125 --- /dev/null +++ b/doc/_static/zenodo_cache/17595503.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.17595503 + + + 10.5281/zenodo.17595503 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/19716234.svg b/doc/_static/zenodo_cache/19716234.svg new file mode 100644 index 000000000000..910ecbef7fae --- /dev/null +++ b/doc/_static/zenodo_cache/19716234.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.19716234 + + + 10.5281/zenodo.19716234 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/20654446.svg b/doc/_static/zenodo_cache/20654446.svg new file mode 100644 index 000000000000..4669c312a200 --- /dev/null +++ b/doc/_static/zenodo_cache/20654446.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.20654446 + + + 10.5281/zenodo.20654446 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/248351.svg b/doc/_static/zenodo_cache/248351.svg new file mode 100644 index 000000000000..e8e38ac9c1be --- /dev/null +++ b/doc/_static/zenodo_cache/248351.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.248351 + + + 10.5281/zenodo.248351 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/2577644.svg b/doc/_static/zenodo_cache/2577644.svg new file mode 100644 index 000000000000..492bbbbc60cf --- /dev/null +++ b/doc/_static/zenodo_cache/2577644.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.2577644 + + + 10.5281/zenodo.2577644 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/2669103.svg b/doc/_static/zenodo_cache/2669103.svg new file mode 100644 index 000000000000..fef871d56e50 --- /dev/null +++ b/doc/_static/zenodo_cache/2669103.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.2669103 + + + 10.5281/zenodo.2669103 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/2893252.svg b/doc/_static/zenodo_cache/2893252.svg new file mode 100644 index 000000000000..2e39a0b456b1 --- /dev/null +++ b/doc/_static/zenodo_cache/2893252.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.2893252 + + + 10.5281/zenodo.2893252 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/3264781.svg b/doc/_static/zenodo_cache/3264781.svg new file mode 100644 index 000000000000..7924a7dcaa22 --- /dev/null +++ b/doc/_static/zenodo_cache/3264781.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.3264781 + + + 10.5281/zenodo.3264781 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/32914.svg b/doc/_static/zenodo_cache/32914.svg new file mode 100644 index 000000000000..0656fd8b062b --- /dev/null +++ b/doc/_static/zenodo_cache/32914.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.32914 + + + 10.5281/zenodo.32914 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/3563226.svg b/doc/_static/zenodo_cache/3563226.svg new file mode 100644 index 000000000000..4731dfab137a --- /dev/null +++ b/doc/_static/zenodo_cache/3563226.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.3563226 + + + 10.5281/zenodo.3563226 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/3633833.svg b/doc/_static/zenodo_cache/3633833.svg new file mode 100644 index 000000000000..34a894f0ccc6 --- /dev/null +++ b/doc/_static/zenodo_cache/3633833.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.3633833 + + + 10.5281/zenodo.3633833 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/3633844.svg b/doc/_static/zenodo_cache/3633844.svg new file mode 100644 index 000000000000..a3e6b7724224 --- /dev/null +++ b/doc/_static/zenodo_cache/3633844.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.3633844 + + + 10.5281/zenodo.3633844 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/3695547.svg b/doc/_static/zenodo_cache/3695547.svg new file mode 100644 index 000000000000..b0bdfe3ba830 --- /dev/null +++ b/doc/_static/zenodo_cache/3695547.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.3695547 + + + 10.5281/zenodo.3695547 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/3714460.svg b/doc/_static/zenodo_cache/3714460.svg new file mode 100644 index 000000000000..07e433ea0313 --- /dev/null +++ b/doc/_static/zenodo_cache/3714460.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.3714460 + + + 10.5281/zenodo.3714460 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/3898017.svg b/doc/_static/zenodo_cache/3898017.svg new file mode 100644 index 000000000000..b435f0e8316a --- /dev/null +++ b/doc/_static/zenodo_cache/3898017.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.3898017 + + + 10.5281/zenodo.3898017 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/3948793.svg b/doc/_static/zenodo_cache/3948793.svg new file mode 100644 index 000000000000..f95c418b3e8b --- /dev/null +++ b/doc/_static/zenodo_cache/3948793.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.3948793 + + + 10.5281/zenodo.3948793 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/3984190.svg b/doc/_static/zenodo_cache/3984190.svg new file mode 100644 index 000000000000..bb548f560222 --- /dev/null +++ b/doc/_static/zenodo_cache/3984190.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.3984190 + + + 10.5281/zenodo.3984190 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/4030140.svg b/doc/_static/zenodo_cache/4030140.svg new file mode 100644 index 000000000000..8fcb71dead83 --- /dev/null +++ b/doc/_static/zenodo_cache/4030140.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.4030140 + + + 10.5281/zenodo.4030140 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/4268928.svg b/doc/_static/zenodo_cache/4268928.svg new file mode 100644 index 000000000000..e7d632a40e54 --- /dev/null +++ b/doc/_static/zenodo_cache/4268928.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.4268928 + + + 10.5281/zenodo.4268928 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/44579.svg b/doc/_static/zenodo_cache/44579.svg new file mode 100644 index 000000000000..4e5854a3e770 --- /dev/null +++ b/doc/_static/zenodo_cache/44579.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.44579 + + + 10.5281/zenodo.44579 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/4475376.svg b/doc/_static/zenodo_cache/4475376.svg new file mode 100644 index 000000000000..bf223b01ddc3 --- /dev/null +++ b/doc/_static/zenodo_cache/4475376.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.4475376 + + + 10.5281/zenodo.4475376 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/4638398.svg b/doc/_static/zenodo_cache/4638398.svg new file mode 100644 index 000000000000..8b50f14790dd --- /dev/null +++ b/doc/_static/zenodo_cache/4638398.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.4638398 + + + 10.5281/zenodo.4638398 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/4649959.svg b/doc/_static/zenodo_cache/4649959.svg new file mode 100644 index 000000000000..a604de20cdd5 --- /dev/null +++ b/doc/_static/zenodo_cache/4649959.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.4649959 + + + 10.5281/zenodo.4649959 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/4743323.svg b/doc/_static/zenodo_cache/4743323.svg new file mode 100644 index 000000000000..204cf037ad27 --- /dev/null +++ b/doc/_static/zenodo_cache/4743323.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.4743323 + + + 10.5281/zenodo.4743323 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/5194481.svg b/doc/_static/zenodo_cache/5194481.svg new file mode 100644 index 000000000000..728ae0c15a6a --- /dev/null +++ b/doc/_static/zenodo_cache/5194481.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.5194481 + + + 10.5281/zenodo.5194481 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/56926.svg b/doc/_static/zenodo_cache/56926.svg new file mode 100644 index 000000000000..5358db519e44 --- /dev/null +++ b/doc/_static/zenodo_cache/56926.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.56926 + + + 10.5281/zenodo.56926 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/570311.svg b/doc/_static/zenodo_cache/570311.svg new file mode 100644 index 000000000000..289b4f407a9b --- /dev/null +++ b/doc/_static/zenodo_cache/570311.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.570311 + + + 10.5281/zenodo.570311 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/5706396.svg b/doc/_static/zenodo_cache/5706396.svg new file mode 100644 index 000000000000..54718543c9c8 --- /dev/null +++ b/doc/_static/zenodo_cache/5706396.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.5706396 + + + 10.5281/zenodo.5706396 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/573577.svg b/doc/_static/zenodo_cache/573577.svg new file mode 100644 index 000000000000..5aea1629ed35 --- /dev/null +++ b/doc/_static/zenodo_cache/573577.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.573577 + + + 10.5281/zenodo.573577 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/5773480.svg b/doc/_static/zenodo_cache/5773480.svg new file mode 100644 index 000000000000..431dbd803973 --- /dev/null +++ b/doc/_static/zenodo_cache/5773480.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.5773480 + + + 10.5281/zenodo.5773480 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/61948.svg b/doc/_static/zenodo_cache/61948.svg new file mode 100644 index 000000000000..8761c190e8f1 --- /dev/null +++ b/doc/_static/zenodo_cache/61948.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.61948 + + + 10.5281/zenodo.61948 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/6513224.svg b/doc/_static/zenodo_cache/6513224.svg new file mode 100644 index 000000000000..fd54dfcb9abb --- /dev/null +++ b/doc/_static/zenodo_cache/6513224.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.6513224 + + + 10.5281/zenodo.6513224 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/6982547.svg b/doc/_static/zenodo_cache/6982547.svg new file mode 100644 index 000000000000..6eb000d892da --- /dev/null +++ b/doc/_static/zenodo_cache/6982547.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.6982547 + + + 10.5281/zenodo.6982547 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/7084615.svg b/doc/_static/zenodo_cache/7084615.svg new file mode 100644 index 000000000000..9bb362063414 --- /dev/null +++ b/doc/_static/zenodo_cache/7084615.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.7084615 + + + 10.5281/zenodo.7084615 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/7162185.svg b/doc/_static/zenodo_cache/7162185.svg new file mode 100644 index 000000000000..ea0966377194 --- /dev/null +++ b/doc/_static/zenodo_cache/7162185.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.7162185 + + + 10.5281/zenodo.7162185 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/7275322.svg b/doc/_static/zenodo_cache/7275322.svg new file mode 100644 index 000000000000..2d0fd408b504 --- /dev/null +++ b/doc/_static/zenodo_cache/7275322.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.7275322 + + + 10.5281/zenodo.7275322 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/7527665.svg b/doc/_static/zenodo_cache/7527665.svg new file mode 100644 index 000000000000..3c3e0b7a8b2a --- /dev/null +++ b/doc/_static/zenodo_cache/7527665.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.7527665 + + + 10.5281/zenodo.7527665 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/7637593.svg b/doc/_static/zenodo_cache/7637593.svg new file mode 100644 index 000000000000..4e91dea5e805 --- /dev/null +++ b/doc/_static/zenodo_cache/7637593.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.7637593 + + + 10.5281/zenodo.7637593 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/7697899.svg b/doc/_static/zenodo_cache/7697899.svg new file mode 100644 index 000000000000..b540a1909046 --- /dev/null +++ b/doc/_static/zenodo_cache/7697899.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.7697899 + + + 10.5281/zenodo.7697899 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/8118151.svg b/doc/_static/zenodo_cache/8118151.svg new file mode 100644 index 000000000000..e9d33ec5bf34 --- /dev/null +++ b/doc/_static/zenodo_cache/8118151.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.8118151 + + + 10.5281/zenodo.8118151 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/8336761.svg b/doc/_static/zenodo_cache/8336761.svg new file mode 100644 index 000000000000..24c222a8a5f5 --- /dev/null +++ b/doc/_static/zenodo_cache/8336761.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.8336761 + + + 10.5281/zenodo.8336761 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/8347255.svg b/doc/_static/zenodo_cache/8347255.svg new file mode 100644 index 000000000000..318d9e6bea73 --- /dev/null +++ b/doc/_static/zenodo_cache/8347255.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.8347255 + + + 10.5281/zenodo.8347255 + + + \ No newline at end of file diff --git a/doc/_templates/autofunctions.rst b/doc/_templates/autofunctions.rst deleted file mode 100644 index 942731b46587..000000000000 --- a/doc/_templates/autofunctions.rst +++ /dev/null @@ -1,20 +0,0 @@ - -{{ fullname | escape | underline }} - - -.. automodule:: {{ fullname }} - :no-members: - -{% block functions %} -{% if functions %} - -Functions ---------- - -.. autosummary:: - :template: autosummary.rst - :toctree: -{% for item in functions %}{% if item not in ['plotting', 'colormaps'] %} - {{ item }}{% endif %}{% endfor %} -{% endif %} -{% endblock %} diff --git a/doc/_templates/automodule.rst b/doc/_templates/automodule.rst index e9f2a755d413..df3e8283f2f6 100644 --- a/doc/_templates/automodule.rst +++ b/doc/_templates/automodule.rst @@ -1,13 +1,5 @@ {{ fullname | escape | underline}} -{% if fullname in ['mpl_toolkits.axes_grid1.colorbar'] %} -.. To prevent problems with the autosummary for the colorbar doc - treat this separately (sphinx-doc/sphinx/issues/4874) -.. automodule:: {{ fullname }} - :members: - -{% else %} - .. automodule:: {{ fullname }} :no-members: :no-inherited-members: @@ -18,11 +10,13 @@ Classes ------- -.. autosummary:: +.. autosummary:: :template: autosummary.rst :toctree: + {% for item in classes %}{% if item not in ['zip', 'map', 'reduce'] %} {{ item }}{% endif %}{% endfor %} + {% endif %} {% endblock %} @@ -32,12 +26,12 @@ Classes Functions --------- -.. autosummary:: +.. autosummary:: :template: autosummary.rst :toctree: {% for item in functions %}{% if item not in ['zip', 'map', 'reduce'] %} {{ item }}{% endif %}{% endfor %} + {% endif %} {% endblock %} -{% endif %} diff --git a/doc/_templates/autosummary.rst b/doc/_templates/autosummary.rst index 69a840b8af29..824dbe5b9a4b 100644 --- a/doc/_templates/autosummary.rst +++ b/doc/_templates/autosummary.rst @@ -5,9 +5,10 @@ {% if objtype in ['class'] %} + .. auto{{ objtype }}:: {{ objname }} :show-inheritance: - :special-members: + :special-members: __call__ {% else %} .. auto{{ objtype }}:: {{ objname }} @@ -16,16 +17,15 @@ {% if objtype in ['class', 'method', 'function'] %} {% if objname in ['AxesGrid', 'Scalable', 'HostAxes', 'FloatingAxes', - 'ParasiteAxesAuxTrans', 'ParasiteAxes'] %} +'ParasiteAxesAuxTrans', 'ParasiteAxes'] %} + .. Filter out the above aliases to other classes, as sphinx gallery creates no example file for those (sphinx-gallery/sphinx-gallery#365) {% else %} -.. include:: {{module}}.{{objname}}.examples - -.. raw:: html -
+.. minigallery:: {{module}}.{{objname}} + :add-heading: {% endif %} {% endif %} diff --git a/doc/_templates/autosummary_class_only.rst b/doc/_templates/autosummary_class_only.rst new file mode 100644 index 000000000000..d10f1b375fd3 --- /dev/null +++ b/doc/_templates/autosummary_class_only.rst @@ -0,0 +1,12 @@ +{{ fullname | escape | underline }} + + +.. currentmodule:: {{ module }} + + +{% if objtype in ['class'] %} + +.. auto{{ objtype }}:: {{ objname }} + :no-members: + +{% endif %} diff --git a/doc/_templates/cheatsheet_sidebar.html b/doc/_templates/cheatsheet_sidebar.html new file mode 100644 index 000000000000..2ca6548ddd4d --- /dev/null +++ b/doc/_templates/cheatsheet_sidebar.html @@ -0,0 +1,9 @@ + + diff --git a/doc/_templates/donate_sidebar.html b/doc/_templates/donate_sidebar.html index 8f93656208f8..071c92888c3c 100644 --- a/doc/_templates/donate_sidebar.html +++ b/doc/_templates/donate_sidebar.html @@ -1,6 +1,5 @@ - - - -