diff --git a/.circleci/config.yml b/.circleci/config.yml index e7348b868d4b..40ba933cf0d9 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -98,7 +98,7 @@ commands: parameters: numpy_version: type: string - default: "~=2.0.0" + default: "" steps: - run: name: Install Python dependencies diff --git a/.github/workflows/cibuildwheel.yml b/.github/workflows/cibuildwheel.yml index b1e5204ab12a..79d770d0c8f4 100644 --- a/.github/workflows/cibuildwheel.yml +++ b/.github/workflows/cibuildwheel.yml @@ -34,7 +34,7 @@ jobs: 'CI: Run cibuildwheel') ) name: Build sdist - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest outputs: SDIST_NAME: ${{ steps.sdist.outputs.SDIST_NAME }} @@ -115,13 +115,12 @@ jobs: CIBW_TEST_COMMAND: >- python {package}/ci/check_version_number.py MACOSX_DEPLOYMENT_TARGET: "10.12" - MPL_DISABLE_FH4: "yes" strategy: matrix: include: - - os: ubuntu-20.04 + - os: ubuntu-latest cibw_archs: "x86_64" - - os: ubuntu-20.04 + - os: ubuntu-24.04-arm cibw_archs: "aarch64" - os: windows-latest cibw_archs: "auto64" @@ -131,12 +130,6 @@ jobs: cibw_archs: "arm64" steps: - - name: Set up QEMU - if: matrix.cibw_archs == 'aarch64' - uses: docker/setup-qemu-action@49b3bc8e6bdd4a60e6116a5414239cba5943d3cf # v3.2.0 - with: - platforms: arm64 - - name: Download sdist uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 with: @@ -149,16 +142,9 @@ jobs: package-dir: dist/${{ needs.build_sdist.outputs.SDIST_NAME }} env: CIBW_BUILD: "cp313-* cp313t-*" - CIBW_BUILD_FRONTEND: - "pip; args: --pre --extra-index-url https://pypi.anaconda.org/scientific-python-nightly-wheels/simple" - CIBW_FREE_THREADED_SUPPORT: true + CIBW_ENABLE: cpython-freethreading # No free-threading wheels available for aarch64 on Pillow. CIBW_TEST_SKIP: "cp313t-manylinux_aarch64" - # We need pre-releases to get the nightly wheels. - CIBW_BEFORE_TEST: >- - pip install --pre - --extra-index-url https://pypi.anaconda.org/scientific-python-nightly-wheels/simple - contourpy numpy pillow CIBW_ARCHS: ${{ matrix.cibw_archs }} - name: Build wheels for CPython 3.12 @@ -192,14 +178,7 @@ jobs: env: CIBW_BUILD: "pp310-*" CIBW_ARCHS: ${{ matrix.cibw_archs }} - # Work around for https://github.com/pypa/setuptools/issues/4571 - # This can be removed once kiwisolver has wheels for PyPy 3.10 - # https://github.com/nucleic/kiwi/pull/182 - CIBW_BEFORE_TEST: >- - export PIP_CONSTRAINT=pypy-constraint.txt && - echo "setuptools!=72.2.0" > $PIP_CONSTRAINT && - pip install kiwisolver && - unset PIP_CONSTRAINT + CIBW_ENABLE: pypy if: matrix.cibw_archs != 'aarch64' && matrix.os != 'windows-latest' - uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 4bf3e680f7b0..089b15700f1b 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -31,7 +31,7 @@ jobs: persist-credentials: false - name: Initialize CodeQL - uses: github/codeql-action/init@aa578102511db1f4524ed59b8cc2bae4f6e88195 # v3.27.6 + uses: github/codeql-action/init@df409f7d9260372bd5f19e5b04e83cb3c43714ae # v3.27.9 with: languages: ${{ matrix.language }} @@ -42,4 +42,4 @@ jobs: pip install --user -v . - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@aa578102511db1f4524ed59b8cc2bae4f6e88195 # v3.27.6 + uses: github/codeql-action/analyze@df409f7d9260372bd5f19e5b04e83cb3c43714ae # v3.27.9 diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 27aab4b392ee..d42ac6ea00a2 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -155,6 +155,7 @@ jobs: libffi-dev \ libgeos-dev \ libgirepository1.0-dev \ + libnotify4 \ libsdl2-2.0-0 \ libxkbcommon-x11-0 \ libxcb-cursor0 \ @@ -178,8 +179,7 @@ jobs: if [[ "${{ matrix.os }}" = ubuntu-20.04 ]]; then sudo apt-get install -yy --no-install-recommends libopengl0 else # ubuntu-22.04 - sudo apt-get install -yy --no-install-recommends \ - gir1.2-gtk-4.0 libnotify4 + sudo apt-get install -yy --no-install-recommends gir1.2-gtk-4.0 fi ;; macOS) 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/api/axes_api.rst b/doc/api/axes_api.rst index 6afdad4e768e..06893dd95c57 100644 --- a/doc/api/axes_api.rst +++ b/doc/api/axes_api.rst @@ -262,6 +262,7 @@ Property cycle Axes.set_prop_cycle +.. _axes-api-axis: Axis / limits ============= @@ -269,11 +270,16 @@ Axis / limits .. For families of methods of the form {get,set}_{x,y}foo, try to list them in the order set_xfoo, get_xfoo, set_yfoo, get_yfoo +Axis access +----------- + .. autosummary:: :toctree: _as_gen :template: autosummary.rst :nosignatures: + Axes.xaxis + Axes.yaxis Axes.get_xaxis Axes.get_yaxis @@ -616,5 +622,6 @@ Other Axes.get_transformed_clip_path_and_affine Axes.has_data Axes.set + Axes.remove .. autoclass:: matplotlib.axes.Axes.ArtistList diff --git a/doc/api/prev_api_changes/api_changes_3.10.0.rst b/doc/api/prev_api_changes/api_changes_3.10.0.rst index 83bde66213f3..ac4e4e981b21 100644 --- a/doc/api/prev_api_changes/api_changes_3.10.0.rst +++ b/doc/api/prev_api_changes/api_changes_3.10.0.rst @@ -5,7 +5,7 @@ API Changes for 3.10.0 :local: :depth: 1 -.. include:: /api/prev_api_changes/api_changes_3.10.0/behaviour.rst +.. include:: /api/prev_api_changes/api_changes_3.10.0/behavior.rst .. include:: /api/prev_api_changes/api_changes_3.10.0/deprecations.rst diff --git a/doc/api/prev_api_changes/api_changes_3.10.0/behavior.rst b/doc/api/prev_api_changes/api_changes_3.10.0/behavior.rst index 87da6568a860..ae50371fa7aa 100644 --- a/doc/api/prev_api_changes/api_changes_3.10.0/behavior.rst +++ b/doc/api/prev_api_changes/api_changes_3.10.0/behavior.rst @@ -1,3 +1,7 @@ +Behavior Changes +---------------- + + onselect argument to selector widgets made optional ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/doc/api/prev_api_changes/api_changes_3.10.0/deprecations.rst b/doc/api/prev_api_changes/api_changes_3.10.0/deprecations.rst index ad344b37d069..383c19f3c811 100644 --- a/doc/api/prev_api_changes/api_changes_3.10.0/deprecations.rst +++ b/doc/api/prev_api_changes/api_changes_3.10.0/deprecations.rst @@ -1,3 +1,7 @@ +Deprecations +------------ + + Positional parameters in plotting functions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -5,6 +9,7 @@ Many plotting functions will restrict positional arguments to the first few para in the future. All further configuration parameters will have to be passed as keyword arguments. This is to enforce better code and and allow for future changes with reduced risk of breaking existing code. + Changing ``Figure.number`` ~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/doc/api/prev_api_changes/api_changes_3.10.0/development.rst b/doc/api/prev_api_changes/api_changes_3.10.0/development.rst index 58ece9877912..329256b466b5 100644 --- a/doc/api/prev_api_changes/api_changes_3.10.0/development.rst +++ b/doc/api/prev_api_changes/api_changes_3.10.0/development.rst @@ -1,3 +1,6 @@ +Development changes +------------------- + Documentation-specific custom Sphinx roles are now semi-public ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/doc/api/prev_api_changes/api_changes_3.10.0/removals.rst b/doc/api/prev_api_changes/api_changes_3.10.0/removals.rst index e535123c7016..7ed06e7446ef 100644 --- a/doc/api/prev_api_changes/api_changes_3.10.0/removals.rst +++ b/doc/api/prev_api_changes/api_changes_3.10.0/removals.rst @@ -1,3 +1,7 @@ +Removals +-------- + + ttconv removed ~~~~~~~~~~~~~~ diff --git a/doc/api/prev_api_changes/api_changes_3.10.1.rst b/doc/api/prev_api_changes/api_changes_3.10.1.rst new file mode 100644 index 000000000000..26d43ddf8b17 --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_3.10.1.rst @@ -0,0 +1,14 @@ +API Changes for 3.10.1 +====================== + +Behaviour +--------- + +*alpha* parameter handling on images +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When passing and array to ``imshow(..., alpha=...)``, the parameter was silently ignored +if the image data was a RGB or RBGA image or if :rc:`interpolation_state` +resolved to "rbga". + +This is now fixed, and the alpha array overwrites any previous transparency information. diff --git a/doc/api/scale_api.rst b/doc/api/scale_api.rst index 1eb890dcfb48..623fbdd0392f 100644 --- a/doc/api/scale_api.rst +++ b/doc/api/scale_api.rst @@ -6,3 +6,4 @@ :members: :undoc-members: :show-inheritance: + :member-order: bysource diff --git a/doc/devel/min_dep_policy.rst b/doc/devel/min_dep_policy.rst index 6ff083ca6dc1..e9e18ed391dc 100644 --- a/doc/devel/min_dep_policy.rst +++ b/doc/devel/min_dep_policy.rst @@ -115,6 +115,7 @@ specification of the dependencies. ========== ======== ====== Matplotlib Python NumPy ========== ======== ====== +`3.10`_ 3.10 1.23.0 `3.9`_ 3.9 1.23.0 `3.8`_ 3.9 1.21.0 `3.7`_ 3.8 1.20.0 @@ -136,6 +137,7 @@ Matplotlib Python NumPy 1.0 2.4 1.1 ========== ======== ====== +.. _`3.10`: https://matplotlib.org/3.10.0/devel/dependencies.html .. _`3.9`: https://matplotlib.org/3.9.0/devel/dependencies.html .. _`3.8`: https://matplotlib.org/3.8.0/devel/dependencies.html .. _`3.7`: https://matplotlib.org/3.7.0/devel/dependencies.html diff --git a/doc/install/dependencies.rst b/doc/install/dependencies.rst index b8f54f346186..3034a64a3361 100644 --- a/doc/install/dependencies.rst +++ b/doc/install/dependencies.rst @@ -256,7 +256,7 @@ source files. .. tab-item:: Linux On some Linux systems, you can install a meta-build package. For example, - on Ubuntu ``apt install build-essential`` + on Ubuntu ``apt install build-essential`` with elevated privileges. Otherwise, use the system distribution's package manager to install :ref:`gcc `. diff --git a/doc/project/citing.rst b/doc/project/citing.rst index be58473a26e4..2cd317906bb5 100644 --- a/doc/project/citing.rst +++ b/doc/project/citing.rst @@ -32,6 +32,9 @@ By version .. START OF AUTOGENERATED +v3.10.0 + .. image:: ../_static/zenodo_cache/14464227.svg + :target: https://doi.org/10.5281/zenodo.14464227 v3.9.4 .. image:: ../_static/zenodo_cache/14436121.svg :target: https://doi.org/10.5281/zenodo.14436121 diff --git a/doc/sphinxext/gallery_order.py b/doc/sphinxext/gallery_order.py index 378cb394d37b..99b90062a42a 100644 --- a/doc/sphinxext/gallery_order.py +++ b/doc/sphinxext/gallery_order.py @@ -86,6 +86,8 @@ def __call__(self, item): "color_demo", # pies "pie_features", "pie_demo2", + # scales + "scales", # Scales overview # **Plot Types # Basic diff --git a/doc/users/github_stats.rst b/doc/users/github_stats.rst index c12a983aa6a8..de1f85004f09 100644 --- a/doc/users/github_stats.rst +++ b/doc/users/github_stats.rst @@ -1,590 +1,174 @@ .. _github-stats: -GitHub statistics for 3.10.0 (Dec 13, 2024) +GitHub statistics for 3.10.1 (Feb 27, 2025) =========================================== -GitHub statistics for 2024/05/15 (tag: v3.9.0) - 2024/12/13 +GitHub statistics for 2024/12/14 (tag: v3.10.0) - 2025/02/27 These lists are automatically generated, and may be incomplete or contain duplicates. -We closed 100 issues and merged 337 pull requests. -The full list can be seen `on GitHub `__ +We closed 14 issues and merged 107 pull requests. +The full list can be seen `on GitHub `__ -The following 128 authors contributed 1932 commits. +The following 28 authors contributed 241 commits. -* abhi-jha -* Adam J. Stewart -* Aditi Gautam -* Aditya Vidyadhar Kamath -* Aishling Cooke -* Alan -* Alan Sosa -* Alice -* Aman Nijjar -* Ammar Qazi -* Ancheng -* anpaulan -* Anson0028 -* Anthony Lee -* anTon +* Anselm Hahn * Antony Lee -* Ayoub Gouasmi -* Brigitta Sipőcz -* Caitlin Hathaway -* cesar -* Charlie LeWarne -* Christian Mattsson -* ClarkeAC -* Clemens Brunner -* Clement Gilli -* cmp0xff -* Costa Paraskevopoulos -* dale -* Dani Pinyol -* Daniel Weiss -* Danny -* David Bakaj -* David Lowry-Duda -* David Meyer -* David Stansby -* dbakaj +* Ben Greiner +* Chaoyi Hu +* Christine P. Chai * dependabot[bot] -* Diogo Cardoso -* Doron Behar -* Edgar Andrés Margffoy Tuay * Elliott Sales de Andrade -* Eytan Adler -* farquh -* Felipe Cybis Pereira -* Filippo Balzaretti -* FMasson -* Francisco Cardozo -* Gavin S +* G.D. McBain * Greg Lucas -* haaris * hannah -* Ian Thomas -* Illviljan -* James Addison -* James Spencer -* Jody Klymak -* john -* Jonas Eschle -* Jouni K. Seppänen -* juanis2112 -* Juanita Gomez -* Justin Hendrick -* K900 -* Kaustbh -* Kaustubh -* Kherim Willems +* hu-xiaonan +* Khushi_29 +* Khushikela29 +* KIU Shueng Chuan +* Kyle Martin * Kyle Sunden -* Kyra Cho -* Larry Bradley -* litchi -* Lorenzo -* Lucx33 * Lumberbot (aka Jack) -* MadPhysicist -* malhar2460 -* Martino Sorbaro -* Mathias Hauser -* Matthew Feickert -* Matthew Petroff -* Melissa Weber Mendonça -* Michael -* Michael Droettboom -* Michael Hinton -* MischaMegens2 -* Moritz Wolter -* muchojp -* Nabil -* nakamura yuki -* odile -* OdileVidrine +* Manthan Nagvekar +* musvaage +* Nathan G. Wiseman * Oscar Gustafsson -* Panicks28 -* Paul An -* Pedro Barão -* PedroBittarBarao -* Peter Talley -* Pierre-antoine Comby -* Pranav -* Pranav Raghu -* pre-commit-ci[bot] -* proximalf -* r3kste -* Randolf Scholz -* Refael Ackermann -* RickyP24 -* rnhmjoj +* Owl * Ruth Comer -* Ryan May -* Sai Chaitanya, Sanivada -* saranti -* scaccol +* saikarna913 * Scott Shambaugh -* Sean Smith -* Simon May -* simond07 -* smcgrawDotNet -* Takumasa N -* Takumasa N. -* Takumasa Nakamura -* thiagoluisbecker * Thomas A Caswell -* Tiago Lubiana * Tim Hoffmann -* trananso * Trygve Magnus Ræder -* Victor Liu -* vittoboa -* Xeniya Shoiko GitHub issues and pull requests: -Pull Requests (337): +Pull Requests (107): -* :ghpull:`29299`: Merge v3.9.x into v3.10.x -* :ghpull:`29296`: Backport PR #29295 on branch v3.10.x (BLD: Pin meson-python to <0.17.0) -* :ghpull:`29290`: Backport PR #29254 on branch v3.10.x (DOC: Add note to align_labels()) -* :ghpull:`29289`: Backport PR #29260 on branch v3.10.x (DOC: Better explanation of rcParams "patch.edgecolor" and "patch.force_edgecolor") -* :ghpull:`29288`: Backport PR #29285 on branch v3.10.x (Retarget PR#29175 to main) -* :ghpull:`29254`: DOC: Add note to align_labels() -* :ghpull:`29260`: DOC: Better explanation of rcParams "patch.edgecolor" and "patch.force_edgecolor" -* :ghpull:`29285`: Retarget PR#29175 to main -* :ghpull:`29286`: Backport PR #29274 on branch v3.10.x (Bump the actions group across 1 directory with 2 updates) -* :ghpull:`29274`: Bump the actions group across 1 directory with 2 updates -* :ghpull:`29283`: Backport PR #29272 on branch v3.10.x (DOC: Add section on translating between Axes and pyplot interface) -* :ghpull:`29272`: DOC: Add section on translating between Axes and pyplot interface -* :ghpull:`29279`: Backport PR #29265 on branch v3.10.x (DOC: Slightly improve the LineCollection docstring) -* :ghpull:`29276`: Backport PR #29247 on branch v3.10.x (Fix building freetype 2.6.1 on macOS clang 18) -* :ghpull:`29244`: Switch to a 3d rotation trackball implementation with path independence -* :ghpull:`29265`: DOC: Slightly improve the LineCollection docstring -* :ghpull:`29247`: Fix building freetype 2.6.1 on macOS clang 18 -* :ghpull:`29268`: Bump the actions group with 2 updates -* :ghpull:`29266`: Backport PR #29251 on branch v3.10.x (Zizmor audit) -* :ghpull:`29269`: Backport PR #29267 on branch v3.10.x (Exclude pylab from mypy checks) -* :ghpull:`29267`: Exclude pylab from mypy checks -* :ghpull:`29251`: Zizmor audit -* :ghpull:`29255`: Backport PR #29249 on branch v3.10.x ([Bug Fix] Fix reverse mapping for _translate_tick_params) -* :ghpull:`29249`: [Bug Fix] Fix reverse mapping for _translate_tick_params -* :ghpull:`29250`: Backport PR #29243 on branch v3.10.x (Add quotes around [dev] in environment.yml) -* :ghpull:`29243`: Add quotes around [dev] in environment.yml -* :ghpull:`29246`: Backport PR #29240 on branch v3.10.x (DOC: Add plt.show() to introductory pyplot example) -* :ghpull:`29240`: DOC: Add plt.show() to introductory pyplot example -* :ghpull:`29239`: Backport PR #29236 on branch v3.10.x (ANI: Reduce Pillow frames to RGB when opaque) -* :ghpull:`29238`: Backport PR #29167 on branch v3.10.x (BUGFIX: use axes unit information in ConnectionPatch ) -* :ghpull:`29236`: ANI: Reduce Pillow frames to RGB when opaque -* :ghpull:`29167`: BUGFIX: use axes unit information in ConnectionPatch -* :ghpull:`29232`: Merge branch v3.9.x into v3.10.x -* :ghpull:`29230`: Backport PR #29188 on branch v3.10.x (Bump pypa/cibuildwheel from 2.21.3 to 2.22.0 in the actions group) -* :ghpull:`29188`: Bump pypa/cibuildwheel from 2.21.3 to 2.22.0 in the actions group -* :ghpull:`29225`: Backport PR #29213 on branch v3.10.x (avoid-unnecessary-warning-in-_pcolorargs-function) -* :ghpull:`29211`: Backport PR #29133 on branch v3.10.x (Creating_parse_bar_color_args to unify color handling in plt.bar with precedence and sequence support for facecolor and edgecolor) -* :ghpull:`29177`: Backport PR #29148 on branch v3.10.x (Don't fail on equal-but-differently-named cmaps in qt figureoptions.) -* :ghpull:`29226`: Backport PR #29206 on branch v3.10.x (Skip more tests on pure-Wayland systems) -* :ghpull:`29206`: Skip more tests on pure-Wayland systems -* :ghpull:`29213`: avoid-unnecessary-warning-in-_pcolorargs-function -* :ghpull:`29210`: Backport PR #29209 on branch v3.10.x (FIX: pcolormesh with no x y args and nearest interp) -* :ghpull:`29133`: Creating_parse_bar_color_args to unify color handling in plt.bar with precedence and sequence support for facecolor and edgecolor -* :ghpull:`29209`: FIX: pcolormesh with no x y args and nearest interp -* :ghpull:`29200`: Backport PR #29182 on branch v3.10.x (Update backend_qt.py: parent not passed to __init__ on subplottool) -* :ghpull:`29207`: Backport PR #29169 on branch v3.10.x (Minor fixes to text intro explainer) -* :ghpull:`29169`: Minor fixes to text intro explainer -* :ghpull:`29159`: Pending warning for deprecated parameter 'vert' of box and violin on 3.10 -* :ghpull:`29196`: Backport PR #29191 on branch v3.10.x (ci: Simplify 3.13t test setup) -* :ghpull:`29182`: Update backend_qt.py: parent not passed to __init__ on subplottool -* :ghpull:`29189`: Backport PR #28934 on branch v3.10.x (ci: Unpin micromamba again) -* :ghpull:`29186`: Backport PR #28335 on branch v3.10.x (DOC: do not posting LLM output as your own work) -* :ghpull:`28934`: ci: Unpin micromamba again -* :ghpull:`28335`: DOC: do not posting LLM output as your own work -* :ghpull:`29178`: Backport PR #29163 on branch v3.9.x (ci: Remove outdated pkg-config package on macOS) -* :ghpull:`29170`: Backport PR #29154 on branch v3.10.x (Relax conditions for warning on updating converters) -* :ghpull:`29154`: Relax conditions for warning on updating converters -* :ghpull:`29166`: Backport PR #29153 on branch v3.10.x (Bump codecov/codecov-action from 4 to 5 in the actions group) -* :ghpull:`29164`: Backport PR #29163 on branch v3.10.x (ci: Remove outdated pkg-config package on macOS) -* :ghpull:`29168`: Backport PR #29073 on branch v3.10.x (Update secondary_axis tutorial) -* :ghpull:`29073`: Update secondary_axis tutorial -* :ghpull:`29163`: ci: Remove outdated pkg-config package on macOS -* :ghpull:`29145`: Backport PR #29144 on branch v3.10.x (Use both TCL_SETVAR and TCL_SETVAR2 for tcl 9 support) -* :ghpull:`29144`: Use both TCL_SETVAR and TCL_SETVAR2 for tcl 9 support -* :ghpull:`29140`: Backport PR #29080 on branch v3.10.x (Updates the ``galleries/tutorials/artists.py`` file in response to issue #28920) -* :ghpull:`29080`: Updates the ``galleries/tutorials/artists.py`` file in response to issue #28920 -* :ghpull:`29138`: Backport PR #29134 on branch v3.10.x (MNT: Temporarily skip failing test to unbreak CI) -* :ghpull:`29134`: MNT: Temporarily skip failing test to unbreak CI -* :ghpull:`29132`: Backport PR #29128 on branch v3.10.x (Tweak AutoMinorLocator docstring.) -* :ghpull:`29128`: Tweak AutoMinorLocator docstring. -* :ghpull:`29123`: Bump the actions group with 2 updates -* :ghpull:`29122`: Backport PR #29120 on branch v3.10.x (DOC: Switch nested pie example from cmaps to color_sequences) -* :ghpull:`29100`: Backport PR #29099 on branch v3.10.x (MNT: remove _ttconv.pyi) -* :ghpull:`29099`: MNT: remove _ttconv.pyi -* :ghpull:`29098`: Backport PR #29097 on branch v3.10.x (ENH: add back/forward buttons to osx backend move) -* :ghpull:`29097`: ENH: add back/forward buttons to osx backend move -* :ghpull:`29095`: Backport PR #29071 on branch v3.10.x (Bump pypa/gh-action-pypi-publish from 1.10.3 to 1.11.0 in the actions group) -* :ghpull:`29096`: Backport PR #29094 on branch v3.10.x (DOC: fix link in See Also section of axes.violin) -* :ghpull:`29092`: Backport PR #29088 on branch v3.10.x (DOC: Format aliases in kwargs tables) -* :ghpull:`29094`: DOC: fix link in See Also section of axes.violin -* :ghpull:`29091`: Backport PR #29085 on branch v3.10.x (FIX: Update GTK3Agg backend export name for consistency) -* :ghpull:`29088`: DOC: Format aliases in kwargs tables -* :ghpull:`29089`: Backport PR #29065 on branch v3.10.x (DOC: Update docstring of triplot()) -* :ghpull:`29085`: FIX: Update GTK3Agg backend export name for consistency -* :ghpull:`29084`: Backport PR #29081 on branch v3.10.x (Document "none" as color value) -* :ghpull:`29065`: DOC: Update docstring of triplot() -* :ghpull:`29081`: Document "none" as color value -* :ghpull:`29061`: Backport PR #29024 on branch v3.10.x (Fix saving animations to transparent formats) -* :ghpull:`29069`: Backport PR #29068 on branch v3.10.x ([DOC] Fix indentation in sync_cmaps example) -* :ghpull:`29070`: Backport PR #29048 on branch v3.10.x (DOC: integrated pr workflow from contributing guide into install and workflow) -* :ghpull:`29048`: DOC: integrated pr workflow from contributing guide into install and workflow -* :ghpull:`29068`: [DOC] Fix indentation in sync_cmaps example -* :ghpull:`29024`: Fix saving animations to transparent formats -* :ghpull:`29059`: Cleanup converter docs and StrCategoryConverter behavior -* :ghpull:`29058`: [DOC] Update missing-references.json -* :ghpull:`29057`: DOC/TST: lock numpy<2.1 in environment.yml -* :ghpull:`29053`: Factor out common formats strings in LogFormatter, LogFormatterExponent. -* :ghpull:`28970`: Add explicit converter setting to Axis -* :ghpull:`28048`: Enables setting hatch linewidth in Patches and Collections, also fixes setting hatch linewidth by rcParams -* :ghpull:`29017`: DOC: Document preferred figure size for examples -* :ghpull:`28871`: updated contribution doc #28476 -* :ghpull:`28453`: Stop relying on dead-reckoning mouse buttons for motion_notify_event. -* :ghpull:`28495`: ticker.EngFormatter: allow offset -* :ghpull:`29039`: MNT: Add provisional get_backend(resolve=False) flag -* :ghpull:`28946`: MNT: Deprecate plt.polar() with an existing non-polar Axes -* :ghpull:`29013`: FIX: auto_fmtxdate for constrained layout -* :ghpull:`29022`: Fixes AIX internal CI build break. -* :ghpull:`28830`: Feature: Support passing DataFrames to table.table -* :ghpull:`27766`: Return filename from save_figure -* :ghpull:`27167`: ENH: add long_axis property to colorbar -* :ghpull:`29021`: Update minimum pybind11 to 2.13.2 -* :ghpull:`28863`: Improved documentation for quiver -* :ghpull:`29019`: Update requirements to add PyStemmer to doc-requirements and environment -* :ghpull:`28653`: Mnt/generalize plot varargs -* :ghpull:`28967`: Fix MSVC cast warnings -* :ghpull:`29016`: DOC: Better explain suptitle / supxlabel / supylabel naming -* :ghpull:`28842`: FT2Font extension improvements -* :ghpull:`28658`: New data → color pipeline -* :ghpull:`29012`: Bump required pybind11 to 2.13 -* :ghpull:`29007`: MNT: Deprecate changing Figure.number -* :ghpull:`28861`: Break Artist._remove_method reference cycle -* :ghpull:`28478`: bugfix for ``PathSimplifier`` -* :ghpull:`28992`: DOC: Refresh transform tree example -* :ghpull:`28890`: MNT: Add missing dependency to environment.yml -* :ghpull:`28354`: Add Quiverkey zorder option -* :ghpull:`28966`: Fix polar error bar cap orientation -* :ghpull:`28819`: Mark all extensions as free-threading safe -* :ghpull:`28986`: DOC: Add tags for 3D fill_between examples -* :ghpull:`28984`: DOC / BUG: Better example for 3D axlim_clip argument -* :ghpull:`20866`: Remove ttconv and implement Type-42 embedding using fontTools -* :ghpull:`28975`: Set guiEvent where applicable for gtk4. -* :ghpull:`28568`: added tags to mplot3d examples -* :ghpull:`28976`: Bump pypa/cibuildwheel from 2.21.2 to 2.21.3 in the actions group -* :ghpull:`28978`: CI: Resolve mypy stubtest build errors -* :ghpull:`28823`: Fix 3D rotation precession -* :ghpull:`28841`: Make mplot3d mouse rotation style adjustable -* :ghpull:`28971`: DOC: correct linestyle example and reference rcParams -* :ghpull:`28702`: [MNT]: #28701 separate the generation of polygon vertices in fill_between to enable resampling -* :ghpull:`28965`: Suggest imageio_ffmpeg to provide ffmpeg as animation writer. -* :ghpull:`28964`: FIX macos: Use the agg buffer_rgba rather than private attribute -* :ghpull:`28963`: Remove refs to outdated writers in animation.py. -* :ghpull:`28948`: Raise ValueError for RGB values outside the [0, 1] range in rgb_to_hsv function -* :ghpull:`28857`: Pybind11 cleanup -* :ghpull:`28949`: [pre-commit.ci] pre-commit autoupdate -* :ghpull:`28950`: Bump the actions group with 2 updates -* :ghpull:`28904`: Agg: Remove 16-bit limits -* :ghpull:`28856`: Convert remaining code to pybind11 -* :ghpull:`28874`: Remove remaining 3.8 deprecations -* :ghpull:`28943`: DOC: Clarify the returned line of axhline()/axvline() -* :ghpull:`28935`: DOC: Fix invalid rcParam references -* :ghpull:`28942`: In colorbar docs, add ref from 'boundaries' doc to 'spacing' doc. -* :ghpull:`28933`: Switch AxLine.set_xy{1,2} to take a single argument. -* :ghpull:`28869`: ci: Bump build image on AppVeyor to MSVC 2019 -* :ghpull:`28906`: Re-fix exception caching in dviread. -* :ghpull:`27349`: [ENH] Implement dynamic clipping to axes limits for 3D plots -* :ghpull:`28913`: DOC: Fix Axis.set_label reference -* :ghpull:`28911`: MNT: Fix double evaluation of _LazyTickList -* :ghpull:`28584`: MNT: Prevent users from erroneously using legend label API on Axis -* :ghpull:`28853`: MNT: Check the input sizes of regular X,Y in pcolorfast -* :ghpull:`28838`: TST: Fix minor issues in interactive backend test -* :ghpull:`28795`: MNT: Cleanup docstring substitution mechanisms -* :ghpull:`28897`: Fix minor issues in stubtest wrapper -* :ghpull:`28899`: Don't cache exception with traceback reference loop in dviread. -* :ghpull:`28888`: DOC: Better visualization for the default color cycle example -* :ghpull:`28896`: doc: specify non-python dependencies in dev install docs -* :ghpull:`28843`: MNT: Cleanup FontProperties __init__ API -* :ghpull:`28683`: MNT: Warn if fixed aspect overwrites explicitly set data limits -* :ghpull:`25645`: Fix issue with sketch not working on PathCollection in Agg -* :ghpull:`28886`: DOC: Cross-link Axes attributes -* :ghpull:`28880`: Remove 'in' from removal substitution for deprecation messages -* :ghpull:`28875`: DOC: Fix documentation of hist() kwarg lists -* :ghpull:`28825`: DOC: Fix non-working code object references -* :ghpull:`28862`: Improve pie chart error messages -* :ghpull:`28844`: DOC: Add illustration to Figure.subplots_adjust -* :ghpull:`28588`: Fix scaling in Tk on non-Windows systems -* :ghpull:`28849`: DOC: Mark subfigures as no longer provisional -* :ghpull:`26000`: making onselect a keyword argument on selectors -* :ghpull:`26013`: Support unhashable callbacks in CallbackRegistry -* :ghpull:`27011`: Convert Agg extension to pybind11 -* :ghpull:`28845`: In examples, prefer named locations rather than location numbers. -* :ghpull:`27218`: API: finish LocationEvent.lastevent removal -* :ghpull:`26870`: Removed the deprecated code from axis.py -* :ghpull:`27996`: Create ``InsetIndicator`` artist -* :ghpull:`28532`: TYP: Fix xycoords and friends -* :ghpull:`28785`: Convert ft2font extension to pybind11 -* :ghpull:`28815`: DOC: Document policy on colormaps and styles -* :ghpull:`28826`: MNT: Replace _docstring.dedent_interpd by its alias _docstring.interpd -* :ghpull:`27567`: DOC: batch of tags -* :ghpull:`27302`: Tags for simple_scatter.py demo -* :ghpull:`28820`: DOC: Fix missing cross-reference checks for sphinx-tags -* :ghpull:`28786`: Handle single color in ContourSet -* :ghpull:`28808`: DOC: Add a plot to margins() to visualize the effect -* :ghpull:`27938`: feat: add dunder method for math operations on Axes Size divider -* :ghpull:`28569`: Adding tags to many examples -* :ghpull:`28183`: Expire deprecations -* :ghpull:`28801`: DOC: Clarify AxLine.set_xy2 / AxLine.set_slope -* :ghpull:`28788`: TST: Skip webp tests if it isn't available -* :ghpull:`28550`: Remove internal use of ``Artist.figure`` -* :ghpull:`28767`: MNT: expire ``ContourSet`` deprecations -* :ghpull:`28755`: TYP: Add typing for internal _tri extension -* :ghpull:`28765`: Add tests for most of FT2Font, and fix some bugs -* :ghpull:`28781`: TST: Fix test_pickle_load_from_subprocess in a dirty tree -* :ghpull:`28783`: Fix places where "auto" was not listed as valid interpolation_stage. -* :ghpull:`28779`: DOC/TST: lock numpy < 2.1 -* :ghpull:`28771`: Ensure SketchParams is always fully initialized -* :ghpull:`28375`: FIX: Made AffineDeltaTransform pass-through properly -* :ghpull:`28454`: MultivarColormap and BivarColormap -* :ghpull:`27891`: Refactor some parts of ft2font extension -* :ghpull:`28752`: quick fix dev build by locking out numpy version that's breaking things -* :ghpull:`28749`: Add sphinxcontrib-video to environment.yml -* :ghpull:`27851`: Add ten-color accessible color cycle as style sheet -* :ghpull:`28501`: ConciseDateFormatter's offset string is correct on an inverted axis -* :ghpull:`28734`: Compressed layout moves suptitle -* :ghpull:`28736`: Simplify some code in dviread -* :ghpull:`28347`: Doc: added triage section to new contributor docs -* :ghpull:`28735`: ci: Avoid setuptools 72.2.0 when installing kiwi on PyPy -* :ghpull:`28728`: MNT: Deprecate reimported functions in top-level namespace -* :ghpull:`28730`: MNT: Don't rely on RcParams being a dict subclass in internal code -* :ghpull:`28714`: Simplify _api.warn_external on Python 3.12+ -* :ghpull:`28727`: MNT: Better workaround for format_cursor_data on ScalarMappables -* :ghpull:`28725`: Stop disabling FH4 Exception Handling on MSVC -* :ghpull:`28711`: Merge branch v3.9.x into main -* :ghpull:`28713`: DOC: Add a few more notes to release guide -* :ghpull:`28720`: DOC: Clarify axhline() uses axes coordinates -* :ghpull:`28718`: DOC: Update missing references for numpydoc 1.8.0 -* :ghpull:`28710`: DOC: clarify alpha handling for indicate_inset[_zoom] -* :ghpull:`28704`: Fixed arrowstyle doc interpolation in FancyPatch.set_arrow() #28698. -* :ghpull:`28709`: Bump actions/attest-build-provenance from 1.4.0 to 1.4.1 in the actions group -* :ghpull:`28707`: Avoid division-by-zero in Sketch::Sketch -* :ghpull:`28610`: CI: Add CI to test matplotlib against free-threaded Python -* :ghpull:`28262`: Fix PolygonSelector cursor to temporarily hide during active zoom/pan -* :ghpull:`28670`: API: deprecate unused helper in patch._Styles -* :ghpull:`28589`: Qt embedding example: Separate drawing and data retrieval timers -* :ghpull:`28655`: Inline annotation and PGF user demos -* :ghpull:`28654`: DOC: Remove long uninstructive examples -* :ghpull:`28652`: Fix docstring style inconsistencies in lines.py -* :ghpull:`28641`: DOC: Standardize example titles - part 2 -* :ghpull:`28642`: DOC: Simplify heatmap example -* :ghpull:`28638`: DOC: Remove hint on PRs from origin/main -* :ghpull:`28587`: Added dark-mode diverging colormaps -* :ghpull:`28546`: DOC: Clarify/simplify example of multiple images with one colorbar -* :ghpull:`28613`: Added documentation for parameters vmin and vmax inside specgram function. -* :ghpull:`28627`: DOC: Bump minimum Sphinx to 5.1.0 -* :ghpull:`28628`: DOC: Sub-structure next API changes overview -* :ghpull:`28629`: FIX: ``Axis.set_in_layout`` respected -* :ghpull:`28575`: Add branch tracking to development workflow instructions -* :ghpull:`28616`: CI: Build docs on latest Python -* :ghpull:`28617`: DOC: Enable parallel builds -* :ghpull:`28544`: DOC: Standardize example titles -* :ghpull:`28615`: DOC: hack to suppress sphinx-gallery 17.0 warning -* :ghpull:`28293`: BLD: Enable building Python 3.13 wheels for nightlies -* :ghpull:`27385`: Fix 3D lines being visible when behind camera -* :ghpull:`28609`: svg: Ensure marker-only lines get URLs -* :ghpull:`28599`: Upgrade code to Python 3.10 -* :ghpull:`28593`: Update ruff to 0.2.0 -* :ghpull:`28603`: Simplify ttconv python<->C++ conversion using std::optional. -* :ghpull:`28557`: DOC: apply toc styling to remove nesting -* :ghpull:`28542`: CI: adjust pins in mypy GHA job -* :ghpull:`28504`: Changes in SVG backend to improve compatibility with Affinity designer -* :ghpull:`28122`: Disable clipping in Agg resamplers. -* :ghpull:`28597`: Pin PyQt6 back on Ubuntu 20.04 -* :ghpull:`28073`: Add support for multiple hatches, edgecolors and linewidths in histograms -* :ghpull:`28594`: MNT: Raise on GeoAxes limits manipulation -* :ghpull:`28312`: Remove one indirection layer in ToolSetCursor. -* :ghpull:`28573`: ENH: include property name in artist AttributeError -* :ghpull:`28503`: Bump minimum Python to 3.10 -* :ghpull:`28525`: FIX: colorbar pad for ``ImageGrid`` -* :ghpull:`28558`: DOC: Change _make_image signature to numpydoc -* :ghpull:`28061`: API: add antialiased to interpolation-stage in image -* :ghpull:`28536`: [svg] Add rcParam["svg.id"] to add a top-level id attribute to -* :ghpull:`28540`: Subfigures become stale when their artists are stale -* :ghpull:`28177`: Rationalise artist get_figure methods; make figure attribute a property -* :ghpull:`28527`: DOC: improve tagging guidelines page -* :ghpull:`28530`: DOC: Simplify axhspan example -* :ghpull:`28537`: DOC: Update timeline example for newer releases -* :ghpull:`27833`: [SVG] Introduce sequential ID-generation scheme for clip-paths. -* :ghpull:`28512`: DOC: Fix version switcher for stable docs -* :ghpull:`28492`: MNT: Remove PolyQuadMesh deprecations -* :ghpull:`28509`: CI: Use micromamba on AppVeyor -* :ghpull:`28510`: Merge v3.9.1 release into main -* :ghpull:`28494`: [pre-commit.ci] pre-commit autoupdate -* :ghpull:`28497`: Add words to ignore for codespell -* :ghpull:`28455`: Expand ticklabels_rotation example to cover rotating default ticklabels. -* :ghpull:`28282`: DOC: clarify no-build-isolation & mypy ignoring new functions -* :ghpull:`28306`: Fixed PolarAxes not using fmt_xdata and added simple test (#4568) -* :ghpull:`28400`: DOC: Improve doc wording of data parameter -* :ghpull:`28225`: [ENH]: fill_between extended to 3D -* :ghpull:`28371`: Bump pypa/cibuildwheel from 2.18.1 to 2.19.0 in the actions group -* :ghpull:`28390`: Inline RendererBase._get_text_path_transform. -* :ghpull:`28381`: Take hinting rcParam into account in MathTextParser cache. -* :ghpull:`28363`: flip subfigures axes to match subplots -* :ghpull:`28340`: Fix missing font error when using MiKTeX -* :ghpull:`28379`: PathEffectsRenderer can plainly inherit RendererBase._draw_text_as_path. -* :ghpull:`28275`: Revive sanitizing default filenames extracted from UI window titles -* :ghpull:`28360`: DOC: fixed code for testing check figures equal example -* :ghpull:`28370`: Reorder Axes3D parameters semantically. -* :ghpull:`28350`: Typo in communication guide: extensiblity -> extensibility -* :ghpull:`28290`: Introduce natural 3D rotation with mouse -* :ghpull:`28186`: apply unary minus spacing directly after equals sign -* :ghpull:`28311`: Update 3D orientation indication right away -* :ghpull:`28300`: Faster title alignment -* :ghpull:`28313`: Factor out handling of missing spines in alignment calculations. -* :ghpull:`28196`: TST: add timeouts to font_manager + threading test -* :ghpull:`28279`: Doc/ipython dep -* :ghpull:`28091`: [MNT]: create build-requirements.txt and update dev-requirements.txt -* :ghpull:`27992`: Add warning for multiple pyplot.figure calls with same ID -* :ghpull:`28238`: DOC: Update release guide to match current automations -* :ghpull:`28232`: Merge v3.9.0 release into main -* :ghpull:`28228`: DOC: Fix typo in release_guide.rst -* :ghpull:`28074`: Add ``orientation`` parameter to Boxplot and deprecate ``vert`` -* :ghpull:`27998`: Add a new ``orientation`` parameter to Violinplot and deprecate ``vert`` -* :ghpull:`28217`: Better group logging of font handling by texmanager. -* :ghpull:`28130`: Clarify the role of out_mask and out_alpha in _make_image. -* :ghpull:`28201`: Deprecate ``Poly3DCollection.get_vector`` -* :ghpull:`28046`: DOC: Clarify merge policy -* :ghpull:`26893`: PGF: Consistently set LaTeX document font size -* :ghpull:`28156`: Don't set savefig.facecolor/edgecolor in dark_background/538 styles. -* :ghpull:`28030`: Fix #28016: wrong lower ylim when baseline=None on stairs -* :ghpull:`28127`: GOV: write up policy on not updating req for CVEs in dependencies -* :ghpull:`28106`: Fix: [Bug]: Setting norm by string doesn't work for hexbin #28105 -* :ghpull:`28143`: Merge branch v3.9.x into main -* :ghpull:`28133`: Make ``functions`` param to secondary_x/yaxis not keyword-only. -* :ghpull:`28083`: Convert TensorFlow to numpy for plots -* :ghpull:`28116`: FIX: Correct names of aliased cmaps -* :ghpull:`28118`: Remove redundant baseline tests in test_image. -* :ghpull:`28093`: Minor maintenance on pgf docs/backends. -* :ghpull:`27818`: Set polygon offsets for log scaled hexbin -* :ghpull:`28058`: TYP: add float to to_rgba x type -* :ghpull:`27964`: BUG: Fix NonUniformImage with nonlinear scale -* :ghpull:`28054`: DOC: Clarify that parameters to gridded data plotting functions are p… -* :ghpull:`27882`: Deleting all images that have passed tests before upload -* :ghpull:`28033`: API: warn if stairs used in way that is likely not desired -* :ghpull:`27786`: Deprecate positional use of most arguments of plotting functions -* :ghpull:`28025`: DOC: Clarify interface terminology -* :ghpull:`28043`: MNT: Add git blame ignore for docstring parameter indentation fix -* :ghpull:`28037`: DOC: Fix inconsistent spacing in some docstrings in _axes.py -* :ghpull:`28031`: Be more specific in findobj return type +* :ghpull:`29682`: Backport PR #29680 on branch v3.10.x (DOC: fix the bug of examples\event_handling) +* :ghpull:`29683`: Backport PR #29670 on branch v3.10.x (DOC: change marginal scatter plot to subplot_mosaic) +* :ghpull:`29680`: DOC: fix the bug of examples\event_handling +* :ghpull:`29676`: Backport PR #29666 on branch v3.10.x (DOC: Revising the Figure Legend Demo Example) +* :ghpull:`29675`: Backport PR #29662 on branch v3.10.x (DOC: Move Colorbar parameters to __init__) +* :ghpull:`29662`: DOC: Move Colorbar parameters to __init__ +* :ghpull:`29668`: Backport PR #29667 on branch v3.10.x (DOC: remove redundant gridspec from example) +* :ghpull:`29664`: Backport PR #29642 on branch v3.10.x (DOC: Add docstrings to get_usetex and set_usetex in ticker.py) +* :ghpull:`29663`: Backport PR #29075 on branch v3.10.x (Add xaxis and yaxis attributes to Axes docs) +* :ghpull:`29642`: DOC: Add docstrings to get_usetex and set_usetex in ticker.py +* :ghpull:`29661`: Backport PR #29652 on branch v3.10.x (Reorder kwonly kwargs in Colorbar & related docs.) +* :ghpull:`29652`: Reorder kwonly kwargs in Colorbar & related docs. +* :ghpull:`29075`: Add xaxis and yaxis attributes to Axes docs +* :ghpull:`29656`: Backport PR #28437 on branch v3.10.x (Respect array alpha with interpolation_stage='rgba' in _Imagebase::_make_image) +* :ghpull:`29448`: Backport PR #29362 on branch v3.10.0-doc (TYP: semantics of enums in stub files changed) +* :ghpull:`28437`: Respect array alpha with interpolation_stage='rgba' in _Imagebase::_make_image +* :ghpull:`29651`: Backport PR #29650 on branch v3.10.x (Copy-edit "interactive figures & async programming" guide.) +* :ghpull:`29650`: Copy-edit "interactive figures & async programming" guide. +* :ghpull:`29633`: Backport PR #29631 on branch v3.10.x (Add inline notebook to test data) +* :ghpull:`29631`: Add inline notebook to test data +* :ghpull:`29627`: Backport PR #29617 on branch v3.10.x (DOC: Add docstrings to matplotlib.cbook.GrouperView) +* :ghpull:`29617`: DOC: Add docstrings to matplotlib.cbook.GrouperView +* :ghpull:`29625`: Backport PR #29622 on branch v3.10.x (DOC: Move "Infinite lines" example from section "pyplot" to "Lines, bars and markers) +* :ghpull:`29623`: Backport PR #29621 on branch v3.10.x (DOC: Cleanup text rotation in data coordinates example) +* :ghpull:`29619`: Backport PR #29616 on branch v3.10.x (FIX: Fix unit example so that we can unpin numpy<2.1) +* :ghpull:`29616`: FIX: Fix unit example so that we can unpin numpy<2.1 +* :ghpull:`29611`: Backport PR #29608 on branch v3.10.x (Remove md5 usage to prevent issues on FIPS enabled systems (closes #29603)) +* :ghpull:`29608`: Remove md5 usage to prevent issues on FIPS enabled systems (closes #29603) +* :ghpull:`29609`: Backport PR #29607 on branch v3.10.x (Correct doc for axvline arg x which sets x not y) +* :ghpull:`29604`: Backport PR #29601 on branch v3.10.x (DOC: Duplicate categorical values are mapped to the same position) +* :ghpull:`29598`: Backport PR #29597 on branch v3.10.x (Fix typo in deprecation notes for 3.10.0) +* :ghpull:`29591`: Backport PR #29585 on branch v3.10.x (DOC: Document that tight_layout may not converge) +* :ghpull:`29585`: DOC: Document that tight_layout may not converge +* :ghpull:`29587`: Backport PR #25801 on branch v3.10.x (Remove some examples from Userdemo) +* :ghpull:`29577`: Backport PR #29576 on branch v3.10.x (Remove documentation for no-longer existent ContourSet attributes.) +* :ghpull:`29576`: Remove documentation for no-longer existent ContourSet attributes. +* :ghpull:`29530`: Bump the actions group with 5 updates +* :ghpull:`29564`: Backport PR #29563 on branch v3.10.x (DOC: add color sequences reference example) +* :ghpull:`29563`: DOC: add color sequences reference example +* :ghpull:`29557`: Backport PR #29518: TST: Increase tolerance on more arches +* :ghpull:`29555`: Backport PR #29546 on branch v3.10.x (FIX: pyplot.matshow figure handling) +* :ghpull:`29546`: FIX: pyplot.matshow figure handling +* :ghpull:`29518`: TST: Increase tolerance on more arches +* :ghpull:`29547`: Backport PR #29543 on branch v3.10.x (DOC: Minor improvement on broken_barh()) +* :ghpull:`29538`: Backport PR #29536 on branch v3.10.x (Fix typo in solarized example plot.) +* :ghpull:`29531`: Backport PR #29520 on branch v3.10.x (FIX: Correct variable name from _frame to _frames in PillowWriter class) +* :ghpull:`29520`: FIX: Correct variable name from _frame to _frames in PillowWriter class +* :ghpull:`29521`: Backport PR #29509 on branch v3.10.x (MNT: Discourage arrow()) +* :ghpull:`29509`: MNT: Discourage arrow() +* :ghpull:`29514`: Backport PR #29511 on branch v3.10.x (DOC: Document the behavior of bar() for categorical x data) +* :ghpull:`29513`: Backport PR #29471 on branch v3.10.x (Fix subplot docs) +* :ghpull:`29511`: DOC: Document the behavior of bar() for categorical x data +* :ghpull:`29471`: Fix subplot docs +* :ghpull:`29500`: Backport PR #29478 on branch v3.10.x (DOC: Added blurb for colorizer objects in what's new for 3.10) +* :ghpull:`29498`: Backport PR #29488 on branch v3.10.x (DOC: Update broken_barh example) +* :ghpull:`29490`: Backport PR #29476 on branch v3.10.x (ci: Enable native ARM builders for wheels) +* :ghpull:`29476`: ci: Enable native ARM builders for wheels +* :ghpull:`29462`: Backport PR #29404 on branch v3.10.x (DOC: scales - built in options and custom scale usefulness) +* :ghpull:`29459`: Backport PR #29456 on branch v3.10.x (DOC: Fix type descriptions in fill_between docstring) +* :ghpull:`29404`: DOC: scales - built in options and custom scale usefulness +* :ghpull:`29458`: Backport PR #29457 on branch v3.10.x (DOC: Use float instead for scalar for type descriptions in docstrings) +* :ghpull:`29456`: DOC: Fix type descriptions in fill_between docstring +* :ghpull:`29457`: DOC: Use float instead for scalar for type descriptions in docstrings +* :ghpull:`29452`: Backport PR #29411 on branch v3.10.x (fix #29410 Modifying Axes' position also alters the original Bbox object used for initialization) +* :ghpull:`29411`: fix #29410 Modifying Axes' position also alters the original Bbox object used for initialization +* :ghpull:`29451`: Backport PR #29449 on branch v3.10.x (ci: Install libnotify4 on all Ubuntu) +* :ghpull:`29449`: ci: Install libnotify4 on all Ubuntu +* :ghpull:`29444`: Backport PR #29442 on branch v3.10.x (DOC: put section headings in 3.10 what's new) +* :ghpull:`29436`: Backport PR #29407 on branch v3.10.x (DOC: Improve log scale example) +* :ghpull:`29432`: Backport PR #29431 on branch v3.10.x (ft2font: Split named instance count from style flags) +* :ghpull:`29431`: ft2font: Split named instance count from style flags +* :ghpull:`29423`: Backport PR #29130 on branch v3.10.x (Raise warning if both c and facecolors are used in scatter plot (... and related improvements in the test suite).) +* :ghpull:`29420`: Backport PR #29406 on branch v3.10.x (DOC: Update scales overview) +* :ghpull:`29417`: Backport PR #29409 on branch v3.10.x (Fixed test case(test_axes.py) failing on ppc64le) +* :ghpull:`29416`: Backport PR #29382 on branch v3.10.x (Fix title position for polar plots) +* :ghpull:`29382`: Fix title position for polar plots +* :ghpull:`29412`: Backport PR #29363 on branch v3.10.x (FIX: Add version gate to GTK4 calls when necessary) +* :ghpull:`29409`: Fixed test case(test_axes.py) failing on ppc64le +* :ghpull:`29363`: FIX: Add version gate to GTK4 calls when necessary +* :ghpull:`29408`: Backport PR #29401 on branch v3.10.x (FIX: add errorbars with ``add_container``) +* :ghpull:`29401`: FIX: add errorbars with ``add_container`` +* :ghpull:`29130`: Raise warning if both c and facecolors are used in scatter plot (... and related improvements in the test suite). +* :ghpull:`29390`: Backport PR #29389 on branch v3.10.x (DOC: Minor improvements on VPacker, HPacker, PaddedBox docs) +* :ghpull:`29389`: DOC: Minor improvements on VPacker, HPacker, PaddedBox docs +* :ghpull:`29371`: Backport PR #29353 on branch v3.10.x (DOC: Improve module docs of matplotlib.scale) +* :ghpull:`29361`: Backport PR #29355 on branch v3.10.x (Add QtCore.Slot() decorations to FigureCanvasQT) +* :ghpull:`29369`: Backport PR #29362 on branch v3.10.x (TYP: semantics of enums in stub files changed) +* :ghpull:`29353`: DOC: Improve module docs of matplotlib.scale +* :ghpull:`29362`: TYP: semantics of enums in stub files changed +* :ghpull:`29365`: Backport PR #29364 on branch v3.10.x (fix typo) +* :ghpull:`29366`: Backport PR #29347 on branch v3.10.x (DOC: Explain parameters linthresh and linscale of symlog scale) +* :ghpull:`29364`: fix typo +* :ghpull:`29355`: Add QtCore.Slot() decorations to FigureCanvasQT +* :ghpull:`29351`: Backport PR #29348 on branch v3.10.x (DOC: Cleanup scales examples) +* :ghpull:`29336`: Backport PR #29328 on branch v3.10.x (Bump github/codeql-action from 3.27.6 to 3.27.9 in the actions group) +* :ghpull:`29328`: Bump github/codeql-action from 3.27.6 to 3.27.9 in the actions group +* :ghpull:`29330`: Backport PR #29321 on branch v3.10.x (DOC: List min. Python version for Matplotlib 3.10) +* :ghpull:`29324`: Backport PR #29258 on branch v3.10.x (Adding font Size as default parameter) +* :ghpull:`29326`: Backport PR #29323 on branch v3.10.x (DOC: Don't put quotes around coordinate system names) +* :ghpull:`29323`: DOC: Don't put quotes around coordinate system names +* :ghpull:`29258`: Adding font Size as default parameter +* :ghpull:`29320`: Backport PR #29317 on branch v3.10.x (FIX: pass renderer through ``_auto_legend_data``) +* :ghpull:`29317`: FIX: pass renderer through ``_auto_legend_data`` +* :ghpull:`29315`: Backport PR #29314 on branch v3.10.x (DOC: fix footnote in choosing colormaps guide) +* :ghpull:`29309`: Backport PR #29308 on branch v3.10.x (Update cibuildwheel workflow) +* :ghpull:`29310`: Backport PR #29292 on branch v3.10.x (Update dependencies.rst) +* :ghpull:`29308`: Update cibuildwheel workflow -Issues (100): +Issues (14): -* :ghissue:`29298`: [Doc]: The link at "see also" is incorrect. (Axes.violin) -* :ghissue:`29248`: [Bug]: Figure.align_labels() confused by GridSpecFromSubplotSpec -* :ghissue:`26738`: Improve LineCollection docstring further -* :ghissue:`29263`: [Bug]: mypy failures in CI -* :ghissue:`27416`: [Bug]: get_tick_params on xaxis shows wrong keywords -* :ghissue:`29241`: [Bug]: Instructions for setting up conda dev environment in environment.yml give issues with MacOS/zsh -* :ghissue:`29227`: [Bug]: Introductory example on the pyplot API page does not show - missing plt.show() -* :ghissue:`29190`: [Bug]: inconsistent ‘animation.FuncAnimation’ between display and save -* :ghissue:`29090`: [MNT]: More consistent color parameters for bar() -* :ghissue:`29179`: [Bug]: Incorrect pcolormesh when shading='nearest' and only the mesh data C is provided. -* :ghissue:`29067`: [Bug]: ``secondary_xaxis`` produces ticks at incorrect locations -* :ghissue:`29126`: [Bug]: TkAgg backend is broken with tcl/tk 9.0 -* :ghissue:`29045`: [ENH]: implement back/forward buttons on mouse move events on macOS -* :ghissue:`27173`: [Bug]: Gifs no longer create transparent background -* :ghissue:`19229`: Add public API for setting an axis unit converter -* :ghissue:`21108`: [Bug]: Hatch linewidths cannot be modified in an rcParam context -* :ghissue:`27784`: [Bug]: Polar plot error bars don't rotate with angle for ``set_theta_direction`` and ``set_theta_offset`` -* :ghissue:`29011`: [Bug]: Figure.autofmt_xdate() not working in presence of colorbar with constrained layout -* :ghissue:`29020`: AIX internal CI build break #Matplotlib -* :ghissue:`28726`: feature request: support passing DataFrames to table.table -* :ghissue:`28570`: [MNT]: Try improving doc build speed by using PyStemmer -* :ghissue:`13388`: Typo in the figure API (fig.suptitle) -* :ghissue:`28994`: [Bug]: Figure Number Gives Type Error -* :ghissue:`28985`: [ENH]: Cannot disable coordinate display in ToolManager/Toolbar (it's doable in NavigationToolbar2) -* :ghissue:`17914`: ``PathSimplifier`` fails to ignore ``CLOSEPOLY`` vertices -* :ghissue:`28885`: [Bug]: Strange errorbar caps when polar axes have non-default theta direction or theta zero location -* :ghissue:`12418`: replace ttconv for ps/pdf -* :ghissue:`28962`: [Bug]: gtk4 backend does not set guiEvent attribute -* :ghissue:`28408`: [ENH]: mplot3d mouse rotation style -* :ghissue:`28701`: [MNT]: Separate the generation of polygon vertices from ``_fill_between_x_or_y`` -* :ghissue:`28941`: [Bug]: unexplicit error message when using ``matplotlib.colors.rgb_to_hsv()`` with wrong input -* :ghissue:`23846`: [MNT]: Pybind11 transition plan -* :ghissue:`28866`: Possible memory leak in pybind11 migration -* :ghissue:`26368`: [Bug]: Long audio files result in incomplete spectrogram visualizations -* :ghissue:`23826`: [Bug]: Overflow of 16-bit integer in Agg renderer causes PolyCollections to be drawn at incorrect locations -* :ghissue:`28927`: [Bug]: Enforce that Line data modifications are sequences -* :ghissue:`12312`: colorbar(boundaries=...) doesn't work so well with nonlinear norms -* :ghissue:`28800`: [ENH]: AxLine xy1/xy2 setters should take xy as single parameters, (possibly) not separate ones -* :ghissue:`28893`: [Bug]: Lines between points are invisible when there are more than 7 subfigures per row -* :ghissue:`28908`: [Bug]: Possible performance issue with _LazyTickList -* :ghissue:`27971`: [Bug]: ax.xaxis.set_label(...) doesn't set the x-axis label -* :ghissue:`28059`: [Bug]: pcolorfast should validate that regularly spaced X or Y inputs have the right size -* :ghissue:`28892`: [Doc]: Be more specific on dependencies that need to be installed for a "reasonable" dev environment -* :ghissue:`19693`: path.sketch doesn't apply to PolyCollection -* :ghissue:`28873`: [Bug]: hist()'s doc for edgecolors/facecolors does not match behavior (which is itself not very consistent) -* :ghissue:`23005`: [Doc]: Add figure to ``subplots_adjust`` -* :ghissue:`25947`: [Doc]: Subfigures still marked as provisional -* :ghissue:`26012`: [Bug]: "Unhashable type" when event callback is a method of a ``dict`` subclass -* :ghissue:`23425`: [Bug]: Axes.indicate_inset connectors affect constrained layout -* :ghissue:`23424`: [Bug]: Axes.indicate_inset(linewidth=...) doesn't affect connectors -* :ghissue:`19768`: Overlay created by ``Axes.indicate_inset_zoom`` does not adjust when changing inset ranges -* :ghissue:`27673`: [Doc]: Confusing page on color changes -* :ghissue:`28782`: [Bug]: String ``contour(colors)`` gives confusing error when ``extend`` used -* :ghissue:`27930`: [ENH]: Make axes_grid1.Size more math friendly. -* :ghissue:`28372`: [Bug]: AffineDeltaTransform does not appear to invalidate properly -* :ghissue:`27866`: [Bug]: Adding suptitle in compressed layout causes weird spacing -* :ghissue:`28731`: [Bug]: Plotting numpy.array of dtype float32 with pyplot.imshow and specified colors.LogNorm produces wrong colors -* :ghissue:`28715`: [Bug]: CI doc builds fail since a couple of days -* :ghissue:`28698`: [bug]: arrowstyle doc interpolation in FancyPatch.set_arrow() -* :ghissue:`28669`: [Bug]: division-by-zero error in Sketch::Sketch with Agg backend -* :ghissue:`28548`: [Doc]: matplotlib.pyplot.specgram parameters vmin and vmax are not documented -* :ghissue:`28165`: [Bug]: PolygonSelector should hide itself when zoom/pan is active -* :ghissue:`18608`: Feature proposal: "Dark mode" divergent colormaps -* :ghissue:`28623`: [Bug]: ``Axis.set_in_layout`` not respected? -* :ghissue:`6305`: Matplotlib 3D plot - parametric curve “wraparound” from certain perspectives -* :ghissue:`28595`: [Bug]: set_url without effect for instances of Line2D with linestyle 'none' -* :ghissue:`20910`: [Bug]: Exported SVG files are no longer imported Affinity Designer correctly -* :ghissue:`28600`: [TST] Upcoming dependency test failures -* :ghissue:`26718`: [Bug]: stacked histogram does not properly handle edgecolor and hatches -* :ghissue:`28590`: [ENH]: Geo Projections support for inverting axis -* :ghissue:`27954`: [ENH]: Iterables in grouped histogram labels -* :ghissue:`27878`: [ENH]: AttributeError('... got an unexpected keyword argument ...') should set the .name attribute to the keyword -* :ghissue:`28489`: [TST] Upcoming dependency test failures -* :ghissue:`28343`: [Bug]: inconsistent colorbar pad for ``ImageGrid`` with ``cbar_mode="single"`` -* :ghissue:`28535`: [ENH]: Add id attribute to top level svg tag -* :ghissue:`28170`: [Doc]: ``get_figure`` may return a ``SubFigure`` -* :ghissue:`27831`: [Bug]: Nondeterminism in SVG clipPath element id attributes -* :ghissue:`4568`: Add ``fmt_r`` and ``fmt_theta`` methods to polar axes -* :ghissue:`28105`: [Bug]: Setting norm by string doesn't work for hexbin -* :ghissue:`28142`: [ENH]: Add fill between support for 3D plots -* :ghissue:`28344`: [Bug]: subfigures are added in column major order -* :ghissue:`28212`: [Bug]: Matplotlib not work with MiKTeX. -* :ghissue:`28288`: [ENH]: Natural 3D rotation with mouse -* :ghissue:`28180`: [Bug]: mathtext should distinguish between unary and binary minus -* :ghissue:`26150`: [Bug]: Savefig slow with subplots -* :ghissue:`28310`: [Bug]: orientation indication shows up late in mplot3d, and then lingers -* :ghissue:`16263`: Apply NEP29 (time-limited support) to IPython -* :ghissue:`28192`: [MNT]: Essential build requirements not included in dev-requirements -* :ghissue:`27978`: [Bug]: strange behaviour when redefining figure size -* :ghissue:`13435`: boxplot/violinplot orientation-setting API -* :ghissue:`28199`: [MNT]: Misleading function name ``Poly3DCollection.get_vector()`` -* :ghissue:`26892`: [Bug]: PGF font size mismatch between measurement and output -* :ghissue:`28016`: [Bug]: Unexpected ylim of stairs with baseline=None -* :ghissue:`28114`: [Bug]: mpl.colormaps[ "Grays" ].name is "Greys", not "Grays" -* :ghissue:`18045`: Cannot access hexbin data when ``xscale='log'`` and ``yscale='log'`` are set. -* :ghissue:`27820`: [Bug]: Logscale Axis + NonUniformImage + GUI move tool = Distortion -* :ghissue:`28047`: [Bug]: plt.barbs is a command that cannot be passed in a c parameter by parameter name, but can be passed in the form of a positional parameter -* :ghissue:`23400`: Only upload failed images on failure -* :ghissue:`26752`: [Bug]: ``ax.stairs()`` creates inaccurate ``fill`` for the plot -* :ghissue:`21817`: [Doc/Dev]: style guide claims "object oriented" is verboten. +* :ghissue:`28382`: [Bug]: interpolation_stage="rgba" does not respect array-alpha +* :ghissue:`28780`: Doc build fails with numpy>=2.1.0 +* :ghissue:`29603`: [Bug]: Setting ``text.usetex=True`` in ``pyplot.rcParams`` Raises FIPS Compliance Errors +* :ghissue:`29575`: [Doc]: QuadContourSet does not contain a collections attribute like stated in the manual +* :ghissue:`29519`: [Bug]: 'PillowWriter' object has no attribute '_frame' shouldn't be '_frames'? +* :ghissue:`29507`: [Bug]: Duplicating the labels in the ``height``/``width`` argument in ``barh()``/``bar`` leads to undrawn bars +* :ghissue:`29447`: [Doc]: ``subplot`` behavior is not same as the doc reads in 3.10(stable) +* :ghissue:`29410`: [Bug]: Modifying Axes' position also alters the original Bbox object used for initialization +* :ghissue:`29396`: [Bug]: Style flag errors trying to save figures as PDF with font Inter +* :ghissue:`29381`: [Bug]: title position incorrect for polar plot +* :ghissue:`29350`: [Bug]: Matplotlib causes segmentation fault when hovering mouse over graph +* :ghissue:`25274`: [Bug]: .remove() on ErrorbarContainer object does not remove the corresponding item from the legend +* :ghissue:`29202`: [Bug]: ``fontsize`` in tables not working +* :ghissue:`29301`: [Bug]: Blank EPS output with legend and annotate Previous GitHub statistics diff --git a/doc/users/prev_whats_new/github_stats_3.10.0.rst b/doc/users/prev_whats_new/github_stats_3.10.0.rst new file mode 100644 index 000000000000..01b54708b7ec --- /dev/null +++ b/doc/users/prev_whats_new/github_stats_3.10.0.rst @@ -0,0 +1,587 @@ +.. _github-stats-3_10_0: + +GitHub statistics for 3.10.0 (Dec 13, 2024) +=========================================== + +GitHub statistics for 2024/05/15 (tag: v3.9.0) - 2024/12/13 + +These lists are automatically generated, and may be incomplete or contain duplicates. + +We closed 100 issues and merged 337 pull requests. +The full list can be seen `on GitHub `__ + +The following 128 authors contributed 1932 commits. + +* abhi-jha +* Adam J. Stewart +* Aditi Gautam +* Aditya Vidyadhar Kamath +* Aishling Cooke +* Alan +* Alan Sosa +* Alice +* Aman Nijjar +* Ammar Qazi +* Ancheng +* anpaulan +* Anson0028 +* Anthony Lee +* anTon +* Antony Lee +* Ayoub Gouasmi +* Brigitta Sipőcz +* Caitlin Hathaway +* cesar +* Charlie LeWarne +* Christian Mattsson +* ClarkeAC +* Clemens Brunner +* Clement Gilli +* cmp0xff +* Costa Paraskevopoulos +* dale +* Dani Pinyol +* Daniel Weiss +* Danny +* David Bakaj +* David Lowry-Duda +* David Meyer +* David Stansby +* dbakaj +* dependabot[bot] +* Diogo Cardoso +* Doron Behar +* Edgar Andrés Margffoy Tuay +* Elliott Sales de Andrade +* Eytan Adler +* farquh +* Felipe Cybis Pereira +* Filippo Balzaretti +* FMasson +* Francisco Cardozo +* Gavin S +* Greg Lucas +* haaris +* hannah +* Ian Thomas +* Illviljan +* James Addison +* James Spencer +* Jody Klymak +* john +* Jonas Eschle +* Jouni K. Seppänen +* juanis2112 +* Juanita Gomez +* Justin Hendrick +* K900 +* Kaustbh +* Kaustubh +* Kherim Willems +* Kyle Sunden +* Kyra Cho +* Larry Bradley +* litchi +* Lorenzo +* Lucx33 +* Lumberbot (aka Jack) +* MadPhysicist +* malhar2460 +* Martino Sorbaro +* Mathias Hauser +* Matthew Feickert +* Matthew Petroff +* Melissa Weber Mendonça +* Michael +* Michael Droettboom +* Michael Hinton +* MischaMegens2 +* Moritz Wolter +* muchojp +* Nabil +* nakamura yuki +* odile +* OdileVidrine +* Oscar Gustafsson +* Panicks28 +* Paul An +* Pedro Barão +* PedroBittarBarao +* Peter Talley +* Pierre-antoine Comby +* Pranav +* Pranav Raghu +* pre-commit-ci[bot] +* proximalf +* r3kste +* Randolf Scholz +* Refael Ackermann +* RickyP24 +* rnhmjoj +* Ruth Comer +* Ryan May +* Sai Chaitanya, Sanivada +* saranti +* scaccol +* Scott Shambaugh +* Sean Smith +* Simon May +* simond07 +* smcgrawDotNet +* Takumasa N +* Takumasa N. +* Takumasa Nakamura +* thiagoluisbecker +* Thomas A Caswell +* Tiago Lubiana +* Tim Hoffmann +* trananso +* Trygve Magnus Ræder +* Victor Liu +* vittoboa +* Xeniya Shoiko + +GitHub issues and pull requests: + +Pull Requests (337): + +* :ghpull:`29299`: Merge v3.9.x into v3.10.x +* :ghpull:`29296`: Backport PR #29295 on branch v3.10.x (BLD: Pin meson-python to <0.17.0) +* :ghpull:`29290`: Backport PR #29254 on branch v3.10.x (DOC: Add note to align_labels()) +* :ghpull:`29289`: Backport PR #29260 on branch v3.10.x (DOC: Better explanation of rcParams "patch.edgecolor" and "patch.force_edgecolor") +* :ghpull:`29288`: Backport PR #29285 on branch v3.10.x (Retarget PR#29175 to main) +* :ghpull:`29254`: DOC: Add note to align_labels() +* :ghpull:`29260`: DOC: Better explanation of rcParams "patch.edgecolor" and "patch.force_edgecolor" +* :ghpull:`29285`: Retarget PR#29175 to main +* :ghpull:`29286`: Backport PR #29274 on branch v3.10.x (Bump the actions group across 1 directory with 2 updates) +* :ghpull:`29274`: Bump the actions group across 1 directory with 2 updates +* :ghpull:`29283`: Backport PR #29272 on branch v3.10.x (DOC: Add section on translating between Axes and pyplot interface) +* :ghpull:`29272`: DOC: Add section on translating between Axes and pyplot interface +* :ghpull:`29279`: Backport PR #29265 on branch v3.10.x (DOC: Slightly improve the LineCollection docstring) +* :ghpull:`29276`: Backport PR #29247 on branch v3.10.x (Fix building freetype 2.6.1 on macOS clang 18) +* :ghpull:`29244`: Switch to a 3d rotation trackball implementation with path independence +* :ghpull:`29265`: DOC: Slightly improve the LineCollection docstring +* :ghpull:`29247`: Fix building freetype 2.6.1 on macOS clang 18 +* :ghpull:`29268`: Bump the actions group with 2 updates +* :ghpull:`29266`: Backport PR #29251 on branch v3.10.x (Zizmor audit) +* :ghpull:`29269`: Backport PR #29267 on branch v3.10.x (Exclude pylab from mypy checks) +* :ghpull:`29267`: Exclude pylab from mypy checks +* :ghpull:`29251`: Zizmor audit +* :ghpull:`29255`: Backport PR #29249 on branch v3.10.x ([Bug Fix] Fix reverse mapping for _translate_tick_params) +* :ghpull:`29249`: [Bug Fix] Fix reverse mapping for _translate_tick_params +* :ghpull:`29250`: Backport PR #29243 on branch v3.10.x (Add quotes around [dev] in environment.yml) +* :ghpull:`29243`: Add quotes around [dev] in environment.yml +* :ghpull:`29246`: Backport PR #29240 on branch v3.10.x (DOC: Add plt.show() to introductory pyplot example) +* :ghpull:`29240`: DOC: Add plt.show() to introductory pyplot example +* :ghpull:`29239`: Backport PR #29236 on branch v3.10.x (ANI: Reduce Pillow frames to RGB when opaque) +* :ghpull:`29238`: Backport PR #29167 on branch v3.10.x (BUGFIX: use axes unit information in ConnectionPatch ) +* :ghpull:`29236`: ANI: Reduce Pillow frames to RGB when opaque +* :ghpull:`29167`: BUGFIX: use axes unit information in ConnectionPatch +* :ghpull:`29232`: Merge branch v3.9.x into v3.10.x +* :ghpull:`29230`: Backport PR #29188 on branch v3.10.x (Bump pypa/cibuildwheel from 2.21.3 to 2.22.0 in the actions group) +* :ghpull:`29188`: Bump pypa/cibuildwheel from 2.21.3 to 2.22.0 in the actions group +* :ghpull:`29225`: Backport PR #29213 on branch v3.10.x (avoid-unnecessary-warning-in-_pcolorargs-function) +* :ghpull:`29211`: Backport PR #29133 on branch v3.10.x (Creating_parse_bar_color_args to unify color handling in plt.bar with precedence and sequence support for facecolor and edgecolor) +* :ghpull:`29177`: Backport PR #29148 on branch v3.10.x (Don't fail on equal-but-differently-named cmaps in qt figureoptions.) +* :ghpull:`29226`: Backport PR #29206 on branch v3.10.x (Skip more tests on pure-Wayland systems) +* :ghpull:`29206`: Skip more tests on pure-Wayland systems +* :ghpull:`29213`: avoid-unnecessary-warning-in-_pcolorargs-function +* :ghpull:`29210`: Backport PR #29209 on branch v3.10.x (FIX: pcolormesh with no x y args and nearest interp) +* :ghpull:`29133`: Creating_parse_bar_color_args to unify color handling in plt.bar with precedence and sequence support for facecolor and edgecolor +* :ghpull:`29209`: FIX: pcolormesh with no x y args and nearest interp +* :ghpull:`29200`: Backport PR #29182 on branch v3.10.x (Update backend_qt.py: parent not passed to __init__ on subplottool) +* :ghpull:`29207`: Backport PR #29169 on branch v3.10.x (Minor fixes to text intro explainer) +* :ghpull:`29169`: Minor fixes to text intro explainer +* :ghpull:`29159`: Pending warning for deprecated parameter 'vert' of box and violin on 3.10 +* :ghpull:`29196`: Backport PR #29191 on branch v3.10.x (ci: Simplify 3.13t test setup) +* :ghpull:`29182`: Update backend_qt.py: parent not passed to __init__ on subplottool +* :ghpull:`29189`: Backport PR #28934 on branch v3.10.x (ci: Unpin micromamba again) +* :ghpull:`29186`: Backport PR #28335 on branch v3.10.x (DOC: do not posting LLM output as your own work) +* :ghpull:`28934`: ci: Unpin micromamba again +* :ghpull:`28335`: DOC: do not posting LLM output as your own work +* :ghpull:`29178`: Backport PR #29163 on branch v3.9.x (ci: Remove outdated pkg-config package on macOS) +* :ghpull:`29170`: Backport PR #29154 on branch v3.10.x (Relax conditions for warning on updating converters) +* :ghpull:`29154`: Relax conditions for warning on updating converters +* :ghpull:`29166`: Backport PR #29153 on branch v3.10.x (Bump codecov/codecov-action from 4 to 5 in the actions group) +* :ghpull:`29164`: Backport PR #29163 on branch v3.10.x (ci: Remove outdated pkg-config package on macOS) +* :ghpull:`29168`: Backport PR #29073 on branch v3.10.x (Update secondary_axis tutorial) +* :ghpull:`29073`: Update secondary_axis tutorial +* :ghpull:`29163`: ci: Remove outdated pkg-config package on macOS +* :ghpull:`29145`: Backport PR #29144 on branch v3.10.x (Use both TCL_SETVAR and TCL_SETVAR2 for tcl 9 support) +* :ghpull:`29144`: Use both TCL_SETVAR and TCL_SETVAR2 for tcl 9 support +* :ghpull:`29140`: Backport PR #29080 on branch v3.10.x (Updates the ``galleries/tutorials/artists.py`` file in response to issue #28920) +* :ghpull:`29080`: Updates the ``galleries/tutorials/artists.py`` file in response to issue #28920 +* :ghpull:`29138`: Backport PR #29134 on branch v3.10.x (MNT: Temporarily skip failing test to unbreak CI) +* :ghpull:`29134`: MNT: Temporarily skip failing test to unbreak CI +* :ghpull:`29132`: Backport PR #29128 on branch v3.10.x (Tweak AutoMinorLocator docstring.) +* :ghpull:`29128`: Tweak AutoMinorLocator docstring. +* :ghpull:`29123`: Bump the actions group with 2 updates +* :ghpull:`29122`: Backport PR #29120 on branch v3.10.x (DOC: Switch nested pie example from cmaps to color_sequences) +* :ghpull:`29100`: Backport PR #29099 on branch v3.10.x (MNT: remove _ttconv.pyi) +* :ghpull:`29099`: MNT: remove _ttconv.pyi +* :ghpull:`29098`: Backport PR #29097 on branch v3.10.x (ENH: add back/forward buttons to osx backend move) +* :ghpull:`29097`: ENH: add back/forward buttons to osx backend move +* :ghpull:`29095`: Backport PR #29071 on branch v3.10.x (Bump pypa/gh-action-pypi-publish from 1.10.3 to 1.11.0 in the actions group) +* :ghpull:`29096`: Backport PR #29094 on branch v3.10.x (DOC: fix link in See Also section of axes.violin) +* :ghpull:`29092`: Backport PR #29088 on branch v3.10.x (DOC: Format aliases in kwargs tables) +* :ghpull:`29094`: DOC: fix link in See Also section of axes.violin +* :ghpull:`29091`: Backport PR #29085 on branch v3.10.x (FIX: Update GTK3Agg backend export name for consistency) +* :ghpull:`29088`: DOC: Format aliases in kwargs tables +* :ghpull:`29089`: Backport PR #29065 on branch v3.10.x (DOC: Update docstring of triplot()) +* :ghpull:`29085`: FIX: Update GTK3Agg backend export name for consistency +* :ghpull:`29084`: Backport PR #29081 on branch v3.10.x (Document "none" as color value) +* :ghpull:`29065`: DOC: Update docstring of triplot() +* :ghpull:`29081`: Document "none" as color value +* :ghpull:`29061`: Backport PR #29024 on branch v3.10.x (Fix saving animations to transparent formats) +* :ghpull:`29069`: Backport PR #29068 on branch v3.10.x ([DOC] Fix indentation in sync_cmaps example) +* :ghpull:`29070`: Backport PR #29048 on branch v3.10.x (DOC: integrated pr workflow from contributing guide into install and workflow) +* :ghpull:`29048`: DOC: integrated pr workflow from contributing guide into install and workflow +* :ghpull:`29068`: [DOC] Fix indentation in sync_cmaps example +* :ghpull:`29024`: Fix saving animations to transparent formats +* :ghpull:`29059`: Cleanup converter docs and StrCategoryConverter behavior +* :ghpull:`29058`: [DOC] Update missing-references.json +* :ghpull:`29057`: DOC/TST: lock numpy<2.1 in environment.yml +* :ghpull:`29053`: Factor out common formats strings in LogFormatter, LogFormatterExponent. +* :ghpull:`28970`: Add explicit converter setting to Axis +* :ghpull:`28048`: Enables setting hatch linewidth in Patches and Collections, also fixes setting hatch linewidth by rcParams +* :ghpull:`29017`: DOC: Document preferred figure size for examples +* :ghpull:`28871`: updated contribution doc #28476 +* :ghpull:`28453`: Stop relying on dead-reckoning mouse buttons for motion_notify_event. +* :ghpull:`28495`: ticker.EngFormatter: allow offset +* :ghpull:`29039`: MNT: Add provisional get_backend(resolve=False) flag +* :ghpull:`28946`: MNT: Deprecate plt.polar() with an existing non-polar Axes +* :ghpull:`29013`: FIX: auto_fmtxdate for constrained layout +* :ghpull:`29022`: Fixes AIX internal CI build break. +* :ghpull:`28830`: Feature: Support passing DataFrames to table.table +* :ghpull:`27766`: Return filename from save_figure +* :ghpull:`27167`: ENH: add long_axis property to colorbar +* :ghpull:`29021`: Update minimum pybind11 to 2.13.2 +* :ghpull:`28863`: Improved documentation for quiver +* :ghpull:`29019`: Update requirements to add PyStemmer to doc-requirements and environment +* :ghpull:`28653`: Mnt/generalize plot varargs +* :ghpull:`28967`: Fix MSVC cast warnings +* :ghpull:`29016`: DOC: Better explain suptitle / supxlabel / supylabel naming +* :ghpull:`28842`: FT2Font extension improvements +* :ghpull:`28658`: New data → color pipeline +* :ghpull:`29012`: Bump required pybind11 to 2.13 +* :ghpull:`29007`: MNT: Deprecate changing Figure.number +* :ghpull:`28861`: Break Artist._remove_method reference cycle +* :ghpull:`28478`: bugfix for ``PathSimplifier`` +* :ghpull:`28992`: DOC: Refresh transform tree example +* :ghpull:`28890`: MNT: Add missing dependency to environment.yml +* :ghpull:`28354`: Add Quiverkey zorder option +* :ghpull:`28966`: Fix polar error bar cap orientation +* :ghpull:`28819`: Mark all extensions as free-threading safe +* :ghpull:`28986`: DOC: Add tags for 3D fill_between examples +* :ghpull:`28984`: DOC / BUG: Better example for 3D axlim_clip argument +* :ghpull:`20866`: Remove ttconv and implement Type-42 embedding using fontTools +* :ghpull:`28975`: Set guiEvent where applicable for gtk4. +* :ghpull:`28568`: added tags to mplot3d examples +* :ghpull:`28976`: Bump pypa/cibuildwheel from 2.21.2 to 2.21.3 in the actions group +* :ghpull:`28978`: CI: Resolve mypy stubtest build errors +* :ghpull:`28823`: Fix 3D rotation precession +* :ghpull:`28841`: Make mplot3d mouse rotation style adjustable +* :ghpull:`28971`: DOC: correct linestyle example and reference rcParams +* :ghpull:`28702`: [MNT]: #28701 separate the generation of polygon vertices in fill_between to enable resampling +* :ghpull:`28965`: Suggest imageio_ffmpeg to provide ffmpeg as animation writer. +* :ghpull:`28964`: FIX macos: Use the agg buffer_rgba rather than private attribute +* :ghpull:`28963`: Remove refs to outdated writers in animation.py. +* :ghpull:`28948`: Raise ValueError for RGB values outside the [0, 1] range in rgb_to_hsv function +* :ghpull:`28857`: Pybind11 cleanup +* :ghpull:`28949`: [pre-commit.ci] pre-commit autoupdate +* :ghpull:`28950`: Bump the actions group with 2 updates +* :ghpull:`28904`: Agg: Remove 16-bit limits +* :ghpull:`28856`: Convert remaining code to pybind11 +* :ghpull:`28874`: Remove remaining 3.8 deprecations +* :ghpull:`28943`: DOC: Clarify the returned line of axhline()/axvline() +* :ghpull:`28935`: DOC: Fix invalid rcParam references +* :ghpull:`28942`: In colorbar docs, add ref from 'boundaries' doc to 'spacing' doc. +* :ghpull:`28933`: Switch AxLine.set_xy{1,2} to take a single argument. +* :ghpull:`28869`: ci: Bump build image on AppVeyor to MSVC 2019 +* :ghpull:`28906`: Re-fix exception caching in dviread. +* :ghpull:`27349`: [ENH] Implement dynamic clipping to axes limits for 3D plots +* :ghpull:`28913`: DOC: Fix Axis.set_label reference +* :ghpull:`28911`: MNT: Fix double evaluation of _LazyTickList +* :ghpull:`28584`: MNT: Prevent users from erroneously using legend label API on Axis +* :ghpull:`28853`: MNT: Check the input sizes of regular X,Y in pcolorfast +* :ghpull:`28838`: TST: Fix minor issues in interactive backend test +* :ghpull:`28795`: MNT: Cleanup docstring substitution mechanisms +* :ghpull:`28897`: Fix minor issues in stubtest wrapper +* :ghpull:`28899`: Don't cache exception with traceback reference loop in dviread. +* :ghpull:`28888`: DOC: Better visualization for the default color cycle example +* :ghpull:`28896`: doc: specify non-python dependencies in dev install docs +* :ghpull:`28843`: MNT: Cleanup FontProperties __init__ API +* :ghpull:`28683`: MNT: Warn if fixed aspect overwrites explicitly set data limits +* :ghpull:`25645`: Fix issue with sketch not working on PathCollection in Agg +* :ghpull:`28886`: DOC: Cross-link Axes attributes +* :ghpull:`28880`: Remove 'in' from removal substitution for deprecation messages +* :ghpull:`28875`: DOC: Fix documentation of hist() kwarg lists +* :ghpull:`28825`: DOC: Fix non-working code object references +* :ghpull:`28862`: Improve pie chart error messages +* :ghpull:`28844`: DOC: Add illustration to Figure.subplots_adjust +* :ghpull:`28588`: Fix scaling in Tk on non-Windows systems +* :ghpull:`28849`: DOC: Mark subfigures as no longer provisional +* :ghpull:`26000`: making onselect a keyword argument on selectors +* :ghpull:`26013`: Support unhashable callbacks in CallbackRegistry +* :ghpull:`27011`: Convert Agg extension to pybind11 +* :ghpull:`28845`: In examples, prefer named locations rather than location numbers. +* :ghpull:`27218`: API: finish LocationEvent.lastevent removal +* :ghpull:`26870`: Removed the deprecated code from axis.py +* :ghpull:`27996`: Create ``InsetIndicator`` artist +* :ghpull:`28532`: TYP: Fix xycoords and friends +* :ghpull:`28785`: Convert ft2font extension to pybind11 +* :ghpull:`28815`: DOC: Document policy on colormaps and styles +* :ghpull:`28826`: MNT: Replace _docstring.dedent_interpd by its alias _docstring.interpd +* :ghpull:`27567`: DOC: batch of tags +* :ghpull:`27302`: Tags for simple_scatter.py demo +* :ghpull:`28820`: DOC: Fix missing cross-reference checks for sphinx-tags +* :ghpull:`28786`: Handle single color in ContourSet +* :ghpull:`28808`: DOC: Add a plot to margins() to visualize the effect +* :ghpull:`27938`: feat: add dunder method for math operations on Axes Size divider +* :ghpull:`28569`: Adding tags to many examples +* :ghpull:`28183`: Expire deprecations +* :ghpull:`28801`: DOC: Clarify AxLine.set_xy2 / AxLine.set_slope +* :ghpull:`28788`: TST: Skip webp tests if it isn't available +* :ghpull:`28550`: Remove internal use of ``Artist.figure`` +* :ghpull:`28767`: MNT: expire ``ContourSet`` deprecations +* :ghpull:`28755`: TYP: Add typing for internal _tri extension +* :ghpull:`28765`: Add tests for most of FT2Font, and fix some bugs +* :ghpull:`28781`: TST: Fix test_pickle_load_from_subprocess in a dirty tree +* :ghpull:`28783`: Fix places where "auto" was not listed as valid interpolation_stage. +* :ghpull:`28779`: DOC/TST: lock numpy < 2.1 +* :ghpull:`28771`: Ensure SketchParams is always fully initialized +* :ghpull:`28375`: FIX: Made AffineDeltaTransform pass-through properly +* :ghpull:`28454`: MultivarColormap and BivarColormap +* :ghpull:`27891`: Refactor some parts of ft2font extension +* :ghpull:`28752`: quick fix dev build by locking out numpy version that's breaking things +* :ghpull:`28749`: Add sphinxcontrib-video to environment.yml +* :ghpull:`27851`: Add ten-color accessible color cycle as style sheet +* :ghpull:`28501`: ConciseDateFormatter's offset string is correct on an inverted axis +* :ghpull:`28734`: Compressed layout moves suptitle +* :ghpull:`28736`: Simplify some code in dviread +* :ghpull:`28347`: Doc: added triage section to new contributor docs +* :ghpull:`28735`: ci: Avoid setuptools 72.2.0 when installing kiwi on PyPy +* :ghpull:`28728`: MNT: Deprecate reimported functions in top-level namespace +* :ghpull:`28730`: MNT: Don't rely on RcParams being a dict subclass in internal code +* :ghpull:`28714`: Simplify _api.warn_external on Python 3.12+ +* :ghpull:`28727`: MNT: Better workaround for format_cursor_data on ScalarMappables +* :ghpull:`28725`: Stop disabling FH4 Exception Handling on MSVC +* :ghpull:`28711`: Merge branch v3.9.x into main +* :ghpull:`28713`: DOC: Add a few more notes to release guide +* :ghpull:`28720`: DOC: Clarify axhline() uses axes coordinates +* :ghpull:`28718`: DOC: Update missing references for numpydoc 1.8.0 +* :ghpull:`28710`: DOC: clarify alpha handling for indicate_inset[_zoom] +* :ghpull:`28704`: Fixed arrowstyle doc interpolation in FancyPatch.set_arrow() #28698. +* :ghpull:`28709`: Bump actions/attest-build-provenance from 1.4.0 to 1.4.1 in the actions group +* :ghpull:`28707`: Avoid division-by-zero in Sketch::Sketch +* :ghpull:`28610`: CI: Add CI to test matplotlib against free-threaded Python +* :ghpull:`28262`: Fix PolygonSelector cursor to temporarily hide during active zoom/pan +* :ghpull:`28670`: API: deprecate unused helper in patch._Styles +* :ghpull:`28589`: Qt embedding example: Separate drawing and data retrieval timers +* :ghpull:`28655`: Inline annotation and PGF user demos +* :ghpull:`28654`: DOC: Remove long uninstructive examples +* :ghpull:`28652`: Fix docstring style inconsistencies in lines.py +* :ghpull:`28641`: DOC: Standardize example titles - part 2 +* :ghpull:`28642`: DOC: Simplify heatmap example +* :ghpull:`28638`: DOC: Remove hint on PRs from origin/main +* :ghpull:`28587`: Added dark-mode diverging colormaps +* :ghpull:`28546`: DOC: Clarify/simplify example of multiple images with one colorbar +* :ghpull:`28613`: Added documentation for parameters vmin and vmax inside specgram function. +* :ghpull:`28627`: DOC: Bump minimum Sphinx to 5.1.0 +* :ghpull:`28628`: DOC: Sub-structure next API changes overview +* :ghpull:`28629`: FIX: ``Axis.set_in_layout`` respected +* :ghpull:`28575`: Add branch tracking to development workflow instructions +* :ghpull:`28616`: CI: Build docs on latest Python +* :ghpull:`28617`: DOC: Enable parallel builds +* :ghpull:`28544`: DOC: Standardize example titles +* :ghpull:`28615`: DOC: hack to suppress sphinx-gallery 17.0 warning +* :ghpull:`28293`: BLD: Enable building Python 3.13 wheels for nightlies +* :ghpull:`27385`: Fix 3D lines being visible when behind camera +* :ghpull:`28609`: svg: Ensure marker-only lines get URLs +* :ghpull:`28599`: Upgrade code to Python 3.10 +* :ghpull:`28593`: Update ruff to 0.2.0 +* :ghpull:`28603`: Simplify ttconv python<->C++ conversion using std::optional. +* :ghpull:`28557`: DOC: apply toc styling to remove nesting +* :ghpull:`28542`: CI: adjust pins in mypy GHA job +* :ghpull:`28504`: Changes in SVG backend to improve compatibility with Affinity designer +* :ghpull:`28122`: Disable clipping in Agg resamplers. +* :ghpull:`28597`: Pin PyQt6 back on Ubuntu 20.04 +* :ghpull:`28073`: Add support for multiple hatches, edgecolors and linewidths in histograms +* :ghpull:`28594`: MNT: Raise on GeoAxes limits manipulation +* :ghpull:`28312`: Remove one indirection layer in ToolSetCursor. +* :ghpull:`28573`: ENH: include property name in artist AttributeError +* :ghpull:`28503`: Bump minimum Python to 3.10 +* :ghpull:`28525`: FIX: colorbar pad for ``ImageGrid`` +* :ghpull:`28558`: DOC: Change _make_image signature to numpydoc +* :ghpull:`28061`: API: add antialiased to interpolation-stage in image +* :ghpull:`28536`: [svg] Add rcParam["svg.id"] to add a top-level id attribute to +* :ghpull:`28540`: Subfigures become stale when their artists are stale +* :ghpull:`28177`: Rationalise artist get_figure methods; make figure attribute a property +* :ghpull:`28527`: DOC: improve tagging guidelines page +* :ghpull:`28530`: DOC: Simplify axhspan example +* :ghpull:`28537`: DOC: Update timeline example for newer releases +* :ghpull:`27833`: [SVG] Introduce sequential ID-generation scheme for clip-paths. +* :ghpull:`28512`: DOC: Fix version switcher for stable docs +* :ghpull:`28492`: MNT: Remove PolyQuadMesh deprecations +* :ghpull:`28509`: CI: Use micromamba on AppVeyor +* :ghpull:`28510`: Merge v3.9.1 release into main +* :ghpull:`28494`: [pre-commit.ci] pre-commit autoupdate +* :ghpull:`28497`: Add words to ignore for codespell +* :ghpull:`28455`: Expand ticklabels_rotation example to cover rotating default ticklabels. +* :ghpull:`28282`: DOC: clarify no-build-isolation & mypy ignoring new functions +* :ghpull:`28306`: Fixed PolarAxes not using fmt_xdata and added simple test (#4568) +* :ghpull:`28400`: DOC: Improve doc wording of data parameter +* :ghpull:`28225`: [ENH]: fill_between extended to 3D +* :ghpull:`28371`: Bump pypa/cibuildwheel from 2.18.1 to 2.19.0 in the actions group +* :ghpull:`28390`: Inline RendererBase._get_text_path_transform. +* :ghpull:`28381`: Take hinting rcParam into account in MathTextParser cache. +* :ghpull:`28363`: flip subfigures axes to match subplots +* :ghpull:`28340`: Fix missing font error when using MiKTeX +* :ghpull:`28379`: PathEffectsRenderer can plainly inherit RendererBase._draw_text_as_path. +* :ghpull:`28275`: Revive sanitizing default filenames extracted from UI window titles +* :ghpull:`28360`: DOC: fixed code for testing check figures equal example +* :ghpull:`28370`: Reorder Axes3D parameters semantically. +* :ghpull:`28350`: Typo in communication guide: extensiblity -> extensibility +* :ghpull:`28290`: Introduce natural 3D rotation with mouse +* :ghpull:`28186`: apply unary minus spacing directly after equals sign +* :ghpull:`28311`: Update 3D orientation indication right away +* :ghpull:`28300`: Faster title alignment +* :ghpull:`28313`: Factor out handling of missing spines in alignment calculations. +* :ghpull:`28196`: TST: add timeouts to font_manager + threading test +* :ghpull:`28279`: Doc/ipython dep +* :ghpull:`28091`: [MNT]: create build-requirements.txt and update dev-requirements.txt +* :ghpull:`27992`: Add warning for multiple pyplot.figure calls with same ID +* :ghpull:`28238`: DOC: Update release guide to match current automations +* :ghpull:`28232`: Merge v3.9.0 release into main +* :ghpull:`28228`: DOC: Fix typo in release_guide.rst +* :ghpull:`28074`: Add ``orientation`` parameter to Boxplot and deprecate ``vert`` +* :ghpull:`27998`: Add a new ``orientation`` parameter to Violinplot and deprecate ``vert`` +* :ghpull:`28217`: Better group logging of font handling by texmanager. +* :ghpull:`28130`: Clarify the role of out_mask and out_alpha in _make_image. +* :ghpull:`28201`: Deprecate ``Poly3DCollection.get_vector`` +* :ghpull:`28046`: DOC: Clarify merge policy +* :ghpull:`26893`: PGF: Consistently set LaTeX document font size +* :ghpull:`28156`: Don't set savefig.facecolor/edgecolor in dark_background/538 styles. +* :ghpull:`28030`: Fix #28016: wrong lower ylim when baseline=None on stairs +* :ghpull:`28127`: GOV: write up policy on not updating req for CVEs in dependencies +* :ghpull:`28106`: Fix: [Bug]: Setting norm by string doesn't work for hexbin #28105 +* :ghpull:`28143`: Merge branch v3.9.x into main +* :ghpull:`28133`: Make ``functions`` param to secondary_x/yaxis not keyword-only. +* :ghpull:`28083`: Convert TensorFlow to numpy for plots +* :ghpull:`28116`: FIX: Correct names of aliased cmaps +* :ghpull:`28118`: Remove redundant baseline tests in test_image. +* :ghpull:`28093`: Minor maintenance on pgf docs/backends. +* :ghpull:`27818`: Set polygon offsets for log scaled hexbin +* :ghpull:`28058`: TYP: add float to to_rgba x type +* :ghpull:`27964`: BUG: Fix NonUniformImage with nonlinear scale +* :ghpull:`28054`: DOC: Clarify that parameters to gridded data plotting functions are p… +* :ghpull:`27882`: Deleting all images that have passed tests before upload +* :ghpull:`28033`: API: warn if stairs used in way that is likely not desired +* :ghpull:`27786`: Deprecate positional use of most arguments of plotting functions +* :ghpull:`28025`: DOC: Clarify interface terminology +* :ghpull:`28043`: MNT: Add git blame ignore for docstring parameter indentation fix +* :ghpull:`28037`: DOC: Fix inconsistent spacing in some docstrings in _axes.py +* :ghpull:`28031`: Be more specific in findobj return type + +Issues (100): + +* :ghissue:`29298`: [Doc]: The link at "see also" is incorrect. (Axes.violin) +* :ghissue:`29248`: [Bug]: Figure.align_labels() confused by GridSpecFromSubplotSpec +* :ghissue:`26738`: Improve LineCollection docstring further +* :ghissue:`29263`: [Bug]: mypy failures in CI +* :ghissue:`27416`: [Bug]: get_tick_params on xaxis shows wrong keywords +* :ghissue:`29241`: [Bug]: Instructions for setting up conda dev environment in environment.yml give issues with MacOS/zsh +* :ghissue:`29227`: [Bug]: Introductory example on the pyplot API page does not show - missing plt.show() +* :ghissue:`29190`: [Bug]: inconsistent ‘animation.FuncAnimation’ between display and save +* :ghissue:`29090`: [MNT]: More consistent color parameters for bar() +* :ghissue:`29179`: [Bug]: Incorrect pcolormesh when shading='nearest' and only the mesh data C is provided. +* :ghissue:`29067`: [Bug]: ``secondary_xaxis`` produces ticks at incorrect locations +* :ghissue:`29126`: [Bug]: TkAgg backend is broken with tcl/tk 9.0 +* :ghissue:`29045`: [ENH]: implement back/forward buttons on mouse move events on macOS +* :ghissue:`27173`: [Bug]: Gifs no longer create transparent background +* :ghissue:`19229`: Add public API for setting an axis unit converter +* :ghissue:`21108`: [Bug]: Hatch linewidths cannot be modified in an rcParam context +* :ghissue:`27784`: [Bug]: Polar plot error bars don't rotate with angle for ``set_theta_direction`` and ``set_theta_offset`` +* :ghissue:`29011`: [Bug]: Figure.autofmt_xdate() not working in presence of colorbar with constrained layout +* :ghissue:`29020`: AIX internal CI build break #Matplotlib +* :ghissue:`28726`: feature request: support passing DataFrames to table.table +* :ghissue:`28570`: [MNT]: Try improving doc build speed by using PyStemmer +* :ghissue:`13388`: Typo in the figure API (fig.suptitle) +* :ghissue:`28994`: [Bug]: Figure Number Gives Type Error +* :ghissue:`28985`: [ENH]: Cannot disable coordinate display in ToolManager/Toolbar (it's doable in NavigationToolbar2) +* :ghissue:`17914`: ``PathSimplifier`` fails to ignore ``CLOSEPOLY`` vertices +* :ghissue:`28885`: [Bug]: Strange errorbar caps when polar axes have non-default theta direction or theta zero location +* :ghissue:`12418`: replace ttconv for ps/pdf +* :ghissue:`28962`: [Bug]: gtk4 backend does not set guiEvent attribute +* :ghissue:`28408`: [ENH]: mplot3d mouse rotation style +* :ghissue:`28701`: [MNT]: Separate the generation of polygon vertices from ``_fill_between_x_or_y`` +* :ghissue:`28941`: [Bug]: unexplicit error message when using ``matplotlib.colors.rgb_to_hsv()`` with wrong input +* :ghissue:`23846`: [MNT]: Pybind11 transition plan +* :ghissue:`28866`: Possible memory leak in pybind11 migration +* :ghissue:`26368`: [Bug]: Long audio files result in incomplete spectrogram visualizations +* :ghissue:`23826`: [Bug]: Overflow of 16-bit integer in Agg renderer causes PolyCollections to be drawn at incorrect locations +* :ghissue:`28927`: [Bug]: Enforce that Line data modifications are sequences +* :ghissue:`12312`: colorbar(boundaries=...) doesn't work so well with nonlinear norms +* :ghissue:`28800`: [ENH]: AxLine xy1/xy2 setters should take xy as single parameters, (possibly) not separate ones +* :ghissue:`28893`: [Bug]: Lines between points are invisible when there are more than 7 subfigures per row +* :ghissue:`28908`: [Bug]: Possible performance issue with _LazyTickList +* :ghissue:`27971`: [Bug]: ax.xaxis.set_label(...) doesn't set the x-axis label +* :ghissue:`28059`: [Bug]: pcolorfast should validate that regularly spaced X or Y inputs have the right size +* :ghissue:`28892`: [Doc]: Be more specific on dependencies that need to be installed for a "reasonable" dev environment +* :ghissue:`19693`: path.sketch doesn't apply to PolyCollection +* :ghissue:`28873`: [Bug]: hist()'s doc for edgecolors/facecolors does not match behavior (which is itself not very consistent) +* :ghissue:`23005`: [Doc]: Add figure to ``subplots_adjust`` +* :ghissue:`25947`: [Doc]: Subfigures still marked as provisional +* :ghissue:`26012`: [Bug]: "Unhashable type" when event callback is a method of a ``dict`` subclass +* :ghissue:`23425`: [Bug]: Axes.indicate_inset connectors affect constrained layout +* :ghissue:`23424`: [Bug]: Axes.indicate_inset(linewidth=...) doesn't affect connectors +* :ghissue:`19768`: Overlay created by ``Axes.indicate_inset_zoom`` does not adjust when changing inset ranges +* :ghissue:`27673`: [Doc]: Confusing page on color changes +* :ghissue:`28782`: [Bug]: String ``contour(colors)`` gives confusing error when ``extend`` used +* :ghissue:`27930`: [ENH]: Make axes_grid1.Size more math friendly. +* :ghissue:`28372`: [Bug]: AffineDeltaTransform does not appear to invalidate properly +* :ghissue:`27866`: [Bug]: Adding suptitle in compressed layout causes weird spacing +* :ghissue:`28731`: [Bug]: Plotting numpy.array of dtype float32 with pyplot.imshow and specified colors.LogNorm produces wrong colors +* :ghissue:`28715`: [Bug]: CI doc builds fail since a couple of days +* :ghissue:`28698`: [bug]: arrowstyle doc interpolation in FancyPatch.set_arrow() +* :ghissue:`28669`: [Bug]: division-by-zero error in Sketch::Sketch with Agg backend +* :ghissue:`28548`: [Doc]: matplotlib.pyplot.specgram parameters vmin and vmax are not documented +* :ghissue:`28165`: [Bug]: PolygonSelector should hide itself when zoom/pan is active +* :ghissue:`18608`: Feature proposal: "Dark mode" divergent colormaps +* :ghissue:`28623`: [Bug]: ``Axis.set_in_layout`` not respected? +* :ghissue:`6305`: Matplotlib 3D plot - parametric curve “wraparound” from certain perspectives +* :ghissue:`28595`: [Bug]: set_url without effect for instances of Line2D with linestyle 'none' +* :ghissue:`20910`: [Bug]: Exported SVG files are no longer imported Affinity Designer correctly +* :ghissue:`28600`: [TST] Upcoming dependency test failures +* :ghissue:`26718`: [Bug]: stacked histogram does not properly handle edgecolor and hatches +* :ghissue:`28590`: [ENH]: Geo Projections support for inverting axis +* :ghissue:`27954`: [ENH]: Iterables in grouped histogram labels +* :ghissue:`27878`: [ENH]: AttributeError('... got an unexpected keyword argument ...') should set the .name attribute to the keyword +* :ghissue:`28489`: [TST] Upcoming dependency test failures +* :ghissue:`28343`: [Bug]: inconsistent colorbar pad for ``ImageGrid`` with ``cbar_mode="single"`` +* :ghissue:`28535`: [ENH]: Add id attribute to top level svg tag +* :ghissue:`28170`: [Doc]: ``get_figure`` may return a ``SubFigure`` +* :ghissue:`27831`: [Bug]: Nondeterminism in SVG clipPath element id attributes +* :ghissue:`4568`: Add ``fmt_r`` and ``fmt_theta`` methods to polar axes +* :ghissue:`28105`: [Bug]: Setting norm by string doesn't work for hexbin +* :ghissue:`28142`: [ENH]: Add fill between support for 3D plots +* :ghissue:`28344`: [Bug]: subfigures are added in column major order +* :ghissue:`28212`: [Bug]: Matplotlib not work with MiKTeX. +* :ghissue:`28288`: [ENH]: Natural 3D rotation with mouse +* :ghissue:`28180`: [Bug]: mathtext should distinguish between unary and binary minus +* :ghissue:`26150`: [Bug]: Savefig slow with subplots +* :ghissue:`28310`: [Bug]: orientation indication shows up late in mplot3d, and then lingers +* :ghissue:`16263`: Apply NEP29 (time-limited support) to IPython +* :ghissue:`28192`: [MNT]: Essential build requirements not included in dev-requirements +* :ghissue:`27978`: [Bug]: strange behaviour when redefining figure size +* :ghissue:`13435`: boxplot/violinplot orientation-setting API +* :ghissue:`28199`: [MNT]: Misleading function name ``Poly3DCollection.get_vector()`` +* :ghissue:`26892`: [Bug]: PGF font size mismatch between measurement and output +* :ghissue:`28016`: [Bug]: Unexpected ylim of stairs with baseline=None +* :ghissue:`28114`: [Bug]: mpl.colormaps[ "Grays" ].name is "Greys", not "Grays" +* :ghissue:`18045`: Cannot access hexbin data when ``xscale='log'`` and ``yscale='log'`` are set. +* :ghissue:`27820`: [Bug]: Logscale Axis + NonUniformImage + GUI move tool = Distortion +* :ghissue:`28047`: [Bug]: plt.barbs is a command that cannot be passed in a c parameter by parameter name, but can be passed in the form of a positional parameter +* :ghissue:`23400`: Only upload failed images on failure +* :ghissue:`26752`: [Bug]: ``ax.stairs()`` creates inaccurate ``fill`` for the plot +* :ghissue:`21817`: [Doc/Dev]: style guide claims "object oriented" is verboten. diff --git a/doc/users/prev_whats_new/whats_new_1.0.rst b/doc/users/prev_whats_new/whats_new_1.0.rst index c8da886c9097..772f241f4b23 100644 --- a/doc/users/prev_whats_new/whats_new_1.0.rst +++ b/doc/users/prev_whats_new/whats_new_1.0.rst @@ -26,8 +26,8 @@ doing complex subplot layouts, featuring row and column spans and more. See :ref:`arranging_axes` for a tutorial overview. -.. figure:: ../../gallery/userdemo/images/sphx_glr_demo_gridspec01_001.png - :target: ../../gallery/userdemo/demo_gridspec01.html +.. figure:: ../../gallery/subplots_axes_and_figures/images/sphx_glr_subplot2grid_001.png + :target: ../../gallery/subplots_axes_and_figures/subplot2grid.html :align: center :scale: 50 diff --git a/doc/users/prev_whats_new/whats_new_3.10.0.rst b/doc/users/prev_whats_new/whats_new_3.10.0.rst index bc160787aebc..6172fe1953ff 100644 --- a/doc/users/prev_whats_new/whats_new_3.10.0.rst +++ b/doc/users/prev_whats_new/whats_new_3.10.0.rst @@ -1,3 +1,17 @@ +=================================================== +What's new in Matplotlib 3.10.0 (December 13, 2024) +=================================================== + +For a list of all of the issues and pull requests since the last revision, see the +:ref:`github-stats`. + +.. contents:: Table of Contents + :depth: 4 + +.. toctree:: + :maxdepth: 4 + + New more-accessible color cycle ------------------------------- @@ -43,6 +57,12 @@ colour maps version 8.0.1 (DOI: https://doi.org/10.5281/zenodo.1243862). ax[1].imshow(img, cmap=plt.cm.managua) ax[2].imshow(img, cmap=plt.cm.vanimo) + + +Plotting and Annotation improvements +==================================== + + Specifying a single color in ``contour`` and ``contourf`` --------------------------------------------------------- @@ -65,66 +85,6 @@ may be passed. plt.show() -Exception handling control --------------------------- - -The exception raised when an invalid keyword parameter is passed now includes -that parameter name as the exception's ``name`` property. This provides more -control for exception handling: - - -.. code-block:: python - - import matplotlib.pyplot as plt - - def wobbly_plot(args, **kwargs): - w = kwargs.pop('wobble_factor', None) - - try: - plt.plot(args, **kwargs) - except AttributeError as e: - raise AttributeError(f'wobbly_plot does not take parameter {e.name}') from e - - - wobbly_plot([0, 1], wibble_factor=5) - -.. code-block:: - - AttributeError: wobbly_plot does not take parameter wibble_factor - -Preliminary support for free-threaded CPython 3.13 --------------------------------------------------- - -Matplotlib 3.10 has preliminary support for the free-threaded build of CPython 3.13. See -https://py-free-threading.github.io, `PEP 703 `_ and -the `CPython 3.13 release notes -`_ for more detail -about free-threaded Python. - -Support for free-threaded Python does not mean that Matplotlib is wholly thread safe. We -expect that use of a Figure within a single thread will work, and though input data is -usually copied, modification of data objects used for a plot from another thread may -cause inconsistencies in cases where it is not. Use of any global state (such as the -``pyplot`` module) is highly discouraged and unlikely to work consistently. Also note -that most GUI toolkits expect to run on the main thread, so interactive usage may be -limited or unsupported from other threads. - -If you are interested in free-threaded Python, for example because you have a -multiprocessing-based workflow that you are interested in running with Python threads, we -encourage testing and experimentation. If you run into problems that you suspect are -because of Matplotlib, please open an issue, checking first if the bug also occurs in the -“regular” non-free-threaded CPython 3.13 build. - -Increased Figure limits with Agg renderer ------------------------------------------ - -Figures using the Agg renderer are now limited to 2**23 pixels in each -direction, instead of 2**16. Additionally, bugs that caused artists to not -render past 2**15 pixels horizontally have been fixed. - -Note that if you are using a GUI backend, it may have its own smaller limits -(which may themselves depend on screen size.) - Vectorized ``hist`` style parameters ------------------------------------ @@ -259,39 +219,6 @@ Subfigures are now added in row-major order ax.set_yticks([]) plt.show() -``svg.id`` rcParam ------------------- - -:rc:`svg.id` lets you insert an ``id`` attribute into the top-level ```` tag. - -e.g. ``rcParams["svg.id"] = "svg1"`` results in -default), no ``id`` tag is included - -.. code-block:: XML - - - -This is useful if you would like to link the entire matplotlib SVG file within -another SVG file with the ```` tag. - -.. code-block:: XML - - - - -Where the ``#svg1`` indicator will now refer to the top level ```` tag, and -will hence result in the inclusion of the entire file. ``boxplot`` and ``bxp`` orientation parameter --------------------------------------------- @@ -361,6 +288,67 @@ the ``set_data`` method, enabling e.g. resampling coll.set_data(t, -t**4, t**4) fig.savefig("after.png") + +``matplotlib.colorizer.Colorizer`` as container for ``norm`` and ``cmap`` +------------------------------------------------------------------------- + + `matplotlib.colorizer.Colorizer` encapsulates the data-to-color pipeline. It makes reuse of colormapping easier, e.g. across multiple images. Plotting methods that support *norm* and *cmap* keyword arguments now also accept a *colorizer* keyword argument. + +In the following example the norm and cmap are changed on multiple plots simultaneously: + + +.. plot:: + :include-source: true + :alt: Example use of a matplotlib.colorizer.Colorizer object + + import matplotlib.pyplot as plt + import matplotlib as mpl + import numpy as np + + x = np.linspace(-2, 2, 50)[np.newaxis, :] + y = np.linspace(-2, 2, 50)[:, np.newaxis] + im_0 = 1 * np.exp( - (x**2 + y**2 - x * y)) + im_1 = 2 * np.exp( - (x**2 + y**2 + x * y)) + + colorizer = mpl.colorizer.Colorizer() + fig, axes = plt.subplots(1, 2, figsize=(6, 2)) + cim_0 = axes[0].imshow(im_0, colorizer=colorizer) + fig.colorbar(cim_0) + cim_1 = axes[1].imshow(im_1, colorizer=colorizer) + fig.colorbar(cim_1) + + colorizer.vmin = 0.5 + colorizer.vmax = 2 + colorizer.cmap = 'RdBu' + +All plotting methods that use a data-to-color pipeline now create a colorizer object if one is not provided. This can be re-used by subsequent artists such that they will share a single data-to-color pipeline: + +.. plot:: + :include-source: true + :alt: Example of how artists that share a ``colorizer`` have coupled colormaps + + import matplotlib.pyplot as plt + import matplotlib as mpl + import numpy as np + + x = np.linspace(-2, 2, 50)[np.newaxis, :] + y = np.linspace(-2, 2, 50)[:, np.newaxis] + im_0 = 1 * np.exp( - (x**2 + y**2 - x * y)) + im_1 = 2 * np.exp( - (x**2 + y**2 + x * y)) + + fig, axes = plt.subplots(1, 2, figsize=(6, 2)) + + cim_0 = axes[0].imshow(im_0, cmap='RdBu', vmin=0.5, vmax=2) + fig.colorbar(cim_0) + cim_1 = axes[1].imshow(im_1, colorizer=cim_0.colorizer) + fig.colorbar(cim_1) + + cim_1.cmap = 'rainbow' + +3D plotting improvements +======================== + + Fill between 3D lines --------------------- @@ -471,6 +459,108 @@ view box is a limitation of the current renderer. ax.legend(['axlim_clip=False (default)', 'axlim_clip=True']) +Preliminary support for free-threaded CPython 3.13 +================================================== + +Matplotlib 3.10 has preliminary support for the free-threaded build of CPython 3.13. See +https://py-free-threading.github.io, `PEP 703 `_ and +the `CPython 3.13 release notes +`_ for more detail +about free-threaded Python. + +Support for free-threaded Python does not mean that Matplotlib is wholly thread safe. We +expect that use of a Figure within a single thread will work, and though input data is +usually copied, modification of data objects used for a plot from another thread may +cause inconsistencies in cases where it is not. Use of any global state (such as the +``pyplot`` module) is highly discouraged and unlikely to work consistently. Also note +that most GUI toolkits expect to run on the main thread, so interactive usage may be +limited or unsupported from other threads. + +If you are interested in free-threaded Python, for example because you have a +multiprocessing-based workflow that you are interested in running with Python threads, we +encourage testing and experimentation. If you run into problems that you suspect are +because of Matplotlib, please open an issue, checking first if the bug also occurs in the +“regular” non-free-threaded CPython 3.13 build. + + + +Other Improvements +================== + +``svg.id`` rcParam +------------------ + +:rc:`svg.id` lets you insert an ``id`` attribute into the top-level ```` tag. + +e.g. ``rcParams["svg.id"] = "svg1"`` results in + +.. code-block:: XML + + + +This is useful if you would like to link the entire matplotlib SVG file within +another SVG file with the ```` tag. + +.. code-block:: XML + + + + +Where the ``#svg1`` indicator will now refer to the top level ```` tag, and +will hence result in the inclusion of the entire file. + +By default, no ``id`` tag is included. + +Exception handling control +-------------------------- + +The exception raised when an invalid keyword parameter is passed now includes +that parameter name as the exception's ``name`` property. This provides more +control for exception handling: + + +.. code-block:: python + + import matplotlib.pyplot as plt + + def wobbly_plot(args, **kwargs): + w = kwargs.pop('wobble_factor', None) + + try: + plt.plot(args, **kwargs) + except AttributeError as e: + raise AttributeError(f'wobbly_plot does not take parameter {e.name}') from e + + + wobbly_plot([0, 1], wibble_factor=5) + +.. code-block:: + + AttributeError: wobbly_plot does not take parameter wibble_factor + +Increased Figure limits with Agg renderer +----------------------------------------- + +Figures using the Agg renderer are now limited to 2**23 pixels in each +direction, instead of 2**16. Additionally, bugs that caused artists to not +render past 2**15 pixels horizontally have been fixed. + +Note that if you are using a GUI backend, it may have its own smaller limits +(which may themselves depend on screen size.) + + + Miscellaneous Changes --------------------- diff --git a/doc/users/prev_whats_new/whats_new_3.9.0.rst b/doc/users/prev_whats_new/whats_new_3.9.0.rst index e0190cca3f27..85fabf86efbe 100644 --- a/doc/users/prev_whats_new/whats_new_3.9.0.rst +++ b/doc/users/prev_whats_new/whats_new_3.9.0.rst @@ -3,7 +3,7 @@ What's new in Matplotlib 3.9.0 (May 15, 2024) ============================================= For a list of all of the issues and pull requests since the last revision, see the -:ref:`github-stats`. +:ref:`github-stats-3-9-0`. .. contents:: Table of Contents :depth: 4 diff --git a/doc/users/release_notes.rst b/doc/users/release_notes.rst index 3bb30bf2fa49..ae06d9875988 100644 --- a/doc/users/release_notes.rst +++ b/doc/users/release_notes.rst @@ -18,7 +18,9 @@ Version 3.10 :maxdepth: 1 prev_whats_new/whats_new_3.10.0.rst + ../api/prev_api_changes/api_changes_3.10.1.rst ../api/prev_api_changes/api_changes_3.10.0.rst + github_stats.rst prev_whats_new/github_stats_3.10.0.rst Version 3.9 diff --git a/environment.yml b/environment.yml index 4a36f76031ea..8c4221d0a0fa 100644 --- a/environment.yml +++ b/environment.yml @@ -18,7 +18,7 @@ dependencies: - kiwisolver>=1.3.1 - pybind11>=2.13.2 - meson-python>=0.13.1 - - numpy<2.1 + - numpy - pillow>=8 - pkg-config - pygobject diff --git a/galleries/examples/color/color_sequences.py b/galleries/examples/color/color_sequences.py new file mode 100644 index 000000000000..9a2fd04a53d0 --- /dev/null +++ b/galleries/examples/color/color_sequences.py @@ -0,0 +1,65 @@ +""" +===================== +Named color sequences +===================== + +Matplotlib's `~matplotlib.colors.ColorSequenceRegistry` allows access to +predefined lists of colors by name e.g. +``colors = matplotlib.color_sequences['Set1']``. This example shows all of the +built in color sequences. + +User-defined sequences can be added via `.ColorSequenceRegistry.register`. +""" + +import matplotlib.pyplot as plt +import numpy as np + +import matplotlib as mpl + + +def plot_color_sequences(names, ax): + # Display each named color sequence horizontally on the supplied axes. + + for n, name in enumerate(names): + colors = mpl.color_sequences[name] + n_colors = len(colors) + x = np.arange(n_colors) + y = np.full_like(x, n) + + ax.scatter(x, y, facecolor=colors, edgecolor='dimgray', s=200, zorder=2) + + ax.set_yticks(range(len(names)), labels=names) + ax.grid(visible=True, axis='y') + ax.yaxis.set_inverted(True) + ax.xaxis.set_visible(False) + ax.spines[:].set_visible(False) + ax.tick_params(left=False) + + +built_in_color_sequences = [ + 'tab10', 'tab20', 'tab20b', 'tab20c', 'Pastel1', 'Pastel2', 'Paired', + 'Accent', 'Dark2', 'Set1', 'Set2', 'Set3', 'petroff10'] + + +fig, ax = plt.subplots(figsize=(6.4, 9.6), layout='constrained') + +plot_color_sequences(built_in_color_sequences, ax) +ax.set_title('Built In Color Sequences') + +plt.show() + + +# %% +# +# .. admonition:: References +# +# The use of the following functions, methods, classes and modules is shown +# in this example: +# +# - `matplotlib.colors.ColorSequenceRegistry` +# - `matplotlib.axes.Axes.scatter` +# +# .. tags:: +# +# styling: color +# purpose: reference diff --git a/galleries/examples/color/individual_colors_from_cmap.py b/galleries/examples/color/individual_colors_from_cmap.py index cdd176eb3be1..8d2b41eb02fb 100644 --- a/galleries/examples/color/individual_colors_from_cmap.py +++ b/galleries/examples/color/individual_colors_from_cmap.py @@ -38,7 +38,9 @@ # Extracting colors from a discrete colormap # ------------------------------------------ # The list of all colors in a `.ListedColormap` is available as the ``colors`` -# attribute. +# attribute. Note that all the colors from Matplotlib's qualitative color maps +# are also available as color sequences, so may be accessed more directly from +# the color sequence registry. See :doc:`/gallery/color/color_sequences`. colors = mpl.colormaps['Dark2'].colors diff --git a/galleries/examples/event_handling/data_browser.py b/galleries/examples/event_handling/data_browser.py index 6d9068940285..3d2dfeddc3a3 100644 --- a/galleries/examples/event_handling/data_browser.py +++ b/galleries/examples/event_handling/data_browser.py @@ -82,7 +82,7 @@ def update(self): transform=ax2.transAxes, va='top') ax2.set_ylim(-0.5, 1.5) self.selected.set_visible(True) - self.selected.set_data(xs[dataind], ys[dataind]) + self.selected.set_data([xs[dataind]], [ys[dataind]]) self.text.set_text('selected: %d' % dataind) fig.canvas.draw() diff --git a/galleries/examples/pyplots/axline.py b/galleries/examples/lines_bars_and_markers/axline.py similarity index 64% rename from galleries/examples/pyplots/axline.py rename to galleries/examples/lines_bars_and_markers/axline.py index 71c9994072a1..11e8c646fe41 100644 --- a/galleries/examples/pyplots/axline.py +++ b/galleries/examples/lines_bars_and_markers/axline.py @@ -9,6 +9,8 @@ sigmoid function. `~.axes.Axes.axline` draws infinite straight lines in arbitrary directions. + +.. redirect-from:: /gallery/pyplot/axline """ import matplotlib.pyplot as plt @@ -17,28 +19,28 @@ t = np.linspace(-10, 10, 100) sig = 1 / (1 + np.exp(-t)) -plt.axhline(y=0, color="black", linestyle="--") -plt.axhline(y=0.5, color="black", linestyle=":") -plt.axhline(y=1.0, color="black", linestyle="--") -plt.axvline(color="grey") -plt.axline((0, 0.5), slope=0.25, color="black", linestyle=(0, (5, 5))) -plt.plot(t, sig, linewidth=2, label=r"$\sigma(t) = \frac{1}{1 + e^{-t}}$") -plt.xlim(-10, 10) -plt.xlabel("t") -plt.legend(fontsize=14) +fig, ax = plt.subplots() +ax.axhline(y=0, color="black", linestyle="--") +ax.axhline(y=0.5, color="black", linestyle=":") +ax.axhline(y=1.0, color="black", linestyle="--") +ax.axvline(color="grey") +ax.axline((0, 0.5), slope=0.25, color="black", linestyle=(0, (5, 5))) +ax.plot(t, sig, linewidth=2, label=r"$\sigma(t) = \frac{1}{1 + e^{-t}}$") +ax.set(xlim=(-10, 10), xlabel="t") +ax.legend(fontsize=14) plt.show() # %% -# `~.axes.Axes.axline` can also be used with a ``transform`` parameter, which +# `~.axes.Axes.axline` can also be used with a *transform* parameter, which # applies to the point, but not to the slope. This can be useful for drawing # diagonal grid lines with a fixed slope, which stay in place when the # plot limits are moved. +fig, ax = plt.subplots() for pos in np.linspace(-2, 1, 10): - plt.axline((pos, 0), slope=0.5, color='k', transform=plt.gca().transAxes) + ax.axline((pos, 0), slope=0.5, color='k', transform=ax.transAxes) -plt.ylim([0, 1]) -plt.xlim([0, 1]) +ax.set(xlim=(0, 1), ylim=(0, 1)) plt.show() # %% @@ -57,3 +59,5 @@ # # `~.Axes.axhspan`, `~.Axes.axvspan` draw rectangles that span the Axes in one # direction and are bounded in the other direction. +# +# .. tags:: component: annotation diff --git a/galleries/examples/lines_bars_and_markers/broken_barh.py b/galleries/examples/lines_bars_and_markers/broken_barh.py index e1550385155a..3714ca7c748d 100644 --- a/galleries/examples/lines_bars_and_markers/broken_barh.py +++ b/galleries/examples/lines_bars_and_markers/broken_barh.py @@ -1,31 +1,48 @@ """ -=========== -Broken Barh -=========== +====================== +Broken horizontal bars +====================== -Make a "broken" horizontal bar plot, i.e., one with gaps +`~.Axes.broken_barh` creates sequences of horizontal bars. This example shows +a timing diagram. """ import matplotlib.pyplot as plt +import numpy as np + +# data is a sequence of (start, duration) tuples +cpu_1 = [(0, 3), (3.5, 1), (5, 5)] +cpu_2 = np.column_stack([np.linspace(0, 9, 10), np.full(10, 0.5)]) +cpu_3 = np.column_stack([10*np.random.random(61), np.full(61, 0.05)]) +cpu_4 = [(2, 1.7), (7, 1.2)] +disk = [(1, 1.5)] +network = np.column_stack([10*np.random.random(10), np.full(10, 0.05)]) -# Horizontal bar plot with gaps fig, ax = plt.subplots() -ax.broken_barh([(110, 30), (150, 10)], (10, 9), facecolors='tab:blue') -ax.broken_barh([(10, 50), (100, 20), (130, 10)], (20, 9), - facecolors=('tab:orange', 'tab:green', 'tab:red')) -ax.set_ylim(5, 35) -ax.set_xlim(0, 200) -ax.set_xlabel('seconds since start') -ax.set_yticks([15, 25], labels=['Bill', 'Jim']) # Modify y-axis tick labels -ax.grid(True) # Make grid lines visible -ax.annotate('race interrupted', (61, 25), - xytext=(0.8, 0.9), textcoords='axes fraction', - arrowprops=dict(facecolor='black', shrink=0.05), - fontsize=16, - horizontalalignment='right', verticalalignment='top') +# broken_barh(xranges, (ymin, height)) +ax.broken_barh(cpu_1, (-0.2, 0.4)) +ax.broken_barh(cpu_2, (0.8, 0.4)) +ax.broken_barh(cpu_3, (1.8, 0.4)) +ax.broken_barh(cpu_4, (2.8, 0.4)) +ax.broken_barh(disk, (3.8, 0.4), color="tab:orange") +ax.broken_barh(network, (4.8, 0.4), color="tab:green") +ax.set_xlim(0, 10) +ax.set_yticks(range(6), + labels=["CPU 1", "CPU 2", "CPU 3", "CPU 4", "disk", "network"]) +ax.invert_yaxis() +ax.set_title("Resource usage") plt.show() - # %% +# +# .. admonition:: References +# +# The use of the following functions, methods, classes and modules is shown +# in this example: +# +# - `matplotlib.axes.Axes.broken_barh` / `matplotlib.pyplot.broken_barh` +# - `matplotlib.axes.Axes.invert_yaxis` +# - `matplotlib.axes.Axes.set_yticks` +# # .. tags:: # # component: annotation diff --git a/galleries/examples/lines_bars_and_markers/categorical_variables.py b/galleries/examples/lines_bars_and_markers/categorical_variables.py index 4cceb38fbd4d..a19a30eda2b2 100644 --- a/galleries/examples/lines_bars_and_markers/categorical_variables.py +++ b/galleries/examples/lines_bars_and_markers/categorical_variables.py @@ -20,7 +20,10 @@ # %% -# This works on both Axes: +# Categorical values are a mapping from names to positions. This means that +# values that occur multiple times are mapped to the same position. See the +# ``cat`` and ``dog`` values "happy" and "bored" on the y-axis in the following +# example. cat = ["bored", "happy", "bored", "bored", "happy", "bored"] dog = ["happy", "happy", "happy", "happy", "bored", "bored"] diff --git a/galleries/examples/lines_bars_and_markers/scatter_hist.py b/galleries/examples/lines_bars_and_markers/scatter_hist.py index 505edf6d627f..d2b4c4eab228 100644 --- a/galleries/examples/lines_bars_and_markers/scatter_hist.py +++ b/galleries/examples/lines_bars_and_markers/scatter_hist.py @@ -3,8 +3,11 @@ Scatter plot with histograms ============================ -Show the marginal distributions of a scatter plot as histograms at the sides of -the plot. +Add histograms to the x-axes and y-axes margins of a scatter plot. + +This layout features a central scatter plot illustrating the relationship +between x and y, a histogram at the top displaying the distribution of x, and a +histogram on the right showing the distribution of y. For a nice alignment of the main Axes with the marginals, two options are shown below: @@ -15,14 +18,9 @@ While `.Axes.inset_axes` may be a bit more complex, it allows correct handling of main Axes with a fixed aspect ratio. -An alternative method to produce a similar figure using the ``axes_grid1`` -toolkit is shown in the :doc:`/gallery/axes_grid1/scatter_hist_locatable_axes` -example. Finally, it is also possible to position all Axes in absolute -coordinates using `.Figure.add_axes` (not shown here). - -Let us first define a function that takes x and y data as input, as well -as three Axes, the main Axes for the scatter, and two marginal Axes. It will -then create the scatter and histograms inside the provided Axes. +Let us first define a function that takes x and y data as input, as well as +three Axes, the main Axes for the scatter, and two marginal Axes. It will then +create the scatter and histograms inside the provided Axes. """ import matplotlib.pyplot as plt @@ -55,27 +53,22 @@ def scatter_hist(x, y, ax, ax_histx, ax_histy): # %% +# Defining the Axes positions using subplot_mosaic +# ------------------------------------------------ # -# Defining the Axes positions using a gridspec -# -------------------------------------------- -# -# We define a gridspec with unequal width- and height-ratios to achieve desired -# layout. Also see the :ref:`arranging_axes` tutorial. - -# Start with a square Figure. -fig = plt.figure(figsize=(6, 6)) -# Add a gridspec with two rows and two columns and a ratio of 1 to 4 between -# the size of the marginal Axes and the main Axes in both directions. -# Also adjust the subplot parameters for a square plot. -gs = fig.add_gridspec(2, 2, width_ratios=(4, 1), height_ratios=(1, 4), - left=0.1, right=0.9, bottom=0.1, top=0.9, - wspace=0.05, hspace=0.05) -# Create the Axes. -ax = fig.add_subplot(gs[1, 0]) -ax_histx = fig.add_subplot(gs[0, 0], sharex=ax) -ax_histy = fig.add_subplot(gs[1, 1], sharey=ax) -# Draw the scatter plot and marginals. -scatter_hist(x, y, ax, ax_histx, ax_histy) +# We use the `~.pyplot.subplot_mosaic` function to define the positions and +# names of the three axes; the empty axes is specified by ``'.'``. We manually +# specify the size of the figure, and can make the different axes have +# different sizes by specifying the *width_ratios* and *height_ratios* +# arguments. The *layout* argument is set to ``'constrained'`` to optimize the +# spacing between the axes. + +fig, axs = plt.subplot_mosaic([['histx', '.'], + ['scatter', 'histy']], + figsize=(6, 6), + width_ratios=(4, 1), height_ratios=(1, 4), + layout='constrained') +scatter_hist(x, y, axs['scatter'], axs['histx'], axs['histy']) # %% @@ -90,11 +83,10 @@ def scatter_hist(x, y, ax, ax_histx, ax_histy): # Create a Figure, which doesn't have to be square. fig = plt.figure(layout='constrained') -# Create the main Axes, leaving 25% of the figure space at the top and on the -# right to position marginals. -ax = fig.add_gridspec(top=0.75, right=0.75).subplots() +# Create the main Axes. +ax = fig.add_subplot() # The main Axes' aspect can be fixed. -ax.set(aspect=1) +ax.set_aspect('equal') # Create marginal Axes, which have 25% of the size of the main Axes. Note that # the inset Axes are positioned *outside* (on the right and the top) of the # main Axes, by specifying axes coordinates greater than 1. Axes coordinates @@ -110,13 +102,27 @@ def scatter_hist(x, y, ax, ax_histx, ax_histy): # %% # +# While we recommend using one of the two methods described above, there are +# number of other ways to achieve a similar layout: +# +# - The Axes can be positioned manually in relative coordinates using +# `~matplotlib.figure.Figure.add_axes`. +# - A gridspec can be used to create the layout +# (`~matplotlib.figure.Figure.add_gridspec`) and adding only the three desired +# axes (`~matplotlib.figure.Figure.add_subplot`). +# - Four subplots can be created using `~.pyplot.subplots`, and the unused +# axes in the upper right can be removed manually. +# - The ``axes_grid1`` toolkit can be used, as shown in +# :doc:`/gallery/axes_grid1/scatter_hist_locatable_axes`. +# # .. admonition:: References # # The use of the following functions, methods, classes and modules is shown # in this example: # +# - `matplotlib.figure.Figure.subplot_mosaic` +# - `matplotlib.pyplot.subplot_mosaic` # - `matplotlib.figure.Figure.add_subplot` -# - `matplotlib.figure.Figure.add_gridspec` # - `matplotlib.axes.Axes.inset_axes` # - `matplotlib.axes.Axes.scatter` # - `matplotlib.axes.Axes.hist` diff --git a/galleries/examples/misc/ftface_props.py b/galleries/examples/misc/ftface_props.py index 8306e142c144..ec26dff5bf6a 100644 --- a/galleries/examples/misc/ftface_props.py +++ b/galleries/examples/misc/ftface_props.py @@ -18,12 +18,13 @@ os.path.join(matplotlib.get_data_path(), 'fonts/ttf/DejaVuSans-Oblique.ttf')) -print('Num faces: ', font.num_faces) # number of faces in file -print('Num glyphs: ', font.num_glyphs) # number of glyphs in the face -print('Family name:', font.family_name) # face family name -print('Style name: ', font.style_name) # face style name -print('PS name: ', font.postscript_name) # the postscript name -print('Num fixed: ', font.num_fixed_sizes) # number of embedded bitmaps +print('Num instances: ', font.num_named_instances) # number of named instances in file +print('Num faces: ', font.num_faces) # number of faces in file +print('Num glyphs: ', font.num_glyphs) # number of glyphs in the face +print('Family name: ', font.family_name) # face family name +print('Style name: ', font.style_name) # face style name +print('PS name: ', font.postscript_name) # the postscript name +print('Num fixed: ', font.num_fixed_sizes) # number of embedded bitmaps # the following are only available if face.scalable if font.scalable: diff --git a/galleries/examples/scales/asinh_demo.py b/galleries/examples/scales/asinh_demo.py index a464d4546ea8..bc8b010c47ce 100644 --- a/galleries/examples/scales/asinh_demo.py +++ b/galleries/examples/scales/asinh_demo.py @@ -1,7 +1,7 @@ """ -============ -Asinh Demo -============ +=========== +Asinh scale +=========== Illustration of the `asinh <.scale.AsinhScale>` axis scaling, which uses the transformation diff --git a/galleries/examples/scales/custom_scale.py b/galleries/examples/scales/custom_scale.py index 0023bbcfbcae..0eedb16ec5cf 100644 --- a/galleries/examples/scales/custom_scale.py +++ b/galleries/examples/scales/custom_scale.py @@ -5,13 +5,25 @@ Custom scale ============ -Create a custom scale, by implementing the scaling use for latitude data in a -Mercator Projection. +Custom scales can be created in two ways + +#. For simple cases, use `~.scale.FuncScale` and the ``'function'`` option of + `~.Axes.set_xscale` and `~.Axes.set_yscale`. See the last example in + :doc:`/gallery/scales/scales`. + +#. Create a custom scale class such as the one in this example, which implements + the scaling use for latitude data in a Mercator Projection. This more complicated + approach is useful when + + * You are making special use of the `.Transform` class, such as the special + handling of values beyond the threshold in ``MercatorLatitudeTransform`` + below. + + * You want to override the default locators and formatters for the axis + (``set_default_locators_and_formatters`` below). + + * You want to limit the range of the the axis (``limit_range_for_scale`` below). -Unless you are making special use of the `.Transform` class, you probably -don't need to use this verbose method, and instead can use `~.scale.FuncScale` -and the ``'function'`` option of `~.Axes.set_xscale` and `~.Axes.set_yscale`. -See the last example in :doc:`/gallery/scales/scales`. """ import numpy as np diff --git a/galleries/examples/scales/log_bar.py b/galleries/examples/scales/log_bar.py deleted file mode 100644 index 239069806c5c..000000000000 --- a/galleries/examples/scales/log_bar.py +++ /dev/null @@ -1,29 +0,0 @@ -""" -======= -Log Bar -======= - -Plotting a bar chart with a logarithmic y-axis. -""" -import matplotlib.pyplot as plt -import numpy as np - -data = ((3, 1000), (10, 3), (100, 30), (500, 800), (50, 1)) - -dim = len(data[0]) -w = 0.75 -dimw = w / dim - -fig, ax = plt.subplots() -x = np.arange(len(data)) -for i in range(len(data[0])): - y = [d[i] for d in data] - b = ax.bar(x + i * dimw, y, dimw, bottom=0.001) - -ax.set_xticks(x + dimw / 2, labels=map(str, x)) -ax.set_yscale('log') - -ax.set_xlabel('x') -ax.set_ylabel('y') - -plt.show() diff --git a/galleries/examples/scales/log_demo.py b/galleries/examples/scales/log_demo.py index debbad258bc6..ce0c77551c0a 100644 --- a/galleries/examples/scales/log_demo.py +++ b/galleries/examples/scales/log_demo.py @@ -1,47 +1,83 @@ """ -======== -Log Demo -======== +========= +Log scale +========= Examples of plots with logarithmic axes. + +You can set the x/y axes to be logarithmic by passing "log" to `~.Axes.set_xscale` / +`~.Axes.set_yscale`. + +Convenience functions ``semilogx``, ``semilogy``, and ``loglog`` +---------------------------------------------------------------- +Since plotting data on semi-logarithmic or double-logarithmic scales is very common, +the functions `~.Axes.semilogx`, `~.Axes.semilogy`, and `~.Axes.loglog` are shortcuts +for setting the scale and plotting data; e.g. ``ax.semilogx(x, y)`` is equivalent to +``ax.set_xscale('log'); ax.plot(x, y)``. """ import matplotlib.pyplot as plt import numpy as np -# Data for plotting -t = np.arange(0.01, 20.0, 0.01) - -# Create figure -fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2) - -# log y axis -ax1.semilogy(t, np.exp(-t / 5.0)) -ax1.set(title='semilogy') +fig, (ax1, ax2, ax3) = plt.subplots(1, 3, layout='constrained', figsize=(7, 7/3)) +# log x axis +t = np.arange(0.01, 10.0, 0.01) +ax1.semilogx(t, np.sin(2 * np.pi * t)) +ax1.set(title='semilogx') ax1.grid() +ax1.grid(which="minor", color="0.9") -# log x axis -ax2.semilogx(t, np.sin(2 * np.pi * t)) -ax2.set(title='semilogx') +# log y axis +x = np.arange(4) +ax2.semilogy(4*x, 10**x, 'o--') +ax2.set(title='semilogy') ax2.grid() +ax2.grid(which="minor", color="0.9") # log x and y axis -ax3.loglog(t, 20 * np.exp(-t / 10.0)) -ax3.set_xscale('log', base=2) -ax3.set(title='loglog base 2 on x') +x = np.array([1, 10, 100, 1000]) +ax3.loglog(x, 5 * x, 'o--') +ax3.set(title='loglog') ax3.grid() +ax3.grid(which="minor", color="0.9") + +# %% +# Logarithms with other bases +# --------------------------- +# By default, the log scale is to the base 10. One can change this via the *base* +# parameter. +fig, ax = plt.subplots() +ax.bar(["L1 cache", "L2 cache", "L3 cache", "RAM", "SSD"], + [32, 1_000, 32_000, 16_000_000, 512_000_000]) +ax.set_yscale('log', base=2) +ax.set_yticks([1, 2**10, 2**20, 2**30], labels=['kB', 'MB', 'GB', 'TB']) +ax.set_title("Typical memory sizes") +ax.yaxis.grid() + +# %% +# Dealing with negative values +# ---------------------------- +# Non-positive values cannot be displayed on a log scale. The scale has two options +# to handle these. Either mask the values so that they are ignored, or clip them +# to a small positive value. Which one is more suited depends on the type of the +# data and the visualization. +# +# The following example contains errorbars going negative. If we mask these values, +# the bar vanishes, which is not desirable. In contrast, clipping makes the value +# small positive (but well below the used scale) so that the error bar is drawn +# to the edge of the Axes. +x = np.linspace(0.0, 2.0, 10) +y = 10**x +yerr = 1.75 + 0.75*y -# With errorbars: clip non-positive values -# Use new data for plotting -x = 10.0**np.linspace(0.0, 2.0, 20) -y = x**2.0 +fig, (ax1, ax2) = plt.subplots(1, 2, layout="constrained", figsize=(6, 3)) +fig.suptitle("errorbars going negative") +ax1.set_yscale("log", nonpositive='mask') +ax1.set_title('nonpositive="mask"') +ax1.errorbar(x, y, yerr=yerr, fmt='o', capsize=5) -ax4.set_xscale("log", nonpositive='clip') -ax4.set_yscale("log", nonpositive='clip') -ax4.set(title='Errorbars go negative') -ax4.errorbar(x, y, xerr=0.1 * x, yerr=5.0 + 0.75 * y) -# ylim must be set after errorbar to allow errorbar to autoscale limits -ax4.set_ylim(bottom=0.1) +ax2.set_yscale("log", nonpositive='clip') +ax2.set_title('nonpositive="clip"') +ax2.errorbar(x, y, yerr=yerr, fmt='o', capsize=5) -fig.tight_layout() plt.show() diff --git a/galleries/examples/scales/logit_demo.py b/galleries/examples/scales/logit_demo.py index a21abf5b64fb..22a56433ccd7 100644 --- a/galleries/examples/scales/logit_demo.py +++ b/galleries/examples/scales/logit_demo.py @@ -1,7 +1,7 @@ """ -================ -Logit Demo -================ +=========== +Logit scale +=========== Examples of plots with logit axes. """ diff --git a/galleries/examples/scales/scales.py b/galleries/examples/scales/scales.py index 8df4d2fdd4a9..6c4556c9c1d3 100644 --- a/galleries/examples/scales/scales.py +++ b/galleries/examples/scales/scales.py @@ -1,60 +1,46 @@ """ -====== -Scales -====== +=============== +Scales overview +=============== Illustrate the scale transformations applied to axes, e.g. log, symlog, logit. -The last two examples are examples of using the ``'function'`` scale by -supplying forward and inverse functions for the scale transformation. +See `matplotlib.scale` for a full list of built-in scales, and +:doc:`/gallery/scales/custom_scale` for how to create your own scale. """ import matplotlib.pyplot as plt import numpy as np -from matplotlib.ticker import FixedLocator, NullFormatter +x = np.arange(400) +y = np.linspace(0.002, 1, 400) -# Fixing random state for reproducibility -np.random.seed(19680801) - -# make up some data in the interval ]0, 1[ -y = np.random.normal(loc=0.5, scale=0.4, size=1000) -y = y[(y > 0) & (y < 1)] -y.sort() -x = np.arange(len(y)) - -# plot with various axes scales fig, axs = plt.subplots(3, 2, figsize=(6, 8), layout='constrained') -# linear -ax = axs[0, 0] -ax.plot(x, y) -ax.set_yscale('linear') -ax.set_title('linear') -ax.grid(True) - +axs[0, 0].plot(x, y) +axs[0, 0].set_yscale('linear') +axs[0, 0].set_title('linear') +axs[0, 0].grid(True) -# log -ax = axs[0, 1] -ax.plot(x, y) -ax.set_yscale('log') -ax.set_title('log') -ax.grid(True) +axs[0, 1].plot(x, y) +axs[0, 1].set_yscale('log') +axs[0, 1].set_title('log') +axs[0, 1].grid(True) +axs[1, 0].plot(x, y - y.mean()) +axs[1, 0].set_yscale('symlog', linthresh=0.02) +axs[1, 0].set_title('symlog') +axs[1, 0].grid(True) -# symmetric log -ax = axs[1, 1] -ax.plot(x, y - y.mean()) -ax.set_yscale('symlog', linthresh=0.02) -ax.set_title('symlog') -ax.grid(True) +axs[1, 1].plot(x, y) +axs[1, 1].set_yscale('logit') +axs[1, 1].set_title('logit') +axs[1, 1].grid(True) -# logit -ax = axs[1, 0] -ax.plot(x, y) -ax.set_yscale('logit') -ax.set_title('logit') -ax.grid(True) +axs[2, 0].plot(x, y - y.mean()) +axs[2, 0].set_yscale('asinh', linear_width=0.01) +axs[2, 0].set_title('asinh') +axs[2, 0].grid(True) # Function x**(1/2) @@ -66,38 +52,11 @@ def inverse(x): return x**2 -ax = axs[2, 0] -ax.plot(x, y) -ax.set_yscale('function', functions=(forward, inverse)) -ax.set_title('function: $x^{1/2}$') -ax.grid(True) -ax.yaxis.set_major_locator(FixedLocator(np.arange(0, 1, 0.2)**2)) -ax.yaxis.set_major_locator(FixedLocator(np.arange(0, 1, 0.2))) - - -# Function Mercator transform -def forward(a): - a = np.deg2rad(a) - return np.rad2deg(np.log(np.abs(np.tan(a) + 1.0 / np.cos(a)))) - - -def inverse(a): - a = np.deg2rad(a) - return np.rad2deg(np.arctan(np.sinh(a))) - -ax = axs[2, 1] - -t = np.arange(0, 170.0, 0.1) -s = t / 2. - -ax.plot(t, s, '-', lw=2) - -ax.set_yscale('function', functions=(forward, inverse)) -ax.set_title('function: Mercator') -ax.grid(True) -ax.set_xlim([0, 180]) -ax.yaxis.set_minor_formatter(NullFormatter()) -ax.yaxis.set_major_locator(FixedLocator(np.arange(0, 90, 10))) +axs[2, 1].plot(x, y) +axs[2, 1].set_yscale('function', functions=(forward, inverse)) +axs[2, 1].set_title('function: $x^{1/2}$') +axs[2, 1].grid(True) +axs[2, 1].set_yticks(np.arange(0, 1.2, 0.2)) plt.show() @@ -110,7 +69,6 @@ def inverse(a): # # - `matplotlib.axes.Axes.set_xscale` # - `matplotlib.axes.Axes.set_yscale` -# - `matplotlib.axis.Axis.set_major_locator` # - `matplotlib.scale.LinearScale` # - `matplotlib.scale.LogScale` # - `matplotlib.scale.SymmetricalLogScale` diff --git a/galleries/examples/scales/semilogx_demo.py b/galleries/examples/scales/semilogx_demo.py deleted file mode 100644 index 00c708a03479..000000000000 --- a/galleries/examples/scales/semilogx_demo.py +++ /dev/null @@ -1,23 +0,0 @@ -""" -======== -Log Axis -======== - -.. redirect-from:: /gallery/scales/log_test - -This is an example of assigning a log-scale for the x-axis using -`~.axes.Axes.semilogx`. -""" - -import matplotlib.pyplot as plt -import numpy as np - -fig, ax = plt.subplots() - -dt = 0.01 -t = np.arange(dt, 20.0, dt) - -ax.semilogx(t, np.exp(-t / 5.0)) -ax.grid() - -plt.show() diff --git a/galleries/examples/scales/symlog_demo.py b/galleries/examples/scales/symlog_demo.py index e50be0d0c8a8..47742b853cc9 100644 --- a/galleries/examples/scales/symlog_demo.py +++ b/galleries/examples/scales/symlog_demo.py @@ -1,7 +1,12 @@ """ -=========== -Symlog Demo -=========== +============ +Symlog scale +============ + +The symmetric logarithmic scale is an extension of the logarithmic scale that +also covers negative values. As with the logarithmic scale, it is particularly +useful for numerical data that spans a broad range of values, especially when there +are significant differences between the magnitudes of the numbers involved. Example use of symlog (symmetric log) axis scaling. """ @@ -34,12 +39,82 @@ plt.show() # %% -# It should be noted that the coordinate transform used by ``symlog`` -# has a discontinuous gradient at the transition between its linear -# and logarithmic regions. The ``asinh`` axis scale is an alternative -# technique that may avoid visual artifacts caused by these discontinuities. +# Linear threshold +# ---------------- +# Since each decade on a logarithmic scale covers the same amount of visual space +# and there are infinitely many decades between a given number and zero, the symlog +# scale must deviate from logarithmic mapping in a small range +# *(-linthresh, linthresh)*, so that the range is mapped to a finite visual space. + + +def format_axes(ax, title=None): + """A helper function to better visualize properties of the symlog scale.""" + ax.xaxis.get_minor_locator().set_params(subs=[2, 3, 4, 5, 6, 7, 8, 9]) + ax.grid() + ax.xaxis.grid(which='minor') # minor grid on too + linthresh = ax.xaxis.get_transform().linthresh + linscale = ax.xaxis.get_transform().linscale + ax.axvspan(-linthresh, linthresh, color='0.9') + if title: + ax.set_title(title.format(linthresh=linthresh, linscale=linscale)) + + +x = np.linspace(-60, 60, 201) +y = np.linspace(0, 100.0, 201) + +fig, (ax1, ax2) = plt.subplots(nrows=2, layout="constrained") + +ax1.plot(x, y) +ax1.set_xscale('symlog', linthresh=1) +format_axes(ax1, title='Linear region: linthresh={linthresh}') + +ax2.plot(x, y) +ax2.set_xscale('symlog', linthresh=5) +format_axes(ax2, title='Linear region: linthresh={linthresh}') + +# %% +# Generally, *linthresh* should be chosen so that no or only a few +# data points are in the linear region. As a rule of thumb, +# :math:`linthresh \approx \mathrm{min} |x|`. +# +# +# Linear scale +# ------------ +# Additionally, the *linscale* parameter determines how much visual space should be +# used for the linear range. More precisely, it defines the ratio of visual space +# of the region (0, linthresh) relative to one decade. + +fig, (ax1, ax2) = plt.subplots(nrows=2, layout="constrained") + +ax1.plot(x, y) +ax1.set_xscale('symlog', linthresh=1) +format_axes(ax1, title='Linear region: linthresh={linthresh}, linscale={linscale}') + +ax2.plot(x, y) +ax2.set_xscale('symlog', linthresh=1, linscale=0.1) +format_axes(ax2, title='Linear region: linthresh={linthresh}, linscale={linscale}') # %% +# The suitable value for linscale depends on the dynamic range of data. As most data +# will be outside the linear region, you typically the linear region only to cover +# a small fraction of the visual area. +# +# Limitations and alternatives +# ---------------------------- +# The coordinate transform used by ``symlog`` has a discontinuous gradient at the +# transition between its linear and logarithmic regions. Depending on data and +# scaling, this will be more or less obvious in the plot. + +fig, ax = plt.subplots() +ax.plot(x, y) +ax.set_xscale('symlog', linscale=0.05) +format_axes(ax, title="Discontinuous gradient at linear/log transition") + +# %% +# The ``asinh`` axis scale is an alternative transformation that supports a wide +# dynamic range with a smooth gradient and thus may avoid such visual artifacts. +# See :doc:`/gallery/scales/asinh_demo`. +# # # .. admonition:: References # diff --git a/galleries/examples/style_sheets/plot_solarizedlight2.py b/galleries/examples/style_sheets/plot_solarizedlight2.py index c1d37422216a..a6434f5ef04a 100644 --- a/galleries/examples/style_sheets/plot_solarizedlight2.py +++ b/galleries/examples/style_sheets/plot_solarizedlight2.py @@ -32,7 +32,7 @@ plt.plot(x, np.sin(x) + x + np.random.randn(50)) plt.plot(x, np.sin(x) + 2 * x + np.random.randn(50)) plt.plot(x, np.sin(x) + 3 * x + np.random.randn(50)) - plt.plot(x, np.sin(x) + 4 + np.random.randn(50)) + plt.plot(x, np.sin(x) + 4 * x + np.random.randn(50)) plt.plot(x, np.sin(x) + 5 * x + np.random.randn(50)) plt.plot(x, np.sin(x) + 6 * x + np.random.randn(50)) plt.plot(x, np.sin(x) + 7 * x + np.random.randn(50)) diff --git a/galleries/examples/userdemo/demo_gridspec03.py b/galleries/examples/subplots_axes_and_figures/gridspec_customization.py similarity index 88% rename from galleries/examples/userdemo/demo_gridspec03.py rename to galleries/examples/subplots_axes_and_figures/gridspec_customization.py index 63951ef7d563..08b2dfd45474 100644 --- a/galleries/examples/userdemo/demo_gridspec03.py +++ b/galleries/examples/subplots_axes_and_figures/gridspec_customization.py @@ -1,13 +1,15 @@ """ -============= -GridSpec demo -============= +======================================== +GridSpec with variable sizes and spacing +======================================== This example demonstrates the use of `.GridSpec` to generate subplots, the control of the relative sizes of subplots with *width_ratios* and *height_ratios*, and the control of the spacing around and between subplots using subplot params (*left*, *right*, *bottom*, *top*, *wspace*, and *hspace*). + +.. redirect-from:: /gallery/userdemo/demo_gridspec03 """ import matplotlib.pyplot as plt diff --git a/galleries/examples/userdemo/demo_gridspec01.py b/galleries/examples/subplots_axes_and_figures/subplot2grid.py similarity index 77% rename from galleries/examples/userdemo/demo_gridspec01.py rename to galleries/examples/subplots_axes_and_figures/subplot2grid.py index 7153b136f080..cd500ccf65b2 100644 --- a/galleries/examples/userdemo/demo_gridspec01.py +++ b/galleries/examples/subplots_axes_and_figures/subplot2grid.py @@ -1,11 +1,14 @@ """ -================= -subplot2grid demo -================= +============ +subplot2grid +============ This example demonstrates the use of `.pyplot.subplot2grid` to generate subplots. Using `.GridSpec`, as demonstrated in -:doc:`/gallery/userdemo/demo_gridspec03` is generally preferred. +:doc:`/gallery/subplots_axes_and_figures/gridspec_customization` is +generally preferred. + +.. redirect-from:: /gallery/userdemo/demo_gridspec01 """ import matplotlib.pyplot as plt diff --git a/galleries/examples/text_labels_and_annotations/figlegend_demo.py b/galleries/examples/text_labels_and_annotations/figlegend_demo.py index f6f74b837c10..50b3eeabc085 100644 --- a/galleries/examples/text_labels_and_annotations/figlegend_demo.py +++ b/galleries/examples/text_labels_and_annotations/figlegend_demo.py @@ -3,51 +3,25 @@ Figure legend demo ================== -Instead of plotting a legend on each axis, a legend for all the artists on all -the sub-axes of a figure can be plotted instead. +Rather than plotting a legend on each axis, a legend for all the artists +on all the sub-axes of a figure can be plotted instead. """ import matplotlib.pyplot as plt import numpy as np -fig, axs = plt.subplots(1, 2) - -x = np.arange(0.0, 2.0, 0.02) -y1 = np.sin(2 * np.pi * x) -y2 = np.exp(-x) -l1, = axs[0].plot(x, y1) -l2, = axs[0].plot(x, y2, marker='o') +fig, axs = plt.subplots(1, 2, layout='constrained') -y3 = np.sin(4 * np.pi * x) -y4 = np.exp(-2 * x) -l3, = axs[1].plot(x, y3, color='tab:green') -l4, = axs[1].plot(x, y4, color='tab:red', marker='^') +x = np.arange(0.0, 4*np.pi, 0.2) +axs[0].plot(x, np.sin(x), label='Line 1') +axs[0].plot(x, np.exp(-x/2), marker='o', label='Line 2') +axs[1].plot(x, np.sin(x), color='tab:green', label='Line 3') +axs[1].plot(x, np.exp(-x/4), color='tab:red', marker='^', label='Line 4') -fig.legend((l1, l2), ('Line 1', 'Line 2'), loc='upper left') -fig.legend((l3, l4), ('Line 3', 'Line 4'), loc='upper right') +fig.legend(loc='outside right upper') -plt.tight_layout() plt.show() # %% -# Sometimes we do not want the legend to overlap the Axes. If you use -# *constrained layout* you can specify "outside right upper", and -# *constrained layout* will make room for the legend. - -fig, axs = plt.subplots(1, 2, layout='constrained') - -x = np.arange(0.0, 2.0, 0.02) -y1 = np.sin(2 * np.pi * x) -y2 = np.exp(-x) -l1, = axs[0].plot(x, y1) -l2, = axs[0].plot(x, y2, marker='o') - -y3 = np.sin(4 * np.pi * x) -y4 = np.exp(-2 * x) -l3, = axs[1].plot(x, y3, color='tab:green') -l4, = axs[1].plot(x, y4, color='tab:red', marker='^') - -fig.legend((l1, l2), ('Line 1', 'Line 2'), loc='upper left') -fig.legend((l3, l4), ('Line 3', 'Line 4'), loc='outside right upper') - -plt.show() +# The outside positioning is discussed in detail here: +# https://matplotlib.org/stable/users/explain/axes/legend_guide.html#figure-legends diff --git a/galleries/examples/text_labels_and_annotations/text_rotation_relative_to_line.py b/galleries/examples/text_labels_and_annotations/text_rotation_relative_to_line.py index ae29385e8a6d..78bc9a647af9 100644 --- a/galleries/examples/text_labels_and_annotations/text_rotation_relative_to_line.py +++ b/galleries/examples/text_labels_and_annotations/text_rotation_relative_to_line.py @@ -15,28 +15,18 @@ """ import matplotlib.pyplot as plt -import numpy as np fig, ax = plt.subplots() -# Plot diagonal line (45 degrees) -h = ax.plot(range(0, 10), range(0, 10)) - -# set limits so that it no longer looks on screen to be 45 degrees -ax.set_xlim([-10, 20]) - -# Locations to plot text -l1 = np.array((1, 1)) -l2 = np.array((5, 5)) - -# Rotate angle -angle = 45 +# Plot diagonal line (45 degrees in data coordinates) +ax.plot(range(0, 8), range(0, 8)) +ax.set_xlim([-10, 10]) # Plot text -th1 = ax.text(*l1, 'text not rotated correctly', fontsize=16, - rotation=angle, rotation_mode='anchor') -th2 = ax.text(*l2, 'text rotated correctly', fontsize=16, - rotation=angle, rotation_mode='anchor', - transform_rotates_text=True) +ax.text(-8, 0, 'text 45° in screen coordinates', fontsize=18, + rotation=45, rotation_mode='anchor') +ax.text(0, 0, 'text 45° in data coordinates', fontsize=18, + rotation=45, rotation_mode='anchor', + transform_rotates_text=True) plt.show() diff --git a/galleries/examples/units/basic_units.py b/galleries/examples/units/basic_units.py index 3f64d145b65e..486918a8eafc 100644 --- a/galleries/examples/units/basic_units.py +++ b/galleries/examples/units/basic_units.py @@ -193,6 +193,11 @@ def get_unit(self): class BasicUnit: + # numpy scalars convert eager and np.float64(2) * BasicUnit('cm') + # would thus return a numpy scalar. To avoid this, we increase the + # priority of the BasicUnit. + __array_priority__ = np.float64(0).__array_priority__ + 1 + def __init__(self, name, fullname=None): self.name = name if fullname is None: diff --git a/galleries/users_explain/artists/transforms_tutorial.py b/galleries/users_explain/artists/transforms_tutorial.py index 0be5fa3c2e21..f8a3e98e8077 100644 --- a/galleries/users_explain/artists/transforms_tutorial.py +++ b/galleries/users_explain/artists/transforms_tutorial.py @@ -28,37 +28,37 @@ |Coordinate |Description |Transformation object | |system | |from system to display | +================+===================================+=============================+ -|"data" |The coordinate system of the data |``ax.transData`` | +|*data* |The coordinate system of the data |``ax.transData`` | | |in the Axes. | | +----------------+-----------------------------------+-----------------------------+ -|"axes" |The coordinate system of the |``ax.transAxes`` | +|*axes* |The coordinate system of the |``ax.transAxes`` | | |`~matplotlib.axes.Axes`; (0, 0) | | | |is bottom left of the Axes, and | | | |(1, 1) is top right of the Axes. | | +----------------+-----------------------------------+-----------------------------+ -|"subfigure" |The coordinate system of the |``subfigure.transSubfigure`` | +|*subfigure* |The coordinate system of the |``subfigure.transSubfigure`` | | |`.SubFigure`; (0, 0) is bottom left| | | |of the subfigure, and (1, 1) is top| | | |right of the subfigure. If a | | | |figure has no subfigures, this is | | | |the same as ``transFigure``. | | +----------------+-----------------------------------+-----------------------------+ -|"figure" |The coordinate system of the |``fig.transFigure`` | +|*figure* |The coordinate system of the |``fig.transFigure`` | | |`.Figure`; (0, 0) is bottom left | | | |of the figure, and (1, 1) is top | | | |right of the figure. | | +----------------+-----------------------------------+-----------------------------+ -|"figure-inches" |The coordinate system of the |``fig.dpi_scale_trans`` | +|*figure-inches* |The coordinate system of the |``fig.dpi_scale_trans`` | | |`.Figure` in inches; (0, 0) is | | | |bottom left of the figure, and | | | |(width, height) is the top right | | | |of the figure in inches. | | +----------------+-----------------------------------+-----------------------------+ -|"xaxis", |Blended coordinate systems, using |``ax.get_xaxis_transform()``,| -|"yaxis" |data coordinates on one direction |``ax.get_yaxis_transform()`` | +|*xaxis*, |Blended coordinate systems, using |``ax.get_xaxis_transform()``,| +|*yaxis* |data coordinates on one direction |``ax.get_yaxis_transform()`` | | |and axes coordinates on the other. | | +----------------+-----------------------------------+-----------------------------+ -|"display" |The native coordinate system of the|`None`, or | +|*display* |The native coordinate system of the|`None`, or | | |output ; (0, 0) is the bottom left |`.IdentityTransform()` | | |of the window, and (width, height) | | | |is top right of the output in | | diff --git a/galleries/users_explain/axes/constrainedlayout_guide.py b/galleries/users_explain/axes/constrainedlayout_guide.py index d96b829df372..4697d82ba6a6 100644 --- a/galleries/users_explain/axes/constrainedlayout_guide.py +++ b/galleries/users_explain/axes/constrainedlayout_guide.py @@ -532,7 +532,7 @@ def example_plot(ax, fontsize=12, hide_labels=False): example_plot(ax1) example_plot(ax2) example_plot(ax3) -plt.suptitle('Homogenous nrows, ncols') +plt.suptitle('Homogeneous nrows, ncols') # %% # but the following leads to a poor layout: diff --git a/galleries/users_explain/axes/tight_layout_guide.py b/galleries/users_explain/axes/tight_layout_guide.py index dcffa7437b94..455bb57de126 100644 --- a/galleries/users_explain/axes/tight_layout_guide.py +++ b/galleries/users_explain/axes/tight_layout_guide.py @@ -165,6 +165,10 @@ def example_plot(ax, fontsize=12): # a limitation of the current algorithm, and it is not clear why it # happens. Meanwhile, use of pad larger than 0.3 is recommended. # +# * The algorithm of ``tight_layout`` does not necessarily converge, +# i.e. calling ``tight_layout`` multiple times can lead to slight +# variations in the layout between the calls. +# # Use with GridSpec # ================= # diff --git a/galleries/users_explain/colors/colormaps.py b/galleries/users_explain/colors/colormaps.py index ff146cacf170..026ffc9922e2 100644 --- a/galleries/users_explain/colors/colormaps.py +++ b/galleries/users_explain/colors/colormaps.py @@ -178,7 +178,7 @@ def plot_color_gradients(category, cmap_list): # # Berlin, Managua, and Vanimo are dark-mode diverging colormaps, with minimum # lightness at the center, and maximum at the extremes. These are taken from -# F. Crameri's [scientific colour maps]_ version 8.0.1. +# F. Crameri's [scientific-colour-maps]_ version 8.0.1. plot_color_gradients('Diverging', ['PiYG', 'PRGn', 'BrBG', 'PuOr', 'RdGy', 'RdBu', 'RdYlBu', @@ -446,4 +446,4 @@ def plot_color_gradients(cmap_category, cmap_list): # .. [colorblindness] http://www.color-blindness.com/ # .. [IBM] https://doi.org/10.1109/VISUAL.1995.480803 # .. [turbo] https://ai.googleblog.com/2019/08/turbo-improved-rainbow-colormap-for.html -# .. [scientific colour maps] https://doi.org/10.5281/zenodo.1243862 +# .. [scientific-colour-maps] https://doi.org/10.5281/zenodo.1243862 diff --git a/galleries/users_explain/figure/interactive_guide.rst b/galleries/users_explain/figure/interactive_guide.rst index b08231e84f7e..5cc55edc0955 100644 --- a/galleries/users_explain/figure/interactive_guide.rst +++ b/galleries/users_explain/figure/interactive_guide.rst @@ -11,7 +11,7 @@ Interactive figures and asynchronous programming Matplotlib supports rich interactive figures by embedding figures into a GUI window. The basic interactions of panning and zooming in an -Axes to inspect your data is 'baked in' to Matplotlib. This is +Axes to inspect your data is "baked in" to Matplotlib. This is supported by a full mouse and keyboard event handling system that you can use to build sophisticated interactive graphs. @@ -54,7 +54,7 @@ user hits the 'z' key, please run this other function". This allows users to write reactive, event-driven, programs without having to delve into the nitty-gritty [#f3]_ details of I/O. The core event loop is sometimes referred to as "the main loop" and is typically started, -depending on the library, by methods with names like ``_exec``, +depending on the library, by methods with names like ``exec``, ``run``, or ``start``. @@ -83,7 +83,7 @@ for user input and lets us register functions to be run when that happens. However, if we want to do both we have a problem: the prompt and the GUI event loop are both infinite loops that each think *they* are in charge! In order for both the prompt and the GUI windows to be -responsive we need a method to allow the loops to 'timeshare' : +responsive we need a method to allow the loops to "timeshare" : 1. let the GUI main loop block the python process when you want interactive windows @@ -109,7 +109,7 @@ Blocking the prompt The simplest "integration" is to start the GUI event loop in -'blocking' mode and take over the CLI. While the GUI event loop is +"blocking" mode and take over the CLI. While the GUI event loop is running you cannot enter new commands into the prompt (your terminal may echo the characters typed into the terminal, but they will not be sent to the Python interpreter because it is busy running the GUI @@ -147,7 +147,7 @@ While running the GUI event loop in a blocking mode or explicitly handling UI events is useful, we can do better! We really want to be able to have a usable prompt **and** interactive figure windows. -We can do this using the 'input hook' feature of the interactive +We can do this using the "input hook" feature of the interactive prompt. This hook is called by the prompt as it waits for the user to type (even for a fast typist the prompt is mostly waiting for the human to think and move their fingers). Although the details vary @@ -386,8 +386,8 @@ sure that you are locking in the critical sections. -Eventloop integration mechanism -=============================== +Event loop integration mechanism +================================ CPython / readline ------------------ @@ -404,7 +404,7 @@ run the event loop until a key is pressed on stdin. Matplotlib does not currently do any management of :c:data:`PyOS_InputHook` due to the wide range of ways that Matplotlib is used. This management is left to downstream libraries -- either user code or the shell. Interactive figures, -even with Matplotlib in 'interactive mode', may not work in the vanilla python +even with Matplotlib in "interactive mode", may not work in the vanilla python repl if an appropriate :c:data:`PyOS_InputHook` is not registered. Input hooks, and helpers to install them, are usually included with @@ -433,9 +433,9 @@ method. The source for the ``prompt_toolkit`` input hooks lives at then the loop would look something like :: fds = [...] - while True: # Loop - inp = select(fds).read() # Read - eval(inp) # Evaluate / Print + while True: # Loop + inp = select(fds).read() # Read + eval(inp) # Evaluate / Print .. [#f2] Or you can `write your own `__ if you must. diff --git a/lib/matplotlib/_enums.py b/lib/matplotlib/_enums.py index 773011d36bf6..75a09b7b5d8c 100644 --- a/lib/matplotlib/_enums.py +++ b/lib/matplotlib/_enums.py @@ -10,21 +10,11 @@ they define. """ -from enum import Enum, auto +from enum import Enum from matplotlib import _docstring -class _AutoStringNameEnum(Enum): - """Automate the ``name = 'name'`` part of making a (str, Enum).""" - - def _generate_next_value_(name, start, count, last_values): - return name - - def __hash__(self): - return str(self).__hash__() - - -class JoinStyle(str, _AutoStringNameEnum): +class JoinStyle(str, Enum): """ Define how the connection between two line segments is drawn. @@ -79,9 +69,9 @@ class JoinStyle(str, _AutoStringNameEnum): """ - miter = auto() - round = auto() - bevel = auto() + miter = "miter" + round = "round" + bevel = "bevel" @staticmethod def demo(): @@ -116,7 +106,7 @@ def plot_angle(ax, x, y, angle, style): + "}" -class CapStyle(str, _AutoStringNameEnum): +class CapStyle(str, Enum): r""" Define how the two endpoints (caps) of an unclosed line are drawn. @@ -151,9 +141,9 @@ class CapStyle(str, _AutoStringNameEnum): CapStyle.demo() """ - butt = auto() - projecting = auto() - round = auto() + butt = "butt" + projecting = "projecting" + round = "round" @staticmethod def demo(): diff --git a/lib/matplotlib/_enums.pyi b/lib/matplotlib/_enums.pyi index 351088b36453..714e6cfe03fa 100644 --- a/lib/matplotlib/_enums.pyi +++ b/lib/matplotlib/_enums.pyi @@ -1,18 +1,19 @@ +from typing import cast from enum import Enum -class _AutoStringNameEnum(Enum): - def __hash__(self) -> int: ... -class JoinStyle(str, _AutoStringNameEnum): - miter: str - round: str - bevel: str +class JoinStyle(str, Enum): + miter = "miter" + round = "round" + bevel = "bevel" @staticmethod def demo() -> None: ... -class CapStyle(str, _AutoStringNameEnum): - butt: str - projecting: str - round: str + +class CapStyle(str, Enum): + butt = "butt" + projecting = "projecting" + round = "round" + @staticmethod def demo() -> None: ... diff --git a/lib/matplotlib/animation.py b/lib/matplotlib/animation.py index 2be61284073a..a87f00201124 100644 --- a/lib/matplotlib/animation.py +++ b/lib/matplotlib/animation.py @@ -496,7 +496,7 @@ def grab_frame(self, **savefig_kwargs): "RGBA", self.frame_size, buf.getbuffer(), "raw", "RGBA", 0, 1) if im.getextrema()[3][0] < 255: # This frame has transparency, so we'll just add it as is. - self._frame.append(im) + self._frames.append(im) else: # Without transparency, we switch to RGB mode, which converts to P mode a # little better if needed (specifically, this helps with GIF output.) diff --git a/lib/matplotlib/artist.py b/lib/matplotlib/artist.py index 17724c8b027a..c87c789048c4 100644 --- a/lib/matplotlib/artist.py +++ b/lib/matplotlib/artist.py @@ -1016,7 +1016,7 @@ def set_alpha(self, alpha): Parameters ---------- - alpha : scalar or None + alpha : float or None *alpha* must be within the 0-1 range, inclusive. """ if alpha is not None and not isinstance(alpha, Real): @@ -1035,7 +1035,7 @@ def _set_alpha_for_array(self, alpha): Parameters ---------- - alpha : array-like or scalar or None + alpha : array-like or float or None All values must be within the 0-1 range, inclusive. Masked values and nans are not supported. """ diff --git a/lib/matplotlib/axes/_axes.py b/lib/matplotlib/axes/_axes.py index 679499a4eab3..eebbdcaed459 100644 --- a/lib/matplotlib/axes/_axes.py +++ b/lib/matplotlib/axes/_axes.py @@ -823,7 +823,7 @@ def axvline(self, x=0, ymin=0, ymax=1, **kwargs): Parameters ---------- x : float, default: 0 - y position in :ref:`data coordinates `. + x position in :ref:`data coordinates `. ymin : float, default: 0 The start y-position in :ref:`axes coordinates `. @@ -1618,7 +1618,7 @@ def plot(self, *args, scalex=True, scaley=True, data=None, **kwargs): Parameters ---------- - x, y : array-like or scalar + x, y : array-like or float The horizontal / vertical coordinates of the data points. *x* values are optional and default to ``range(len(y))``. @@ -2391,6 +2391,17 @@ def bar(self, x, height, width=0.8, bottom=None, *, align="center", The x coordinates of the bars. See also *align* for the alignment of the bars to the coordinates. + Bars are often used for categorical data, i.e. string labels below + the bars. You can provide a list of strings directly to *x*. + ``bar(['A', 'B', 'C'], [1, 2, 3])`` is often a shorter and more + convenient notation compared to + ``bar(range(3), [1, 2, 3], tick_label=['A', 'B', 'C'])``. They are + equivalent as long as the names are unique. The explicit *tick_label* + notation draws the names in the sequence given. However, when having + duplicate values in categorical *x* data, these values map to the same + numerical x coordinate, and hence the corresponding bars are drawn on + top of each other. + height : float or array-like The height(s) of the bars. @@ -2706,6 +2717,17 @@ def barh(self, y, width, height=0.8, left=None, *, align="center", The y coordinates of the bars. See also *align* for the alignment of the bars to the coordinates. + Bars are often used for categorical data, i.e. string labels below + the bars. You can provide a list of strings directly to *y*. + ``barh(['A', 'B', 'C'], [1, 2, 3])`` is often a shorter and more + convenient notation compared to + ``barh(range(3), [1, 2, 3], tick_label=['A', 'B', 'C'])``. They are + equivalent as long as the names are unique. The explicit *tick_label* + notation draws the names in the sequence given. However, when having + duplicate values in categorical *y* data, these values map to the same + numerical y coordinate, and hence the corresponding bars are drawn on + top of each other. + width : float or array-like The width(s) of the bars. @@ -3861,7 +3883,7 @@ def apply_mask(arrays, mask): (data_line, tuple(caplines), tuple(barcols)), has_xerr=(xerr is not None), has_yerr=(yerr is not None), label=label) - self.containers.append(errorbar_container) + self.add_container(errorbar_container) return errorbar_container # (l0, caplines, barcols) @@ -4250,13 +4272,13 @@ def bxp(self, bxpstats, positions=None, widths=None, vert=None, A list of dictionaries containing stats for each boxplot. Required keys are: - - ``med``: Median (scalar). - - ``q1``, ``q3``: First & third quartiles (scalars). - - ``whislo``, ``whishi``: Lower & upper whisker positions (scalars). + - ``med``: Median (float). + - ``q1``, ``q3``: First & third quartiles (float). + - ``whislo``, ``whishi``: Lower & upper whisker positions (float). Optional keys are: - - ``mean``: Mean (scalar). Needed if ``showmeans=True``. + - ``mean``: Mean (float). Needed if ``showmeans=True``. - ``fliers``: Data beyond the whiskers (array-like). Needed if ``showfliers=True``. - ``cilo``, ``cihi``: Lower & upper confidence intervals @@ -4675,6 +4697,14 @@ def _parse_scatter_color_args(c, edgecolors, kwargs, xsize, if edgecolors is None and not mpl.rcParams['_internal.classic_mode']: edgecolors = mpl.rcParams['scatter.edgecolors'] + # Raise a warning if both `c` and `facecolor` are set (issue #24404). + if c is not None and facecolors is not None: + _api.warn_external( + "You passed both c and facecolor/facecolors for the markers. " + "c has precedence over facecolor/facecolors. " + "This behavior may change in the future." + ) + c_was_none = c is None if c is None: c = (facecolors if facecolors is not None @@ -5441,10 +5471,22 @@ def on_changed(collection): @_docstring.interpd def arrow(self, x, y, dx, dy, **kwargs): """ - Add an arrow to the Axes. + [*Discouraged*] Add an arrow to the Axes. This draws an arrow from ``(x, y)`` to ``(x+dx, y+dy)``. + .. admonition:: Discouraged + + The use of this method is discouraged because it is not guaranteed + that the arrow renders reasonably. For example, the resulting arrow + is affected by the Axes aspect ratio and limits, which may distort + the arrow. + + Consider using `~.Axes.annotate` without a text instead, e.g. :: + + ax.annotate("", xytext=(0, 0), xy=(0.5, 0.5), + arrowprops=dict(arrowstyle="->")) + Parameters ---------- %(FancyArrow)s @@ -5453,17 +5495,6 @@ def arrow(self, x, y, dx, dy, **kwargs): ------- `.FancyArrow` The created `.FancyArrow` object. - - Notes - ----- - The resulting arrow is affected by the Axes aspect ratio and limits. - This may produce an arrow whose head is not square with its stem. To - create an arrow whose head is square with its stem, - use :meth:`annotate` for example: - - >>> ax.annotate("", xy=(0.5, 0.5), xytext=(0, 0), - ... arrowprops=dict(arrowstyle="->")) - """ # Strip away units for the underlying patch since units # do not make sense to most patch-like code @@ -5591,16 +5622,16 @@ def _fill_between_x_or_y( Parameters ---------- - {ind} : array (length N) + {ind} : array-like The {ind} coordinates of the nodes defining the curves. - {dep}1 : array (length N) or scalar + {dep}1 : array-like or float The {dep} coordinates of the nodes defining the first curve. - {dep}2 : array (length N) or scalar, default: 0 + {dep}2 : array-like or float, default: 0 The {dep} coordinates of the nodes defining the second curve. - where : array of bool (length N), optional + where : array-like of bool, optional Define *where* to exclude some {dir} regions from being filled. The filled regions are defined by the coordinates ``{ind}[where]``. More precisely, fill between ``{ind}[i]`` and ``{ind}[i+1]`` if @@ -6883,7 +6914,7 @@ def hist(self, x, bins=None, range=None, density=False, weights=None, ``True``, then the histogram is normalized such that the first bin equals 1. - bottom : array-like, scalar, or None, default: None + bottom : array-like or float, default: 0 Location of the bottom of each bin, i.e. bins are drawn from ``bottom`` to ``bottom + hist(x, bins)`` If a scalar, the bottom of each bin is shifted by the same amount. If an array, each bin diff --git a/lib/matplotlib/axes/_base.py b/lib/matplotlib/axes/_base.py index 4c5b18e9e843..61d67d2791b4 100644 --- a/lib/matplotlib/axes/_base.py +++ b/lib/matplotlib/axes/_base.py @@ -566,6 +566,36 @@ class _AxesBase(martist.Artist): dataLim: mtransforms.Bbox """The bounding `.Bbox` enclosing all data displayed in the Axes.""" + xaxis: maxis.XAxis + """ + The `.XAxis` instance. + + Common axis-related configuration can be achieved through high-level wrapper + methods on Axes; e.g. `ax.set_xticks <.Axes.set_xticks>` is a shortcut for + `ax.xaxis.set_ticks <.Axis.set_ticks>`. The *xaxis* attribute gives direct + direct access to the underlying `~.axis.Axis` if you need more control. + + See also + + - :ref:`Axis wrapper methods on Axes ` + - :doc:`Axis API ` + """ + + yaxis: maxis.YAxis + """ + The `.YAxis` instance. + + Common axis-related configuration can be achieved through high-level wrapper + methods on Axes; e.g. `ax.set_yticks <.Axes.set_yticks>` is a shortcut for + `ax.yaxis.set_ticks <.Axis.set_ticks>`. The *yaxis* attribute gives direct + access to the underlying `~.axis.Axis` if you need more control. + + See also + + - :ref:`Axis wrapper methods on Axes ` + - :doc:`Axis API ` + """ + @property def _axis_map(self): """A mapping of axis names, e.g. 'x', to `Axis` instances.""" @@ -648,7 +678,7 @@ def __init__(self, fig, args = (rect,) subplotspec = None if len(args) == 1 and isinstance(args[0], mtransforms.Bbox): - self._position = args[0] + self._position = args[0].frozen() elif len(args) == 1 and np.iterable(args[0]): self._position = mtransforms.Bbox.from_bounds(*args[0]) else: @@ -2218,7 +2248,7 @@ def get_xaxis(self): .. admonition:: Discouraged The use of this function is discouraged. You should instead - directly access the attribute ``ax.xaxis``. + directly access the attribute `~.Axes.xaxis`. """ return self.xaxis @@ -2229,7 +2259,7 @@ def get_yaxis(self): .. admonition:: Discouraged The use of this function is discouraged. You should instead - directly access the attribute ``ax.yaxis``. + directly access the attribute `~.Axes.yaxis`. """ return self.yaxis @@ -3071,9 +3101,8 @@ def _update_title_position(self, renderer): top = -np.inf for ax in axs: bb = None - xticklabel_top = any(tick.label2.get_visible() for tick in - [ax.xaxis.majorTicks[0], ax.xaxis.minorTicks[0]]) - if (xticklabel_top or ax.xaxis.get_label_position() == 'top'): + if (ax.xaxis.get_ticks_position() in ['top', 'unknown'] or + ax.xaxis.get_label_position() == 'top'): bb = ax.xaxis.get_tightbbox(renderer) if bb is None: # Extent of the outline for colorbars, of the axes otherwise. diff --git a/lib/matplotlib/axis.py b/lib/matplotlib/axis.py index 56eeb0e4169b..714fb08f55be 100644 --- a/lib/matplotlib/axis.py +++ b/lib/matplotlib/axis.py @@ -777,26 +777,15 @@ def _set_axes_scale(self, value, **kwargs): Parameters ---------- - value : {"linear", "log", "symlog", "logit", ...} or `.ScaleBase` - The axis scale type to apply. + value : str or `.ScaleBase` + The axis scale type to apply. Valid string values are the names of scale + classes ("linear", "log", "function",...). These may be the names of any + of the :ref:`built-in scales` or of any custom scales + registered using `matplotlib.scale.register_scale`. **kwargs - Different keyword arguments are accepted, depending on the scale. - See the respective class keyword arguments: - - - `matplotlib.scale.LinearScale` - - `matplotlib.scale.LogScale` - - `matplotlib.scale.SymmetricalLogScale` - - `matplotlib.scale.LogitScale` - - `matplotlib.scale.FuncScale` - - `matplotlib.scale.AsinhScale` - - Notes - ----- - By default, Matplotlib supports the above-mentioned scales. - Additionally, custom scales may be registered using - `matplotlib.scale.register_scale`. These scales can then also - be used here. + If *value* is a string, keywords are passed to the instantiation method of + the respective class. """ name = self._get_axis_name() old_default_lims = (self.get_major_locator() diff --git a/lib/matplotlib/backend_bases.py b/lib/matplotlib/backend_bases.py index d39fc0a1288b..0843796bad5a 100644 --- a/lib/matplotlib/backend_bases.py +++ b/lib/matplotlib/backend_bases.py @@ -428,11 +428,11 @@ def draw_image(self, gc, x, y, im, transform=None): gc : `.GraphicsContextBase` A graphics context with clipping information. - x : scalar + x : float The distance in physical units (i.e., dots or pixels) from the left hand side of the canvas. - y : scalar + y : float The distance in physical units (i.e., dots or pixels) from the bottom side of the canvas. diff --git a/lib/matplotlib/backend_bases.pyi b/lib/matplotlib/backend_bases.pyi index 8089bb49e597..23a19b79d3be 100644 --- a/lib/matplotlib/backend_bases.pyi +++ b/lib/matplotlib/backend_bases.pyi @@ -236,11 +236,11 @@ class LocationEvent(Event): ) -> None: ... class MouseButton(IntEnum): - LEFT: int - MIDDLE: int - RIGHT: int - BACK: int - FORWARD: int + LEFT = 1 + MIDDLE = 2 + RIGHT = 3 + BACK = 8 + FORWARD = 9 class MouseEvent(LocationEvent): button: MouseButton | Literal["up", "down"] | None @@ -398,9 +398,9 @@ class FigureManagerBase: cursors = Cursors class _Mode(str, Enum): - NONE: str - PAN: str - ZOOM: str + NONE = "" + PAN = "pan/zoom" + ZOOM = "zoom rect" class NavigationToolbar2: toolitems: tuple[tuple[str, ...] | tuple[None, ...], ...] diff --git a/lib/matplotlib/backend_tools.pyi b/lib/matplotlib/backend_tools.pyi index f86a207c7545..32fe8c2f5a79 100644 --- a/lib/matplotlib/backend_tools.pyi +++ b/lib/matplotlib/backend_tools.pyi @@ -6,16 +6,16 @@ from matplotlib.backend_managers import ToolManager, ToolEvent from matplotlib.figure import Figure from matplotlib.scale import ScaleBase -from typing import Any +from typing import Any, cast class Cursors(enum.IntEnum): - POINTER: int - HAND: int - SELECT_REGION: int - MOVE: int - WAIT: int - RESIZE_HORIZONTAL: int - RESIZE_VERTICAL: int + POINTER = cast(int, ...) + HAND = cast(int, ...) + SELECT_REGION = cast(int, ...) + MOVE = cast(int, ...) + WAIT = cast(int, ...) + RESIZE_HORIZONTAL = cast(int, ...) + RESIZE_VERTICAL = cast(int, ...) cursors = Cursors diff --git a/lib/matplotlib/backends/backend_gtk4.py b/lib/matplotlib/backends/backend_gtk4.py index 6af301c2becb..620c9e5b94b6 100644 --- a/lib/matplotlib/backends/backend_gtk4.py +++ b/lib/matplotlib/backends/backend_gtk4.py @@ -29,6 +29,8 @@ TimerGTK as TimerGTK4, ) +_GOBJECT_GE_3_47 = gi.version_info >= (3, 47, 0) + class FigureCanvasGTK4(_FigureCanvasGTK, Gtk.DrawingArea): required_interactive_framework = "gtk4" @@ -115,7 +117,7 @@ def scroll_event(self, controller, dx, dy): MouseEvent( "scroll_event", self, *self._mpl_coords(), step=dy, modifiers=self._mpl_modifiers(controller), - guiEvent=controller.get_current_event(), + guiEvent=controller.get_current_event() if _GOBJECT_GE_3_47 else None, )._process() return True @@ -124,7 +126,7 @@ def button_press_event(self, controller, n_press, x, y): "button_press_event", self, *self._mpl_coords((x, y)), controller.get_current_button(), modifiers=self._mpl_modifiers(controller), - guiEvent=controller.get_current_event(), + guiEvent=controller.get_current_event() if _GOBJECT_GE_3_47 else None, )._process() self.grab_focus() @@ -133,14 +135,14 @@ def button_release_event(self, controller, n_press, x, y): "button_release_event", self, *self._mpl_coords((x, y)), controller.get_current_button(), modifiers=self._mpl_modifiers(controller), - guiEvent=controller.get_current_event(), + guiEvent=controller.get_current_event() if _GOBJECT_GE_3_47 else None, )._process() def key_press_event(self, controller, keyval, keycode, state): KeyEvent( "key_press_event", self, self._get_key(keyval, keycode, state), *self._mpl_coords(), - guiEvent=controller.get_current_event(), + guiEvent=controller.get_current_event() if _GOBJECT_GE_3_47 else None, )._process() return True @@ -148,7 +150,7 @@ def key_release_event(self, controller, keyval, keycode, state): KeyEvent( "key_release_event", self, self._get_key(keyval, keycode, state), *self._mpl_coords(), - guiEvent=controller.get_current_event(), + guiEvent=controller.get_current_event() if _GOBJECT_GE_3_47 else None, )._process() return True @@ -157,21 +159,21 @@ def motion_notify_event(self, controller, x, y): "motion_notify_event", self, *self._mpl_coords((x, y)), buttons=self._mpl_buttons(controller), modifiers=self._mpl_modifiers(controller), - guiEvent=controller.get_current_event(), + guiEvent=controller.get_current_event() if _GOBJECT_GE_3_47 else None, )._process() def enter_notify_event(self, controller, x, y): LocationEvent( "figure_enter_event", self, *self._mpl_coords((x, y)), modifiers=self._mpl_modifiers(), - guiEvent=controller.get_current_event(), + guiEvent=controller.get_current_event() if _GOBJECT_GE_3_47 else None, )._process() def leave_notify_event(self, controller): LocationEvent( "figure_leave_event", self, *self._mpl_coords(), modifiers=self._mpl_modifiers(), - guiEvent=controller.get_current_event(), + guiEvent=controller.get_current_event() if _GOBJECT_GE_3_47 else None, )._process() def resize_event(self, area, width, height): diff --git a/lib/matplotlib/backends/backend_mixed.py b/lib/matplotlib/backends/backend_mixed.py index 6571d1928c0d..971d73cdb448 100644 --- a/lib/matplotlib/backends/backend_mixed.py +++ b/lib/matplotlib/backends/backend_mixed.py @@ -21,9 +21,9 @@ def __init__(self, figure, width, height, dpi, vector_renderer, ---------- figure : `~matplotlib.figure.Figure` The figure instance. - width : scalar + width : float The width of the canvas in logical units - height : scalar + height : float The height of the canvas in logical units dpi : float The dpi of the canvas diff --git a/lib/matplotlib/backends/backend_qt.py b/lib/matplotlib/backends/backend_qt.py index 432bbb1ffdb6..5cde4866cad7 100644 --- a/lib/matplotlib/backends/backend_qt.py +++ b/lib/matplotlib/backends/backend_qt.py @@ -239,6 +239,7 @@ def __init__(self, figure=None): palette = QtGui.QPalette(QtGui.QColor("white")) self.setPalette(palette) + @QtCore.Slot() def _update_pixel_ratio(self): if self._set_device_pixel_ratio( self.devicePixelRatioF() or 1): # rarely, devicePixelRatioF=0 @@ -248,6 +249,7 @@ def _update_pixel_ratio(self): event = QtGui.QResizeEvent(self.size(), self.size()) self.resizeEvent(event) + @QtCore.Slot(QtGui.QScreen) def _update_screen(self, screen): # Handler for changes to a window's attached screen. self._update_pixel_ratio() diff --git a/lib/matplotlib/backends/registry.pyi b/lib/matplotlib/backends/registry.pyi index e1ae5b3e7d3a..565f044bf212 100644 --- a/lib/matplotlib/backends/registry.pyi +++ b/lib/matplotlib/backends/registry.pyi @@ -3,8 +3,8 @@ from types import ModuleType class BackendFilter(Enum): - INTERACTIVE: int - NON_INTERACTIVE: int + INTERACTIVE = 0 + NON_INTERACTIVE = 1 class BackendRegistry: diff --git a/lib/matplotlib/cbook.py b/lib/matplotlib/cbook.py index da7a122b0968..bb2ea311430e 100644 --- a/lib/matplotlib/cbook.py +++ b/lib/matplotlib/cbook.py @@ -880,8 +880,18 @@ class GrouperView: def __init__(self, grouper): self._grouper = grouper def __contains__(self, item): return item in self._grouper def __iter__(self): return iter(self._grouper) - def joined(self, a, b): return self._grouper.joined(a, b) - def get_siblings(self, a): return self._grouper.get_siblings(a) + + def joined(self, a, b): + """ + Return whether *a* and *b* are members of the same set. + """ + return self._grouper.joined(a, b) + + def get_siblings(self, a): + """ + Return all of the items joined with *a*, including itself. + """ + return self._grouper.get_siblings(a) def simple_linear_interpolation(a, steps): diff --git a/lib/matplotlib/collections.py b/lib/matplotlib/collections.py index f18d5a4c3a8c..b94410bcc140 100644 --- a/lib/matplotlib/collections.py +++ b/lib/matplotlib/collections.py @@ -1282,16 +1282,16 @@ def __init__( - 'x': the curves are ``(t, f1)`` and ``(t, f2)``. - 'y': the curves are ``(f1, t)`` and ``(f2, t)``. - t : array (length N) + t : array-like The ``t_direction`` coordinates of the nodes defining the curves. - f1 : array (length N) or scalar + f1 : array-like or float The other coordinates of the nodes defining the first curve. - f2 : array (length N) or scalar + f2 : array-like or float The other coordinates of the nodes defining the second curve. - where : array of bool (length N), optional + where : array-like of bool, optional Define *where* to exclude some {dir} regions from being filled. The filled regions are defined by the coordinates ``t[where]``. More precisely, fill between ``t[i]`` and ``t[i+1]`` if @@ -1362,16 +1362,16 @@ def set_data(self, t, f1, f2, *, where=None): Parameters ---------- - t : array (length N) + t : array-like The ``self.t_direction`` coordinates of the nodes defining the curves. - f1 : array (length N) or scalar + f1 : array-like or float The other coordinates of the nodes defining the first curve. - f2 : array (length N) or scalar + f2 : array-like or float The other coordinates of the nodes defining the second curve. - where : array of bool (length N), optional + where : array-like of bool, optional Define *where* to exclude some {dir} regions from being filled. The filled regions are defined by the coordinates ``t[where]``. More precisely, fill between ``t[i]`` and ``t[i+1]`` if diff --git a/lib/matplotlib/colorbar.py b/lib/matplotlib/colorbar.py index 51ada59a21a0..624e2250303c 100644 --- a/lib/matplotlib/colorbar.py +++ b/lib/matplotlib/colorbar.py @@ -217,81 +217,76 @@ class Colorbar: A list of `.LineCollection` (empty if no lines were drawn). dividers : `.LineCollection` A LineCollection (empty if *drawedges* is ``False``). - - Parameters - ---------- - ax : `~matplotlib.axes.Axes` - The `~.axes.Axes` instance in which the colorbar is drawn. - - mappable : `.ScalarMappable` - The mappable whose colormap and norm will be used. - - To show the under- and over- value colors, the mappable's norm should - be specified as :: - - norm = colors.Normalize(clip=False) - - To show the colors versus index instead of on a 0-1 scale, use:: - - norm=colors.NoNorm() - - cmap : `~matplotlib.colors.Colormap`, default: :rc:`image.cmap` - The colormap to use. This parameter is ignored, unless *mappable* is - None. - - norm : `~matplotlib.colors.Normalize` - The normalization to use. This parameter is ignored, unless *mappable* - is None. - - alpha : float - The colorbar transparency between 0 (transparent) and 1 (opaque). - - orientation : None or {'vertical', 'horizontal'} - If None, use the value determined by *location*. If both - *orientation* and *location* are None then defaults to 'vertical'. - - ticklocation : {'auto', 'left', 'right', 'top', 'bottom'} - The location of the colorbar ticks. The *ticklocation* must match - *orientation*. For example, a horizontal colorbar can only have ticks - at the top or the bottom. If 'auto', the ticks will be the same as - *location*, so a colorbar to the left will have ticks to the left. If - *location* is None, the ticks will be at the bottom for a horizontal - colorbar and at the right for a vertical. - - %(_colormap_kw_doc)s - - location : None or {'left', 'right', 'top', 'bottom'} - Set the *orientation* and *ticklocation* of the colorbar using a - single argument. Colorbars on the left and right are vertical, - colorbars at the top and bottom are horizontal. The *ticklocation* is - the same as *location*, so if *location* is 'top', the ticks are on - the top. *orientation* and/or *ticklocation* can be provided as well - and overrides the value set by *location*, but there will be an error - for incompatible combinations. - - .. versionadded:: 3.7 """ n_rasterize = 50 # rasterize solids if number of colors >= n_rasterize - def __init__(self, ax, mappable=None, *, cmap=None, - norm=None, - alpha=None, - values=None, - boundaries=None, - orientation=None, - ticklocation='auto', - extend=None, - spacing='uniform', # uniform or proportional - ticks=None, - format=None, - drawedges=False, - extendfrac=None, - extendrect=False, - label='', - location=None, - ): - + def __init__( + self, ax, mappable=None, *, + alpha=None, + location=None, + extend=None, + extendfrac=None, + extendrect=False, + ticks=None, + format=None, + values=None, + boundaries=None, + spacing='uniform', + drawedges=False, + label='', + cmap=None, norm=None, # redundant with *mappable* + orientation=None, ticklocation='auto', # redundant with *location* + ): + """ + Parameters + ---------- + ax : `~matplotlib.axes.Axes` + The `~.axes.Axes` instance in which the colorbar is drawn. + + mappable : `.ScalarMappable` + The mappable whose colormap and norm will be used. + + To show the colors versus index instead of on a 0-1 scale, set the + mappable's norm to ``colors.NoNorm()``. + + alpha : float + The colorbar transparency between 0 (transparent) and 1 (opaque). + + location : None or {'left', 'right', 'top', 'bottom'} + Set the colorbar's *orientation* and *ticklocation*. Colorbars on + the left and right are vertical, colorbars at the top and bottom + are horizontal. The *ticklocation* is the same as *location*, so if + *location* is 'top', the ticks are on the top. *orientation* and/or + *ticklocation* can be provided as well and overrides the value set by + *location*, but there will be an error for incompatible combinations. + + .. versionadded:: 3.7 + + %(_colormap_kw_doc)s + + Other Parameters + ---------------- + cmap : `~matplotlib.colors.Colormap`, default: :rc:`image.cmap` + The colormap to use. This parameter is ignored, unless *mappable* is + None. + + norm : `~matplotlib.colors.Normalize` + The normalization to use. This parameter is ignored, unless *mappable* + is None. + + orientation : None or {'vertical', 'horizontal'} + If None, use the value determined by *location*. If both + *orientation* and *location* are None then defaults to 'vertical'. + + ticklocation : {'auto', 'left', 'right', 'top', 'bottom'} + The location of the colorbar ticks. The *ticklocation* must match + *orientation*. For example, a horizontal colorbar can only have ticks + at the top or the bottom. If 'auto', the ticks will be the same as + *location*, so a colorbar to the left will have ticks to the left. If + *location* is None, the ticks will be at the bottom for a horizontal + colorbar and at the right for a vertical. + """ if mappable is None: mappable = cm.ScalarMappable(norm=norm, cmap=cmap) diff --git a/lib/matplotlib/colors.py b/lib/matplotlib/colors.py index 5f909d07c190..aa53b575b737 100644 --- a/lib/matplotlib/colors.py +++ b/lib/matplotlib/colors.py @@ -108,6 +108,7 @@ class ColorSequenceRegistry(Mapping): import matplotlib as mpl colors = mpl.color_sequences['tab10'] + For a list of built in color sequences, see :doc:`/gallery/color/color_sequences`. The returned lists are copies, so that their modification does not change the global definition of the color sequence. @@ -717,7 +718,7 @@ def __call__(self, X, alpha=None, bytes=False): r""" Parameters ---------- - X : float or int, `~numpy.ndarray` or scalar + X : float or int or array-like The data value(s) to convert to RGBA. For floats, *X* should be in the interval ``[0.0, 1.0]`` to return the RGBA values ``X*100`` percent along the Colormap line. @@ -745,7 +746,7 @@ def _get_rgba_and_mask(self, X, alpha=None, bytes=False): r""" Parameters ---------- - X : float or int, `~numpy.ndarray` or scalar + X : float or int or array-like The data value(s) to convert to RGBA. For floats, *X* should be in the interval ``[0.0, 1.0]`` to return the RGBA values ``X*100`` percent along the Colormap line. @@ -1566,7 +1567,7 @@ def __call__(self, X, alpha=None, bytes=False): r""" Parameters ---------- - X : tuple (X0, X1), X0 and X1: float or int `~numpy.ndarray` or scalar + X : tuple (X0, X1), X0 and X1: float or int or array-like The data value(s) to convert to RGBA. - For floats, *X* should be in the interval ``[0.0, 1.0]`` to diff --git a/lib/matplotlib/contour.py b/lib/matplotlib/contour.py index 6b685fa0ed6a..f7318d578121 100644 --- a/lib/matplotlib/contour.py +++ b/lib/matplotlib/contour.py @@ -539,13 +539,6 @@ def _find_closest_point_on_path(xys, p): _docstring.interpd.register(contour_set_attributes=r""" Attributes ---------- -ax : `~matplotlib.axes.Axes` - The Axes object in which the contours are drawn. - -collections : `.silent_list` of `.PathCollection`\s - The `.Artist`\s representing the contour. This is a list of - `.PathCollection`\s for both line and filled contours. - levels : array The values of the contour levels. diff --git a/lib/matplotlib/dviread.pyi b/lib/matplotlib/dviread.pyi index 270818278f17..8073ee9fbff8 100644 --- a/lib/matplotlib/dviread.pyi +++ b/lib/matplotlib/dviread.pyi @@ -8,11 +8,11 @@ from typing import NamedTuple from typing_extensions import Self # < Py 3.11 class _dvistate(Enum): - pre: int - outer: int - inpage: int - post_post: int - finale: int + pre = ... + outer = ... + inpage = ... + post_post = ... + finale = ... class Page(NamedTuple): text: list[Text] diff --git a/lib/matplotlib/ft2font.pyi b/lib/matplotlib/ft2font.pyi index 1638bac692d3..37281afeaafa 100644 --- a/lib/matplotlib/ft2font.pyi +++ b/lib/matplotlib/ft2font.pyi @@ -1,6 +1,6 @@ from enum import Enum, Flag import sys -from typing import BinaryIO, Literal, TypedDict, final, overload +from typing import BinaryIO, Literal, TypedDict, final, overload, cast from typing_extensions import Buffer # < Py 3.12 import numpy as np @@ -10,62 +10,62 @@ __freetype_build_type__: str __freetype_version__: str class FaceFlags(Flag): - SCALABLE: int - FIXED_SIZES: int - FIXED_WIDTH: int - SFNT: int - HORIZONTAL: int - VERTICAL: int - KERNING: int - FAST_GLYPHS: int - MULTIPLE_MASTERS: int - GLYPH_NAMES: int - EXTERNAL_STREAM: int - HINTER: int - CID_KEYED: int - TRICKY: int - COLOR: int - # VARIATION: int # FT 2.9 - # SVG: int # FT 2.12 - # SBIX: int # FT 2.12 - # SBIX_OVERLAY: int # FT 2.12 + SCALABLE = cast(int, ...) + FIXED_SIZES = cast(int, ...) + FIXED_WIDTH = cast(int, ...) + SFNT = cast(int, ...) + HORIZONTAL = cast(int, ...) + VERTICAL = cast(int, ...) + KERNING = cast(int, ...) + FAST_GLYPHS = cast(int, ...) + MULTIPLE_MASTERS = cast(int, ...) + GLYPH_NAMES = cast(int, ...) + EXTERNAL_STREAM = cast(int, ...) + HINTER = cast(int, ...) + CID_KEYED = cast(int, ...) + TRICKY = cast(int, ...) + COLOR = cast(int, ...) + # VARIATION = cast(int, ...) # FT 2.9 + # SVG = cast(int, ...) # FT 2.12 + # SBIX = cast(int, ...) # FT 2.12 + # SBIX_OVERLAY = cast(int, ...) # FT 2.12 class Kerning(Enum): - DEFAULT: int - UNFITTED: int - UNSCALED: int + DEFAULT = cast(int, ...) + UNFITTED = cast(int, ...) + UNSCALED = cast(int, ...) class LoadFlags(Flag): - DEFAULT: int - NO_SCALE: int - NO_HINTING: int - RENDER: int - NO_BITMAP: int - VERTICAL_LAYOUT: int - FORCE_AUTOHINT: int - CROP_BITMAP: int - PEDANTIC: int - IGNORE_GLOBAL_ADVANCE_WIDTH: int - NO_RECURSE: int - IGNORE_TRANSFORM: int - MONOCHROME: int - LINEAR_DESIGN: int - NO_AUTOHINT: int - COLOR: int - COMPUTE_METRICS: int # FT 2.6.1 - # BITMAP_METRICS_ONLY: int # FT 2.7.1 - # NO_SVG: int # FT 2.13.1 + DEFAULT = cast(int, ...) + NO_SCALE = cast(int, ...) + NO_HINTING = cast(int, ...) + RENDER = cast(int, ...) + NO_BITMAP = cast(int, ...) + VERTICAL_LAYOUT = cast(int, ...) + FORCE_AUTOHINT = cast(int, ...) + CROP_BITMAP = cast(int, ...) + PEDANTIC = cast(int, ...) + IGNORE_GLOBAL_ADVANCE_WIDTH = cast(int, ...) + NO_RECURSE = cast(int, ...) + IGNORE_TRANSFORM = cast(int, ...) + MONOCHROME = cast(int, ...) + LINEAR_DESIGN = cast(int, ...) + NO_AUTOHINT = cast(int, ...) + COLOR = cast(int, ...) + COMPUTE_METRICS = cast(int, ...) # FT 2.6.1 + # BITMAP_METRICS_ONLY = cast(int, ...) # FT 2.7.1 + # NO_SVG = cast(int, ...) # FT 2.13.1 # The following should be unique, but the above can be OR'd together. - TARGET_NORMAL: int - TARGET_LIGHT: int - TARGET_MONO: int - TARGET_LCD: int - TARGET_LCD_V: int + TARGET_NORMAL = cast(int, ...) + TARGET_LIGHT = cast(int, ...) + TARGET_MONO = cast(int, ...) + TARGET_LCD = cast(int, ...) + TARGET_LCD_V = cast(int, ...) class StyleFlags(Flag): - NORMAL: int - ITALIC: int - BOLD: int + NORMAL = cast(int, ...) + ITALIC = cast(int, ...) + BOLD = cast(int, ...) class _SfntHeadDict(TypedDict): version: tuple[int, int] @@ -265,6 +265,8 @@ class FT2Font(Buffer): @property def num_glyphs(self) -> int: ... @property + def num_named_instances(self) -> int: ... + @property def postscript_name(self) -> str: ... @property def scalable(self) -> bool: ... diff --git a/lib/matplotlib/image.py b/lib/matplotlib/image.py index 37a1d11678fa..1cbd3c14c135 100644 --- a/lib/matplotlib/image.py +++ b/lib/matplotlib/image.py @@ -501,17 +501,27 @@ def _make_image(self, A, in_bbox, out_bbox, clip_bbox, magnification=1.0, if A.ndim == 2: # interpolation_stage = 'rgba' self.norm.autoscale_None(A) A = self.to_rgba(A) - alpha = self._get_scalar_alpha() - if A.shape[2] == 3: - # No need to resample alpha or make a full array; NumPy will expand - # this out and cast to uint8 if necessary when it's assigned to the - # alpha channel below. - output_alpha = (255 * alpha) if A.dtype == np.uint8 else alpha - else: - output_alpha = _resample( # resample alpha channel - self, A[..., 3], out_shape, t, alpha=alpha) - output = _resample( # resample rgb channels - self, _rgb_to_rgba(A[..., :3]), out_shape, t, alpha=alpha) + alpha = self.get_alpha() + if alpha is None: # alpha parameter not specified + if A.shape[2] == 3: # image has no alpha channel + output_alpha = 255 if A.dtype == np.uint8 else 1.0 + else: + output_alpha = _resample( # resample alpha channel + self, A[..., 3], out_shape, t) + output = _resample( # resample rgb channels + self, _rgb_to_rgba(A[..., :3]), out_shape, t) + elif np.ndim(alpha) > 0: # Array alpha + # user-specified array alpha overrides the existing alpha channel + output_alpha = _resample(self, alpha, out_shape, t) + output = _resample( + self, _rgb_to_rgba(A[..., :3]), out_shape, t) + else: # Scalar alpha + if A.shape[2] == 3: # broadcast scalar alpha + output_alpha = (255 * alpha) if A.dtype == np.uint8 else alpha + else: # or apply scalar alpha to existing alpha channel + output_alpha = _resample(self, A[..., 3], out_shape, t) * alpha + output = _resample( + self, _rgb_to_rgba(A[..., :3]), out_shape, t) output[..., 3] = output_alpha # recombine rgb and alpha # output is now either a 2D array of normed (int or float) data diff --git a/lib/matplotlib/legend.py b/lib/matplotlib/legend.py index ace3f668e740..0c2dfc19705c 100644 --- a/lib/matplotlib/legend.py +++ b/lib/matplotlib/legend.py @@ -934,7 +934,7 @@ def _init_legend_box(self, handles, labels, markerfirst=True): self.texts = text_list self.legend_handles = handle_list - def _auto_legend_data(self): + def _auto_legend_data(self, renderer): """ Return display coordinates for hit testing for "best" positioning. @@ -969,7 +969,7 @@ def _auto_legend_data(self): if len(hoffsets): offsets.extend(transOffset.transform(hoffsets)) elif isinstance(artist, Text): - bboxes.append(artist.get_window_extent()) + bboxes.append(artist.get_window_extent(renderer)) return bboxes, lines, offsets @@ -1150,7 +1150,7 @@ def _find_best_position(self, width, height, renderer): start_time = time.perf_counter() - bboxes, lines, offsets = self._auto_legend_data() + bboxes, lines, offsets = self._auto_legend_data(renderer) bbox = Bbox.from_bounds(0, 0, width, height) diff --git a/lib/matplotlib/offsetbox.py b/lib/matplotlib/offsetbox.py index 49f0946f1ee9..8dd5f4ec23c1 100644 --- a/lib/matplotlib/offsetbox.py +++ b/lib/matplotlib/offsetbox.py @@ -436,6 +436,14 @@ class VPacker(PackerBase): """ VPacker packs its children vertically, automatically adjusting their relative positions at draw time. + + .. code-block:: none + + +---------+ + | Child 1 | + | Child 2 | + | Child 3 | + +---------+ """ def _get_bbox_and_child_offsets(self, renderer): @@ -468,6 +476,12 @@ class HPacker(PackerBase): """ HPacker packs its children horizontally, automatically adjusting their relative positions at draw time. + + .. code-block:: none + + +-------------------------------+ + | Child 1 Child 2 Child 3 | + +-------------------------------+ """ def _get_bbox_and_child_offsets(self, renderer): @@ -498,6 +512,26 @@ class PaddedBox(OffsetBox): The `.PaddedBox` contains a `.FancyBboxPatch` that is used to visualize it when rendering. + + .. code-block:: none + + +----------------------------+ + | | + | | + | | + | <--pad--> Artist | + | ^ | + | pad | + | v | + +----------------------------+ + + Attributes + ---------- + pad : float + The padding in points. + patch : `.FancyBboxPatch` + When *draw_frame* is True, this `.FancyBboxPatch` is made visible and + creates a border around the box. """ def __init__(self, child, pad=0., *, draw_frame=False, patch_attrs=None): diff --git a/lib/matplotlib/pyplot.py b/lib/matplotlib/pyplot.py index ba7a5e32f5d0..48aea1b3bd9c 100644 --- a/lib/matplotlib/pyplot.py +++ b/lib/matplotlib/pyplot.py @@ -994,8 +994,8 @@ def figure( root_fig = num.get_figure(root=True) if root_fig.canvas.manager is None: raise ValueError("The passed figure is not managed by pyplot") - elif any([figsize, dpi, facecolor, edgecolor, not frameon, - kwargs]) and root_fig.canvas.manager.num in allnums: + elif (any(param is not None for param in [figsize, dpi, facecolor, edgecolor]) + or not frameon or kwargs) and root_fig.canvas.manager.num in allnums: _api.warn_external( "Ignoring specified arguments in this call because figure " f"with num: {root_fig.canvas.manager.num} already exists") @@ -1007,8 +1007,8 @@ def figure( if num is None: num = next_num else: - if any([figsize, dpi, facecolor, edgecolor, not frameon, - kwargs]) and num in allnums: + if (any(param is not None for param in [figsize, dpi, facecolor, edgecolor]) + or not frameon or kwargs) and num in allnums: _api.warn_external( "Ignoring specified arguments in this call " f"because figure with num: {num} already exists") @@ -1449,16 +1449,10 @@ def subplot(*args, **kwargs) -> Axes: Notes ----- - Creating a new Axes will delete any preexisting Axes that - overlaps with it beyond sharing a boundary:: - - import matplotlib.pyplot as plt - # plot a line, implicitly creating a subplot(111) - plt.plot([1, 2, 3]) - # now create a subplot which represents the top plot of a grid - # with 2 rows and 1 column. Since this subplot will overlap the - # first, the plot (and its Axes) previously created, will be removed - plt.subplot(211) + .. versionchanged:: 3.8 + In versions prior to 3.8, any preexisting Axes that overlap with the new Axes + beyond sharing a boundary was deleted. Deletion does not happen in more + recent versions anymore. Use `.Axes.remove` explicitly if needed. If you do not want this behavior, use the `.Figure.add_subplot` method or the `.pyplot.axes` function instead. @@ -2668,9 +2662,13 @@ def matshow(A: ArrayLike, fignum: None | int = None, **kwargs) -> AxesImage: if fignum == 0: ax = gca() else: - # Extract actual aspect ratio of array and make appropriately sized - # figure. - fig = figure(fignum, figsize=figaspect(A)) + if fignum is not None and fignum_exists(fignum): + # Do not try to set a figure size. + figsize = None + else: + # Extract actual aspect ratio of array and make appropriately sized figure. + figsize = figaspect(A) + fig = figure(fignum, figsize=figsize) ax = fig.add_axes((0.15, 0.09, 0.775, 0.775)) im = ax.matshow(A, **kwargs) sci(im) diff --git a/lib/matplotlib/scale.py b/lib/matplotlib/scale.py index ccaaae6caf5d..7630ba6e54b9 100644 --- a/lib/matplotlib/scale.py +++ b/lib/matplotlib/scale.py @@ -1,16 +1,33 @@ """ Scales define the distribution of data values on an axis, e.g. a log scaling. -They are defined as subclasses of `ScaleBase`. -See also `.axes.Axes.set_xscale` and the scales examples in the documentation. +The mapping is implemented through `.Transform` subclasses. -See :doc:`/gallery/scales/custom_scale` for a full example of defining a custom -scale. +The following scales are built-in: -Matplotlib also supports non-separable transformations that operate on both -`~.axis.Axis` at the same time. They are known as projections, and defined in -`matplotlib.projections`. -""" +.. _builtin_scales: + +============= ===================== ================================ ================================= +Name Class Transform Inverted transform +============= ===================== ================================ ================================= +"asinh" `AsinhScale` `AsinhTransform` `InvertedAsinhTransform` +"function" `FuncScale` `FuncTransform` `FuncTransform` +"functionlog" `FuncScaleLog` `FuncTransform` + `LogTransform` `InvertedLogTransform` + `FuncTransform` +"linear" `LinearScale` `.IdentityTransform` `.IdentityTransform` +"log" `LogScale` `LogTransform` `InvertedLogTransform` +"logit" `LogitScale` `LogitTransform` `LogisticTransform` +"symlog" `SymmetricalLogScale` `SymmetricalLogTransform` `InvertedSymmetricalLogTransform` +============= ===================== ================================ ================================= + +A user will often only use the scale name, e.g. when setting the scale through +`~.Axes.set_xscale`: ``ax.set_xscale("log")``. + +See also the :ref:`scales examples ` in the documentation. + +Custom scaling can be achieved through `FuncScale`, or by creating your own +`ScaleBase` subclass and corresponding transforms (see :doc:`/gallery/scales/custom_scale`). +Third parties can register their scales by name through `register_scale`. +""" # noqa: E501 import inspect import textwrap @@ -412,6 +429,8 @@ class SymmetricalLogScale(ScaleBase): *linthresh* allows the user to specify the size of this range (-*linthresh*, *linthresh*). + See :doc:`/gallery/scales/symlog_demo` for a detailed description. + Parameters ---------- base : float, default: 10 diff --git a/lib/matplotlib/sphinxext/mathmpl.py b/lib/matplotlib/sphinxext/mathmpl.py index 3e0d562e2d15..30f024524258 100644 --- a/lib/matplotlib/sphinxext/mathmpl.py +++ b/lib/matplotlib/sphinxext/mathmpl.py @@ -146,7 +146,10 @@ def latex2html(node, source): fontset = node['fontset'] fontsize = node['fontsize'] name = 'math-{}'.format( - hashlib.md5(f'{latex}{fontset}{fontsize}'.encode()).hexdigest()[-10:]) + hashlib.sha256( + f'{latex}{fontset}{fontsize}'.encode(), + usedforsecurity=False, + ).hexdigest()[-10:]) destdir = Path(setup.app.builder.outdir, '_images', 'mathmpl') destdir.mkdir(parents=True, exist_ok=True) diff --git a/lib/matplotlib/stackplot.pyi b/lib/matplotlib/stackplot.pyi index 2981d449b566..9509f858a4bf 100644 --- a/lib/matplotlib/stackplot.pyi +++ b/lib/matplotlib/stackplot.pyi @@ -16,3 +16,5 @@ def stackplot( baseline: Literal["zero", "sym", "wiggle", "weighted_wiggle"] = ..., **kwargs ) -> list[PolyCollection]: ... + +__all__ = ['stackplot'] diff --git a/lib/matplotlib/streamplot.pyi b/lib/matplotlib/streamplot.pyi index 9da83096e5a8..be7458020449 100644 --- a/lib/matplotlib/streamplot.pyi +++ b/lib/matplotlib/streamplot.pyi @@ -80,3 +80,5 @@ class StreamMask: class InvalidIndexError(Exception): ... class TerminateTrajectory(Exception): ... class OutOfBounds(IndexError): ... + +__all__ = ['streamplot'] diff --git a/lib/matplotlib/style/core.pyi b/lib/matplotlib/style/core.pyi index 73400492143c..5734b017f7c4 100644 --- a/lib/matplotlib/style/core.pyi +++ b/lib/matplotlib/style/core.pyi @@ -17,3 +17,5 @@ library: dict[str, RcParams] available: list[str] def reload_library() -> None: ... + +__all__ = ['use', 'context', 'available', 'library', 'reload_library'] diff --git a/lib/matplotlib/table.py b/lib/matplotlib/table.py index 21518c4c6726..370ce9fe922f 100644 --- a/lib/matplotlib/table.py +++ b/lib/matplotlib/table.py @@ -838,5 +838,9 @@ def table(ax, if rowLabelWidth == 0: table.auto_set_column_width(-1) + # set_fontsize is only effective after cells are added + if "fontsize" in kwargs: + table.set_fontsize(kwargs["fontsize"]) + ax.add_table(table) return table diff --git a/lib/matplotlib/testing/compare.py b/lib/matplotlib/testing/compare.py index 0f252bc1da8e..3aeddcbe2b5e 100644 --- a/lib/matplotlib/testing/compare.py +++ b/lib/matplotlib/testing/compare.py @@ -46,22 +46,20 @@ def get_cache_dir(): def get_file_hash(path, block_size=2 ** 20): - md5 = hashlib.md5() + sha256 = hashlib.sha256(usedforsecurity=False) with open(path, 'rb') as fd: while True: data = fd.read(block_size) if not data: break - md5.update(data) + sha256.update(data) if Path(path).suffix == '.pdf': - md5.update(str(mpl._get_executable_info("gs").version) - .encode('utf-8')) + sha256.update(str(mpl._get_executable_info("gs").version).encode('utf-8')) elif Path(path).suffix == '.svg': - md5.update(str(mpl._get_executable_info("inkscape").version) - .encode('utf-8')) + sha256.update(str(mpl._get_executable_info("inkscape").version).encode('utf-8')) - return md5.hexdigest() + return sha256.hexdigest() class _ConverterError(Exception): diff --git a/lib/matplotlib/tests/baseline_images/test_polar/polar_title_position.png b/lib/matplotlib/tests/baseline_images/test_polar/polar_title_position.png new file mode 100644 index 000000000000..4a8786b1f892 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_polar/polar_title_position.png differ diff --git a/lib/matplotlib/tests/meson.build b/lib/matplotlib/tests/meson.build index e4a00e850f7f..05336496969f 100644 --- a/lib/matplotlib/tests/meson.build +++ b/lib/matplotlib/tests/meson.build @@ -103,6 +103,7 @@ install_data( 'cmr10.pfb', 'mpltest.ttf', 'test_nbagg_01.ipynb', + 'test_inline_01.ipynb', install_tag: 'tests', install_dir: py3.get_install_dir(subdir: 'matplotlib/tests/')) diff --git a/lib/matplotlib/tests/test_animation.py b/lib/matplotlib/tests/test_animation.py index d026dae59533..e3382f662c73 100644 --- a/lib/matplotlib/tests/test_animation.py +++ b/lib/matplotlib/tests/test_animation.py @@ -13,6 +13,7 @@ import matplotlib as mpl from matplotlib import pyplot as plt from matplotlib import animation +from matplotlib.animation import PillowWriter from matplotlib.testing.decorators import check_figures_equal @@ -551,3 +552,20 @@ def test_movie_writer_invalid_path(anim): with pytest.raises(FileNotFoundError, match=match_str): anim.save("/foo/bar/aardvark/thiscannotreallyexist.mp4", writer=animation.FFMpegFileWriter()) + + +def test_animation_with_transparency(): + """Test animation exhaustion with transparency using PillowWriter directly""" + fig, ax = plt.subplots() + rect = plt.Rectangle((0, 0), 1, 1, color='red', alpha=0.5) + ax.add_patch(rect) + ax.set_xlim(0, 1) + ax.set_ylim(0, 1) + + writer = PillowWriter(fps=30) + writer.setup(fig, 'unused.gif', dpi=100) + writer.grab_frame(transparent=True) + frame = writer._frames[-1] + # Check that the alpha channel is not 255, so frame has transparency + assert frame.getextrema()[3][0] < 255 + plt.close(fig) diff --git a/lib/matplotlib/tests/test_arrow_patches.py b/lib/matplotlib/tests/test_arrow_patches.py index 254b86cb54d6..431d1eb6eaf6 100644 --- a/lib/matplotlib/tests/test_arrow_patches.py +++ b/lib/matplotlib/tests/test_arrow_patches.py @@ -12,7 +12,7 @@ def draw_arrow(ax, t, r): @image_comparison(['fancyarrow_test_image'], - tol=0.012 if platform.machine() == 'arm64' else 0) + tol=0 if platform.machine() == 'x86_64' else 0.012) def test_fancyarrow(): # Added 0 to test division by zero error described in issue 3930 r = [0.4, 0.3, 0.2, 0.1, 0] @@ -149,7 +149,7 @@ def test_arrow_styles(): @image_comparison(['connection_styles.png'], style='mpl20', remove_text=True, - tol=0.013 if platform.machine() == 'arm64' else 0) + tol=0 if platform.machine() == 'x86_64' else 0.013) def test_connection_styles(): styles = mpatches.ConnectionStyle.get_styles() diff --git a/lib/matplotlib/tests/test_axes.py b/lib/matplotlib/tests/test_axes.py index e9218bc82573..cd5cd08fbf74 100644 --- a/lib/matplotlib/tests/test_axes.py +++ b/lib/matplotlib/tests/test_axes.py @@ -243,7 +243,7 @@ def test_matshow(fig_test, fig_ref): 'formatter_ticker_004', 'formatter_ticker_005', ], - tol=0.031 if platform.machine() == 'arm64' else 0) + tol=0 if platform.machine() == 'x86_64' else 0.031) def test_formatter_ticker(): import matplotlib.testing.jpl_units as units units.register() @@ -444,7 +444,7 @@ def test_twin_logscale(fig_test, fig_ref, twin): @image_comparison(['twin_autoscale.png'], - tol=0.009 if platform.machine() == 'arm64' else 0) + tol=0 if platform.machine() == 'x86_64' else 0.009) def test_twinx_axis_scales(): x = np.array([0, 0.5, 1]) y = 0.5 * x @@ -1218,9 +1218,8 @@ def test_imshow(): ax.imshow("r", data=data) -@image_comparison( - ['imshow_clip'], style='mpl20', - tol=1.24 if platform.machine() in ('aarch64', 'arm64', 'ppc64le', 's390x') else 0) +@image_comparison(['imshow_clip'], style='mpl20', + tol=0 if platform.machine() == 'x86_64' else 1.24) def test_imshow_clip(): # As originally reported by Gellule Xg # use former defaults to match existing baseline image @@ -1299,7 +1298,7 @@ def test_fill_betweenx_input(y, x1, x2): @image_comparison(['fill_between_interpolate'], remove_text=True, - tol=0.012 if platform.machine() == 'arm64' else 0) + tol=0 if platform.machine() == 'x86_64' else 0.012) def test_fill_between_interpolate(): x = np.arange(0.0, 2, 0.02) y1 = np.sin(2*np.pi*x) @@ -1727,7 +1726,8 @@ def test_pcolorauto(fig_test, fig_ref, snap): ax.pcolormesh(x2, y2, Z, snap=snap) -@image_comparison(['canonical'], tol=0.02 if platform.machine() == 'arm64' else 0) +@image_comparison(['canonical'], + tol=0 if platform.machine() == 'x86_64' else 0.02) def test_canonical(): fig, ax = plt.subplots() ax.plot([1, 2, 3]) @@ -2652,9 +2652,8 @@ def test_contour_hatching(): extend='both', alpha=0.5) -@image_comparison( - ['contour_colorbar'], style='mpl20', - tol=0.54 if platform.machine() in ('aarch64', 'arm64', 'ppc64le', 's390x') else 0) +@image_comparison(['contour_colorbar'], style='mpl20', + tol=0 if platform.machine() == 'x86_64' else 0.54) def test_contour_colorbar(): x, y, z = contour_dat() @@ -2942,7 +2941,7 @@ def test_scatter_different_shapes(self, fig_test, fig_ref): @pytest.mark.parametrize('c_case, re_key', params_test_scatter_c) def test_scatter_c(self, c_case, re_key): - def get_next_color(): + def get_next_color(): # pragma: no cover return 'blue' # currently unused xsize = 4 @@ -3036,7 +3035,7 @@ def _params(c=None, xsize=2, *, edgecolors=None, **kwargs): _result(c=['b', 'g'], colors=np.array([[0, 0, 1, 1], [0, .5, 0, 1]]))), ]) def test_parse_scatter_color_args(params, expected_result): - def get_next_color(): + def get_next_color(): # pragma: no cover return 'blue' # currently unused c, colors, _edgecolors = mpl.axes.Axes._parse_scatter_color_args( @@ -3063,7 +3062,7 @@ def get_next_color(): (dict(color='r', edgecolor='g'), 'g'), ]) def test_parse_scatter_color_args_edgecolors(kwargs, expected_edgecolors): - def get_next_color(): + def get_next_color(): # pragma: no cover return 'blue' # currently unused c = kwargs.pop('c', None) @@ -3075,7 +3074,7 @@ def get_next_color(): def test_parse_scatter_color_args_error(): - def get_next_color(): + def get_next_color(): # pragma: no cover return 'blue' # currently unused with pytest.raises(ValueError, @@ -3085,6 +3084,55 @@ def get_next_color(): c, None, kwargs={}, xsize=2, get_next_color_func=get_next_color) +# Warning message tested in the next two tests. +WARN_MSG = ( + "You passed both c and facecolor/facecolors for the markers. " + "c has precedence over facecolor/facecolors. This behavior may " + "change in the future." +) +# Test cases shared between direct and integration tests +COLOR_TEST_CASES = [ + ('red', 'blue'), + (['red', 'blue'], ['green', 'yellow']), + ([[1, 0, 0], [0, 1, 0]], [[0, 0, 1], [1, 1, 0]]) +] + + +@pytest.mark.parametrize('c, facecolor', COLOR_TEST_CASES) +def test_parse_c_facecolor_warning_direct(c, facecolor): + """Test the internal _parse_scatter_color_args method directly.""" + def get_next_color(): # pragma: no cover + return 'blue' # currently unused + + # Test with facecolors (plural) + with pytest.warns(UserWarning, match=WARN_MSG): + mpl.axes.Axes._parse_scatter_color_args( + c=c, edgecolors=None, kwargs={'facecolors': facecolor}, + xsize=2, get_next_color_func=get_next_color) + + # Test with facecolor (singular) + with pytest.warns(UserWarning, match=WARN_MSG): + mpl.axes.Axes._parse_scatter_color_args( + c=c, edgecolors=None, kwargs={'facecolor': facecolor}, + xsize=2, get_next_color_func=get_next_color) + + +@pytest.mark.parametrize('c, facecolor', COLOR_TEST_CASES) +def test_scatter_c_facecolor_warning_integration(c, facecolor): + """Test the warning through the actual scatter plot creation.""" + fig, ax = plt.subplots() + x = [0, 1] if isinstance(c, (list, tuple)) else [0] + y = x + + # Test with facecolors (plural) + with pytest.warns(UserWarning, match=WARN_MSG): + ax.scatter(x, y, c=c, facecolors=facecolor) + + # Test with facecolor (singular) + with pytest.warns(UserWarning, match=WARN_MSG): + ax.scatter(x, y, c=c, facecolor=facecolor) + + def test_as_mpl_axes_api(): # tests the _as_mpl_axes api class Polar: @@ -3183,7 +3231,7 @@ def test_log_scales_invalid(): @image_comparison(['stackplot_test_image', 'stackplot_test_image'], - tol=0.031 if platform.machine() == 'arm64' else 0) + tol=0 if platform.machine() == 'x86_64' else 0.031) def test_stackplot(): fig = plt.figure() x = np.linspace(0, 10, 10) @@ -4225,6 +4273,24 @@ def test_errorbar_nonefmt(): assert np.all(errbar.get_color() == mcolors.to_rgba('C0')) +def test_errorbar_remove(): + x = np.arange(5) + y = np.arange(5) + + fig, ax = plt.subplots() + ec = ax.errorbar(x, y, xerr=1, yerr=1) + + assert len(ax.containers) == 1 + assert len(ax.lines) == 5 + assert len(ax.collections) == 2 + + ec.remove() + + assert not ax.containers + assert not ax.lines + assert not ax.collections + + def test_errorbar_line_specific_kwargs(): # Check that passing line-specific keyword arguments will not result in # errors. @@ -5059,7 +5125,7 @@ def test_marker_styles(): @image_comparison(['rc_markerfill.png'], - tol=0.037 if platform.machine() == 'arm64' else 0) + tol=0 if platform.machine() == 'x86_64' else 0.037) def test_markers_fillstyle_rcparams(): fig, ax = plt.subplots() x = np.arange(7) @@ -5642,7 +5708,7 @@ def test_twin_remove(fig_test, fig_ref): @image_comparison(['twin_spines.png'], remove_text=True, - tol=0.022 if platform.machine() == 'arm64' else 0) + tol=0 if platform.machine() == 'x86_64' else 0.022) def test_twin_spines(): def make_patch_spines_invisible(ax): @@ -6239,7 +6305,7 @@ def test_pie_hatch_multi(fig_test, fig_ref): @image_comparison(['set_get_ticklabels.png'], - tol=0.025 if platform.machine() == 'arm64' else 0) + tol=0 if platform.machine() == 'x86_64' else 0.025) def test_set_get_ticklabels(): # test issue 2246 fig, ax = plt.subplots(2) @@ -6832,7 +6898,7 @@ def test_loglog(): @image_comparison(["test_loglog_nonpos.png"], remove_text=True, style='mpl20', - tol=0.029 if platform.machine() == 'arm64' else 0) + tol=0 if platform.machine() == 'x86_64' else 0.029) def test_loglog_nonpos(): fig, axs = plt.subplots(3, 3) x = np.arange(1, 11) @@ -7772,7 +7838,7 @@ def test_scatter_empty_data(): @image_comparison(['annotate_across_transforms.png'], style='mpl20', remove_text=True, - tol=0.025 if platform.machine() == 'arm64' else 0) + tol=0 if platform.machine() == 'x86_64' else 0.025) def test_annotate_across_transforms(): x = np.linspace(0, 10, 200) y = np.exp(-x) * np.sin(x) @@ -7803,7 +7869,7 @@ def inverted(self): @image_comparison(['secondary_xy.png'], style='mpl20', - tol=0.027 if platform.machine() == 'arm64' else 0) + tol=0 if platform.machine() == 'x86_64' else 0.027) def test_secondary_xy(): fig, axs = plt.subplots(1, 2, figsize=(10, 5), constrained_layout=True) @@ -9046,8 +9112,8 @@ def test_child_axes_removal(): def test_scatter_color_repr_error(): - def get_next_color(): - return 'blue' # pragma: no cover + def get_next_color(): # pragma: no cover + return 'blue' # currently unused msg = ( r"'c' argument must be a color, a sequence of colors" r", or a sequence of numbers, not 'red\\n'" @@ -9067,7 +9133,7 @@ def test_zorder_and_explicit_rasterization(): @image_comparison(["preset_clip_paths.png"], remove_text=True, style="mpl20", - tol=0.027 if platform.machine() == "arm64" else 0) + tol=0 if platform.machine() == 'x86_64' else 0.027) def test_preset_clip_paths(): fig, ax = plt.subplots() @@ -9400,7 +9466,7 @@ def test_boxplot_orientation(fig_test, fig_ref): @image_comparison(["use_colorizer_keyword.png"], - tol=0.05 if platform.machine() == 'arm64' else 0) + tol=0 if platform.machine() == 'x86_64' else 0.05) def test_use_colorizer_keyword(): # test using the colorizer keyword np.random.seed(0) @@ -9513,3 +9579,14 @@ def test_bar_color_precedence(): bars = ax.bar([31, 32, 33], [4, 5, 6], color='red', facecolor='green') for bar in bars: assert mcolors.same_color(bar.get_facecolor(), 'green') + + +@check_figures_equal(extensions=['png']) +def test_axes_set_position_external_bbox_unchanged(fig_test, fig_ref): + # From #29410: Modifying Axes' position also alters the original Bbox + # object used for initialization + bbox = mtransforms.Bbox([[0.0, 0.0], [1.0, 1.0]]) + ax_test = fig_test.add_axes(bbox) + ax_test.set_position([0.25, 0.25, 0.5, 0.5]) + assert (bbox.x0, bbox.y0, bbox.width, bbox.height) == (0.0, 0.0, 1.0, 1.0) + ax_ref = fig_ref.add_axes([0.25, 0.25, 0.5, 0.5]) diff --git a/lib/matplotlib/tests/test_bbox_tight.py b/lib/matplotlib/tests/test_bbox_tight.py index 5f2b397b650d..7a2809931757 100644 --- a/lib/matplotlib/tests/test_bbox_tight.py +++ b/lib/matplotlib/tests/test_bbox_tight.py @@ -45,7 +45,7 @@ def test_bbox_inches_tight(): @image_comparison(['bbox_inches_tight_suptile_legend'], savefig_kwarg={'bbox_inches': 'tight'}, - tol=0.02 if platform.machine() == 'arm64' else 0) + tol=0 if platform.machine() == 'x86_64' else 0.02) def test_bbox_inches_tight_suptile_legend(): plt.plot(np.arange(10), label='a straight line') plt.legend(bbox_to_anchor=(0.9, 1), loc='upper left') diff --git a/lib/matplotlib/tests/test_collections.py b/lib/matplotlib/tests/test_collections.py index 11934cfca2c3..db9c4be81a44 100644 --- a/lib/matplotlib/tests/test_collections.py +++ b/lib/matplotlib/tests/test_collections.py @@ -391,7 +391,7 @@ def test_barb_limits(): @image_comparison(['EllipseCollection_test_image.png'], remove_text=True, - tol=0.021 if platform.machine() == 'arm64' else 0) + tol=0 if platform.machine() == 'x86_64' else 0.021) def test_EllipseCollection(): # Test basic functionality fig, ax = plt.subplots() diff --git a/lib/matplotlib/tests/test_constrainedlayout.py b/lib/matplotlib/tests/test_constrainedlayout.py index e42e2ee9bfd8..77f9f34bc2d8 100644 --- a/lib/matplotlib/tests/test_constrainedlayout.py +++ b/lib/matplotlib/tests/test_constrainedlayout.py @@ -198,7 +198,7 @@ def test_constrained_layout9(): @image_comparison(['constrained_layout10.png'], - tol=0.032 if platform.machine() == 'arm64' else 0) + tol=0 if platform.machine() == 'x86_64' else 0.032) def test_constrained_layout10(): """Test for handling legend outside axis""" fig, axs = plt.subplots(2, 2, layout="constrained") diff --git a/lib/matplotlib/tests/test_contour.py b/lib/matplotlib/tests/test_contour.py index e0ea82973af7..543cff18c697 100644 --- a/lib/matplotlib/tests/test_contour.py +++ b/lib/matplotlib/tests/test_contour.py @@ -140,7 +140,7 @@ def test_contour_label_with_disconnected_segments(): @image_comparison(['contour_manual_colors_and_levels.png'], remove_text=True, - tol=0.018 if platform.machine() == 'arm64' else 0) + tol=0 if platform.machine() == 'x86_64' else 0.018) def test_given_colors_levels_and_extends(): # Remove this line when this test image is regenerated. plt.rcParams['pcolormesh.snap'] = False @@ -416,10 +416,8 @@ def test_contourf_log_extension(): cb = plt.colorbar(c3, ax=ax3) -@image_comparison( - ['contour_addlines.png'], remove_text=True, style='mpl20', - tol=0.15 if platform.machine() in ('aarch64', 'arm64', 'ppc64le', 's390x') - else 0.03) +@image_comparison(['contour_addlines.png'], remove_text=True, style='mpl20', + tol=0.03 if platform.machine() == 'x86_64' else 0.15) # tolerance is because image changed minutely when tick finding on # colorbars was cleaned up... def test_contour_addlines(): diff --git a/lib/matplotlib/tests/test_figure.py b/lib/matplotlib/tests/test_figure.py index edf5ea05f119..c80f53413181 100644 --- a/lib/matplotlib/tests/test_figure.py +++ b/lib/matplotlib/tests/test_figure.py @@ -210,7 +210,7 @@ def test_clf_keyword(): @image_comparison(['figure_today'], - tol=0.015 if platform.machine() == 'arm64' else 0) + tol=0 if platform.machine() == 'x86_64' else 0.015) def test_figure(): # named figure support fig = plt.figure('today') diff --git a/lib/matplotlib/tests/test_ft2font.py b/lib/matplotlib/tests/test_ft2font.py index 7dc851b2c9cf..6ba23bab347e 100644 --- a/lib/matplotlib/tests/test_ft2font.py +++ b/lib/matplotlib/tests/test_ft2font.py @@ -40,6 +40,7 @@ def test_ft2font_dejavu_attrs(): assert font.family_name == 'DejaVu Sans' assert font.style_name == 'Book' assert font.num_faces == 1 # Single TTF. + assert font.num_named_instances == 0 # Not a variable font. assert font.num_glyphs == 6241 # From compact encoding view in FontForge. assert font.num_fixed_sizes == 0 # All glyphs are scalable. assert font.num_charmaps == 5 @@ -73,6 +74,7 @@ def test_ft2font_cm_attrs(): assert font.family_name == 'cmtt10' assert font.style_name == 'Regular' assert font.num_faces == 1 # Single TTF. + assert font.num_named_instances == 0 # Not a variable font. assert font.num_glyphs == 133 # From compact encoding view in FontForge. assert font.num_fixed_sizes == 0 # All glyphs are scalable. assert font.num_charmaps == 2 @@ -105,6 +107,7 @@ def test_ft2font_stix_bold_attrs(): assert font.family_name == 'STIXSizeTwoSym' assert font.style_name == 'Bold' assert font.num_faces == 1 # Single TTF. + assert font.num_named_instances == 0 # Not a variable font. assert font.num_glyphs == 20 # From compact encoding view in FontForge. assert font.num_fixed_sizes == 0 # All glyphs are scalable. assert font.num_charmaps == 3 diff --git a/lib/matplotlib/tests/test_image.py b/lib/matplotlib/tests/test_image.py index 24a0ab929bbf..bc98bdb3900c 100644 --- a/lib/matplotlib/tests/test_image.py +++ b/lib/matplotlib/tests/test_image.py @@ -1711,3 +1711,49 @@ def test_resample_dtypes(dtype, ndim): axes_image = ax.imshow(data) # Before fix the following raises ValueError for some dtypes. axes_image.make_image(None)[0] + + +@pytest.mark.parametrize('intp_stage', ('data', 'rgba')) +@check_figures_equal() +def test_interpolation_stage_rgba_respects_alpha_param(fig_test, fig_ref, intp_stage): + axs_tst = fig_test.subplots(2, 3) + axs_ref = fig_ref.subplots(2, 3) + ny, nx = 3, 3 + scalar_alpha = 0.5 + array_alpha = np.random.rand(ny, nx) + + # When the image does not have an alpha channel, alpha should be specified + # by the user or default to 1.0 + im_rgb = np.random.rand(ny, nx, 3) + im_concat_default_a = np.ones((ny, nx, 1)) # alpha defaults to 1.0 + im_rgba = np.concatenate( # combine rgb channels with array alpha + (im_rgb, array_alpha.reshape((ny, nx, 1))), axis=-1 + ) + axs_tst[0][0].imshow(im_rgb) + axs_ref[0][0].imshow(np.concatenate((im_rgb, im_concat_default_a), axis=-1)) + axs_tst[0][1].imshow(im_rgb, interpolation_stage=intp_stage, alpha=scalar_alpha) + axs_ref[0][1].imshow( + np.concatenate( # combine rgb channels with broadcasted scalar alpha + (im_rgb, scalar_alpha * im_concat_default_a), axis=-1 + ), interpolation_stage=intp_stage + ) + axs_tst[0][2].imshow(im_rgb, interpolation_stage=intp_stage, alpha=array_alpha) + axs_ref[0][2].imshow(im_rgba, interpolation_stage=intp_stage) + + # When the image already has an alpha channel, multiply it by the + # scalar alpha param, or replace it by the array alpha param + axs_tst[1][0].imshow(im_rgba) + axs_ref[1][0].imshow(im_rgb, alpha=array_alpha) + axs_tst[1][1].imshow(im_rgba, interpolation_stage=intp_stage, alpha=scalar_alpha) + axs_ref[1][1].imshow( + np.concatenate( # combine rgb channels with scaled array alpha + (im_rgb, scalar_alpha * array_alpha.reshape((ny, nx, 1))), axis=-1 + ), interpolation_stage=intp_stage + ) + new_array_alpha = np.random.rand(ny, nx) + axs_tst[1][2].imshow(im_rgba, interpolation_stage=intp_stage, alpha=new_array_alpha) + axs_ref[1][2].imshow( + np.concatenate( # combine rgb channels with new array alpha + (im_rgb, new_array_alpha.reshape((ny, nx, 1))), axis=-1 + ), interpolation_stage=intp_stage + ) diff --git a/lib/matplotlib/tests/test_legend.py b/lib/matplotlib/tests/test_legend.py index 61892378bd03..8baa7bb0f7d9 100644 --- a/lib/matplotlib/tests/test_legend.py +++ b/lib/matplotlib/tests/test_legend.py @@ -1,4 +1,5 @@ import collections +import io import itertools import platform import time @@ -139,7 +140,7 @@ def test_various_labels(): @image_comparison(['legend_labels_first.png'], remove_text=True, - tol=0.013 if platform.machine() == 'arm64' else 0) + tol=0 if platform.machine() == 'x86_64' else 0.013) def test_labels_first(): # test labels to left of markers fig, ax = plt.subplots() @@ -150,7 +151,7 @@ def test_labels_first(): @image_comparison(['legend_multiple_keys.png'], remove_text=True, - tol=0.013 if platform.machine() == 'arm64' else 0) + tol=0 if platform.machine() == 'x86_64' else 0.013) def test_multiple_keys(): # test legend entries with multiple keys fig, ax = plt.subplots() @@ -513,7 +514,7 @@ def test_figure_legend_outside(): @image_comparison(['legend_stackplot.png'], - tol=0.031 if platform.machine() == 'arm64' else 0) + tol=0 if platform.machine() == 'x86_64' else 0.031) def test_legend_stackplot(): """Test legend for PolyCollection using stackplot.""" # related to #1341, #1943, and PR #3303 @@ -649,7 +650,7 @@ def test_empty_bar_chart_with_legend(): @image_comparison(['shadow_argument_types.png'], remove_text=True, style='mpl20', - tol=0.028 if platform.machine() == 'arm64' else 0) + tol=0 if platform.machine() == 'x86_64' else 0.028) def test_shadow_argument_types(): # Test that different arguments for shadow work as expected fig, ax = plt.subplots() @@ -969,13 +970,12 @@ def test_legend_pathcollection_labelcolor_markfacecolor_cmap(): # test the labelcolor for labelcolor='markerfacecolor' on PathCollection # with colormaps fig, ax = plt.subplots() - facecolors = mpl.cm.viridis(np.random.rand(10)) + colors = mpl.cm.viridis(np.random.rand(10)) ax.scatter( np.arange(10), np.arange(10), label='#1', - c=np.arange(10), - facecolor=facecolors + c=colors ) leg = ax.legend(labelcolor='markerfacecolor') @@ -1427,6 +1427,21 @@ def test_legend_text(): assert_allclose(leg_bboxes[1].bounds, leg_bboxes[0].bounds) +def test_legend_annotate(): + fig, ax = plt.subplots() + + ax.plot([1, 2, 3], label="Line") + ax.annotate("a", xy=(1, 1)) + ax.legend(loc=0) + + with mock.patch.object( + fig, '_get_renderer', wraps=fig._get_renderer) as mocked_get_renderer: + fig.savefig(io.BytesIO()) + + # Finding the legend position should not require _get_renderer to be called + mocked_get_renderer.assert_not_called() + + def test_boxplot_legend_labels(): # Test that legend entries are generated when passing `label`. np.random.seed(19680801) diff --git a/lib/matplotlib/tests/test_lines.py b/lib/matplotlib/tests/test_lines.py index ee8b5b4aaa9e..bbaea2510215 100644 --- a/lib/matplotlib/tests/test_lines.py +++ b/lib/matplotlib/tests/test_lines.py @@ -140,7 +140,7 @@ def test_valid_linestyles(): @image_comparison(['drawstyle_variants.png'], remove_text=True, - tol=0.03 if platform.machine() == 'arm64' else 0) + tol=0 if platform.machine() == 'x86_64' else 0.03) def test_drawstyle_variants(): fig, axs = plt.subplots(6) dss = ["default", "steps-mid", "steps-pre", "steps-post", "steps", None] @@ -183,9 +183,8 @@ def test_set_drawstyle(): assert len(line.get_path().vertices) == len(x) -@image_comparison( - ['line_collection_dashes'], remove_text=True, style='mpl20', - tol=0 if platform.machine() == 'x86_64' else 0.65) +@image_comparison(['line_collection_dashes'], remove_text=True, style='mpl20', + tol=0 if platform.machine() == 'x86_64' else 0.65) def test_set_line_coll_dash_image(): fig, ax = plt.subplots() np.random.seed(0) diff --git a/lib/matplotlib/tests/test_patches.py b/lib/matplotlib/tests/test_patches.py index 9cb67616a96b..2ea0df2540eb 100644 --- a/lib/matplotlib/tests/test_patches.py +++ b/lib/matplotlib/tests/test_patches.py @@ -438,7 +438,7 @@ def test_wedge_movement(): @image_comparison(['wedge_range'], remove_text=True, - tol=0.009 if platform.machine() == 'arm64' else 0) + tol=0 if platform.machine() == 'x86_64' else 0.009) def test_wedge_range(): ax = plt.axes() @@ -564,7 +564,7 @@ def test_units_rectangle(): @image_comparison(['connection_patch.png'], style='mpl20', remove_text=True, - tol=0.024 if platform.machine() == 'arm64' else 0) + tol=0 if platform.machine() == 'x86_64' else 0.024) def test_connection_patch(): fig, (ax1, ax2) = plt.subplots(1, 2) diff --git a/lib/matplotlib/tests/test_path.py b/lib/matplotlib/tests/test_path.py index 2c4df6ea3b39..5424160dad93 100644 --- a/lib/matplotlib/tests/test_path.py +++ b/lib/matplotlib/tests/test_path.py @@ -151,7 +151,7 @@ def test_nonlinear_containment(): @image_comparison(['arrow_contains_point.png'], remove_text=True, style='mpl20', - tol=0.027 if platform.machine() == 'arm64' else 0) + tol=0 if platform.machine() == 'x86_64' else 0.027) def test_arrow_contains_point(): # fix bug (#8384) fig, ax = plt.subplots() @@ -283,7 +283,7 @@ def test_marker_paths_pdf(): @image_comparison(['nan_path'], style='default', remove_text=True, extensions=['pdf', 'svg', 'eps', 'png'], - tol=0.009 if platform.machine() == 'arm64' else 0) + tol=0 if platform.machine() == 'x86_64' else 0.009) def test_nan_isolated_points(): y0 = [0, np.nan, 2, np.nan, 4, 5, 6] diff --git a/lib/matplotlib/tests/test_patheffects.py b/lib/matplotlib/tests/test_patheffects.py index bf067b2abbfd..6c89d1c531e0 100644 --- a/lib/matplotlib/tests/test_patheffects.py +++ b/lib/matplotlib/tests/test_patheffects.py @@ -30,7 +30,7 @@ def test_patheffect1(): @image_comparison(['patheffect2'], remove_text=True, style='mpl20', - tol=0.06 if platform.machine() == 'arm64' else 0) + tol=0 if platform.machine() == 'x86_64' else 0.06) def test_patheffect2(): ax2 = plt.subplot() @@ -45,7 +45,8 @@ def test_patheffect2(): foreground="w")]) -@image_comparison(['patheffect3'], tol=0.019 if platform.machine() == 'arm64' else 0) +@image_comparison(['patheffect3'], + tol=0 if platform.machine() == 'x86_64' else 0.019) def test_patheffect3(): p1, = plt.plot([1, 3, 5, 4, 3], 'o-b', lw=4) p1.set_path_effects([path_effects.SimpleLineShadow(), diff --git a/lib/matplotlib/tests/test_polar.py b/lib/matplotlib/tests/test_polar.py index ee38c88a123f..ff2ad6433e6b 100644 --- a/lib/matplotlib/tests/test_polar.py +++ b/lib/matplotlib/tests/test_polar.py @@ -220,6 +220,13 @@ def test_polar_rlabel_position(): ax.tick_params(rotation='auto') +@image_comparison(['polar_title_position.png'], style='mpl20') +def test_polar_title_position(): + fig = plt.figure() + ax = fig.add_subplot(projection='polar') + ax.set_title('foo') + + @image_comparison(['polar_theta_wedge'], style='default') def test_polar_theta_limits(): r = np.arange(0, 3.0, 0.01) diff --git a/lib/matplotlib/tests/test_pyplot.py b/lib/matplotlib/tests/test_pyplot.py index 21036e177045..1aaa8dd93ca2 100644 --- a/lib/matplotlib/tests/test_pyplot.py +++ b/lib/matplotlib/tests/test_pyplot.py @@ -459,13 +459,13 @@ def test_figure_hook(): def test_multiple_same_figure_calls(): - fig = mpl.pyplot.figure(1, figsize=(1, 2)) + fig = plt.figure(1, figsize=(1, 2)) with pytest.warns(UserWarning, match="Ignoring specified arguments in this call"): - fig2 = mpl.pyplot.figure(1, figsize=(3, 4)) + fig2 = plt.figure(1, figsize=np.array([3, 4])) with pytest.warns(UserWarning, match="Ignoring specified arguments in this call"): - mpl.pyplot.figure(fig, figsize=(5, 6)) + plt.figure(fig, figsize=np.array([5, 6])) assert fig is fig2 - fig3 = mpl.pyplot.figure(1) # Checks for false warnings + fig3 = plt.figure(1) # Checks for false warnings assert fig is fig3 @@ -475,3 +475,11 @@ def test_close_all_warning(): # Check that the warning is issued when 'all' is passed to plt.figure with pytest.warns(UserWarning, match="closes all existing figures"): fig2 = plt.figure("all") + + +def test_matshow(): + fig = plt.figure() + arr = [[0, 1], [1, 2]] + + # Smoke test that matshow does not ask for a new figsize on the existing figure + plt.matshow(arr, fignum=fig.number) diff --git a/lib/matplotlib/tests/test_simplification.py b/lib/matplotlib/tests/test_simplification.py index a052c24cb655..58b4d7a9b24f 100644 --- a/lib/matplotlib/tests/test_simplification.py +++ b/lib/matplotlib/tests/test_simplification.py @@ -29,7 +29,7 @@ def test_clipping(): @image_comparison(['overflow'], remove_text=True, - tol=0.007 if platform.machine() == 'arm64' else 0) + tol=0 if platform.machine() == 'x86_64' else 0.007) def test_overflow(): x = np.array([1.0, 2.0, 3.0, 2.0e5]) y = np.arange(len(x)) diff --git a/lib/matplotlib/tests/test_skew.py b/lib/matplotlib/tests/test_skew.py index fd7e7cebfacb..20ec6bf32b06 100644 --- a/lib/matplotlib/tests/test_skew.py +++ b/lib/matplotlib/tests/test_skew.py @@ -146,7 +146,7 @@ def test_set_line_coll_dash_image(): @image_comparison(['skew_rects'], remove_text=True, - tol=0.009 if platform.machine() == 'arm64' else 0) + tol=0 if platform.machine() == 'x86_64' else 0.009) def test_skew_rectangle(): fix, axes = plt.subplots(5, 5, sharex=True, sharey=True, figsize=(8, 8)) diff --git a/lib/matplotlib/tests/test_subplots.py b/lib/matplotlib/tests/test_subplots.py index 70215c9531ba..9fd887831106 100644 --- a/lib/matplotlib/tests/test_subplots.py +++ b/lib/matplotlib/tests/test_subplots.py @@ -175,7 +175,7 @@ def test_exceptions(): @image_comparison(['subplots_offset_text'], - tol=0.028 if platform.machine() == 'arm64' else 0) + tol=0 if platform.machine() == 'x86_64' else 0.028) def test_subplots_offsettext(): x = np.arange(0, 1e10, 1e9) y = np.arange(0, 100, 10)+1e4 diff --git a/lib/matplotlib/tests/test_table.py b/lib/matplotlib/tests/test_table.py index ee974f3cd8f9..783be25376be 100644 --- a/lib/matplotlib/tests/test_table.py +++ b/lib/matplotlib/tests/test_table.py @@ -270,3 +270,15 @@ def test_table_dataframe(pd): for r, (index, row) in enumerate(df.iterrows()): for c, col in enumerate(df.columns if r == 0 else row.values): assert table[r if r == 0 else r+1, c].get_text().get_text() == str(col) + + +def test_table_fontsize(): + # Test that the passed fontsize propagates to cells + tableData = [['a', 1], ['b', 2]] + fig, ax = plt.subplots() + test_fontsize = 20 + t = ax.table(cellText=tableData, loc='top', fontsize=test_fontsize) + cell_fontsize = t[(0, 0)].get_fontsize() + assert cell_fontsize == test_fontsize, f"Actual:{test_fontsize},got:{cell_fontsize}" + cell_fontsize = t[(1, 1)].get_fontsize() + assert cell_fontsize == test_fontsize, f"Actual:{test_fontsize},got:{cell_fontsize}" diff --git a/lib/matplotlib/texmanager.py b/lib/matplotlib/texmanager.py index a374bfba8cab..2083510396f1 100644 --- a/lib/matplotlib/texmanager.py +++ b/lib/matplotlib/texmanager.py @@ -168,7 +168,10 @@ def get_basefile(cls, tex, fontsize, dpi=None): Return a filename based on a hash of the string, fontsize, and dpi. """ src = cls._get_tex_source(tex, fontsize) + str(dpi) - filehash = hashlib.md5(src.encode('utf-8')).hexdigest() + filehash = hashlib.sha256( + src.encode('utf-8'), + usedforsecurity=False + ).hexdigest() filepath = Path(cls._texcache) num_letters, num_levels = 2, 2 diff --git a/lib/matplotlib/ticker.py b/lib/matplotlib/ticker.py index 801359555a69..3d0059e5aca3 100644 --- a/lib/matplotlib/ticker.py +++ b/lib/matplotlib/ticker.py @@ -465,9 +465,11 @@ def __init__(self, useOffset=None, useMathText=None, useLocale=None, *, self.set_useLocale(useLocale) def get_usetex(self): + """Return whether TeX's math mode is enabled for rendering.""" return self._usetex def set_usetex(self, val): + """Set whether to use TeX's math mode for rendering numbers in the formatter.""" self._usetex = mpl._val_or_rc(val, 'text.usetex') usetex = property(fget=get_usetex, fset=set_usetex) diff --git a/lib/matplotlib/ticker.pyi b/lib/matplotlib/ticker.pyi index f990bf53ca42..bed288658909 100644 --- a/lib/matplotlib/ticker.pyi +++ b/lib/matplotlib/ticker.pyi @@ -295,3 +295,14 @@ class AutoLocator(MaxNLocator): class AutoMinorLocator(Locator): ndivs: int def __init__(self, n: int | None = ...) -> None: ... + +__all__ = ('TickHelper', 'Formatter', 'FixedFormatter', + 'NullFormatter', 'FuncFormatter', 'FormatStrFormatter', + 'StrMethodFormatter', 'ScalarFormatter', 'LogFormatter', + 'LogFormatterExponent', 'LogFormatterMathtext', + 'LogFormatterSciNotation', + 'LogitFormatter', 'EngFormatter', 'PercentFormatter', + 'Locator', 'IndexLocator', 'FixedLocator', 'NullLocator', + 'LinearLocator', 'LogLocator', 'AutoLocator', + 'MultipleLocator', 'MaxNLocator', 'AutoMinorLocator', + 'SymmetricalLogLocator', 'AsinhLocator', 'LogitLocator') diff --git a/lib/matplotlib/tri/_triinterpolate.pyi b/lib/matplotlib/tri/_triinterpolate.pyi index 8a56b22acdb2..33b2fd8be4cd 100644 --- a/lib/matplotlib/tri/_triinterpolate.pyi +++ b/lib/matplotlib/tri/_triinterpolate.pyi @@ -28,3 +28,5 @@ class CubicTriInterpolator(TriInterpolator): trifinder: TriFinder | None = ..., dz: tuple[ArrayLike, ArrayLike] | None = ..., ) -> None: ... + +__all__ = ('TriInterpolator', 'LinearTriInterpolator', 'CubicTriInterpolator') diff --git a/lib/mpl_toolkits/axes_grid1/tests/test_axes_grid1.py b/lib/mpl_toolkits/axes_grid1/tests/test_axes_grid1.py index 778bd9ca04d0..b045e8dc8756 100644 --- a/lib/mpl_toolkits/axes_grid1/tests/test_axes_grid1.py +++ b/lib/mpl_toolkits/axes_grid1/tests/test_axes_grid1.py @@ -346,7 +346,7 @@ def test_fill_facecolor(): # Update style when regenerating the test image @image_comparison(['zoomed_axes.png', 'inverted_zoomed_axes.png'], style=('classic', '_classic_test_patch'), - tol=0.02 if platform.machine() == 'arm64' else 0) + tol=0 if platform.machine() == 'x86_64' else 0.02) def test_zooming_with_inverted_axes(): fig, ax = plt.subplots() ax.plot([1, 2, 3], [1, 2, 3]) diff --git a/lib/mpl_toolkits/mplot3d/tests/test_axes3d.py b/lib/mpl_toolkits/mplot3d/tests/test_axes3d.py index ad952e4395af..b30c2556b105 100644 --- a/lib/mpl_toolkits/mplot3d/tests/test_axes3d.py +++ b/lib/mpl_toolkits/mplot3d/tests/test_axes3d.py @@ -221,9 +221,8 @@ def test_bar3d_lightsource(): np.testing.assert_array_max_ulp(color, collection._facecolor3d[1::6], 4) -@mpl3d_image_comparison( - ['contour3d.png'], style='mpl20', - tol=0.002 if platform.machine() in ('aarch64', 'arm64', 'ppc64le', 's390x') else 0) +@mpl3d_image_comparison(['contour3d.png'], style='mpl20', + tol=0 if platform.machine() == 'x86_64' else 0.002) def test_contour3d(): plt.rcParams['axes3d.automargin'] = True # Remove when image is regenerated fig = plt.figure() @@ -1713,7 +1712,7 @@ def test_errorbar3d_errorevery(): @mpl3d_image_comparison(['errorbar3d.png'], style='mpl20', - tol=0.02 if platform.machine() == 'arm64' else 0) + tol=0 if platform.machine() == 'x86_64' else 0.02) def test_errorbar3d(): """Tests limits, color styling, and legend for 3D errorbars.""" fig = plt.figure() @@ -1729,7 +1728,7 @@ def test_errorbar3d(): ax.legend() -@image_comparison(['stem3d.png'], style='mpl20', tol=0.008) +@image_comparison(['stem3d.png'], style='mpl20', tol=0.009) def test_stem3d(): plt.rcParams['axes3d.automargin'] = True # Remove when image is regenerated fig, axs = plt.subplots(2, 3, figsize=(8, 6), diff --git a/lib/mpl_toolkits/mplot3d/tests/test_legend3d.py b/lib/mpl_toolkits/mplot3d/tests/test_legend3d.py index 0935bbe7f6b0..7fd676df1e31 100644 --- a/lib/mpl_toolkits/mplot3d/tests/test_legend3d.py +++ b/lib/mpl_toolkits/mplot3d/tests/test_legend3d.py @@ -28,7 +28,7 @@ def test_legend_bar(): @image_comparison(['fancy.png'], remove_text=True, style='mpl20', - tol=0.011 if platform.machine() == 'arm64' else 0) + tol=0 if platform.machine() == 'x86_64' else 0.011) def test_fancy(): fig, ax = plt.subplots(subplot_kw=dict(projection='3d')) ax.plot(np.arange(10), np.full(10, 5), np.full(10, 5), 'o--', label='line') diff --git a/src/ft2font_wrapper.cpp b/src/ft2font_wrapper.cpp index 7e1b3948a00e..9b54721810d6 100644 --- a/src/ft2font_wrapper.cpp +++ b/src/ft2font_wrapper.cpp @@ -1475,7 +1475,13 @@ PyFT2Font_face_flags(PyFT2Font *self) static StyleFlags PyFT2Font_style_flags(PyFT2Font *self) { - return static_cast(self->x->get_face()->style_flags); + return static_cast(self->x->get_face()->style_flags & 0xffff); +} + +static FT_Long +PyFT2Font_num_named_instances(PyFT2Font *self) +{ + return (self->x->get_face()->style_flags & 0x7fff0000) >> 16; } static FT_Long @@ -1766,6 +1772,8 @@ PYBIND11_MODULE(ft2font, m, py::mod_gil_not_used()) "Face flags; see `.FaceFlags`.") .def_property_readonly("style_flags", &PyFT2Font_style_flags, "Style flags; see `.StyleFlags`.") + .def_property_readonly("num_named_instances", &PyFT2Font_num_named_instances, + "Number of named instances in the face.") .def_property_readonly("num_glyphs", &PyFT2Font_num_glyphs, "Number of glyphs in the face.") .def_property_readonly("num_fixed_sizes", &PyFT2Font_num_fixed_sizes, diff --git a/tools/cache_zenodo_svg.py b/tools/cache_zenodo_svg.py index 6e31c2a70011..3be7d6ca21e4 100644 --- a/tools/cache_zenodo_svg.py +++ b/tools/cache_zenodo_svg.py @@ -63,6 +63,7 @@ def _get_xdg_cache_dir(): if __name__ == "__main__": data = { + "v3.10.0": "14464227", "v3.9.4": "14436121", "v3.9.3": "14249941", "v3.9.2": "13308876",