From 3598222d904c92e9d184181d3f736be9d3a23922 Mon Sep 17 00:00:00 2001
From: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com>
Date: Wed, 1 Nov 2023 23:18:57 +0100
Subject: [PATCH 01/87] Backport PR #26703: moved communications guidelines
from governance, updated and clarified process
---
doc/_static/mpl.css | 19 +++
doc/devel/coding_guide.rst | 9 --
doc/devel/communication_guide.rst | 223 ++++++++++++++++++++++++++
doc/devel/index.rst | 1 +
doc/devel/release_guide.rst | 25 ++-
doc/users/project/code_of_conduct.rst | 2 +-
doc/users/release_notes.rst | 1 +
7 files changed, 257 insertions(+), 23 deletions(-)
create mode 100644 doc/devel/communication_guide.rst
diff --git a/doc/_static/mpl.css b/doc/_static/mpl.css
index 45ecb21d5511..a37fb76a0436 100644
--- a/doc/_static/mpl.css
+++ b/doc/_static/mpl.css
@@ -161,3 +161,22 @@ div.wide-table table th.stub {
font-style: italic;
font-size: large;
}
+
+
+.checklist {
+ list-style: none;
+ padding: 0;
+ margin: 0;
+}
+.checklist li {
+ margin-left: 24px;
+ padding-left: 23px;
+ margin-right: 6px;
+}
+.checklist li:before {
+ content: "\2610\2001";
+ margin-left: -24px;
+}
+.checklist li p {
+ display: inline;
+}
diff --git a/doc/devel/coding_guide.rst b/doc/devel/coding_guide.rst
index 49f35e3ad13e..0385d6d388f0 100644
--- a/doc/devel/coding_guide.rst
+++ b/doc/devel/coding_guide.rst
@@ -1,12 +1,3 @@
-.. raw:: html
-
-
-
.. _pr-guidelines:
***********************
diff --git a/doc/devel/communication_guide.rst b/doc/devel/communication_guide.rst
new file mode 100644
index 000000000000..b9fa301c0e46
--- /dev/null
+++ b/doc/devel/communication_guide.rst
@@ -0,0 +1,223 @@
+.. _communications-guidelines:
+
+========================
+Communication guidelines
+========================
+
+These guidelines are applicable when acting as a representative of Matplotlib,
+for example at sprints or when giving official talks or tutorials, and in any
+community venue managed by Matplotlib.
+
+
+.. _communication-channels:
+
+Official communication channels
+===============================
+The following venues are managed by Matplotlib maintainers and contributors:
+
+* library and docs: https://github.com/matplotlib/matplotlib
+* forum: https://discourse.matplotlib.org/
+* chat: `https://matrix.to/#/#matplotlib:matrix.org `_
+* blog: https://blog.scientific-python.org/
+
+.. _social-media:
+
+Social media
+------------
+
+Active social media
+^^^^^^^^^^^^^^^^^^^
+
+* https://twitter.com/matplotlib
+* https://instagram.com/matplotart/
+
+Official accounts
+^^^^^^^^^^^^^^^^^
+* https://bsky.app/profile/matplotlib.bsky.social
+* https://fosstodon.org/@matplotlib
+* https://www.tiktok.com/@matplotart
+* https://www.youtube.com/matplotlib
+
+
+.. _mailing-lists:
+
+Mailing lists
+-------------
+
+* `matplotlib-announce@python.org `_
+* `matplotlib-users@python.org `_
+* `matplotlib-devel@python.org `_
+
+.. _social-media-coordination:
+
+Social media coordination
+-------------------------
+* Team mailing list: matplotlib-social@numfocus.org
+* Public chat room: `https://matrix.to/#/#matplotlib_community:gitter.im `_
+
+
+Maintenance
+-----------
+
+If you are interested in moderating the chat or forum or accessing the social
+media accounts:
+
+* Matplotlib maintainers should reach out to the `community-manager`_.
+
+* Everyone else should send an email to matplotlib-social-admin@numfocus.org:
+
+ * Introduce yourself - github handle and participation in the community.
+ * Describe the reason for wanting to moderate or contribute to social.
+
+
+Content guidelines
+==================
+
+Communication on official channels, such as the Matplotlib homepage or on
+Matplotlib social accounts, should conform to the following standards. If you
+are unsure if content that you would like to post or share meets these
+guidelines, ask on the :ref:`social-media-coordination` channels before posting.
+
+General guidelines
+------------------
+
+* Focus on Matplotlib, 3rd party packages, and visualizations made with Matplotlib.
+* These are also acceptable topics:
+
+ * Visualization best practices and libraries.
+ * Projects and initiatives by NumFOCUS and Scientific Python.
+ * How to contribute to open source projects.
+ * Projects, such as scientific papers, that use Matplotlib.
+
+* No gratuitous disparaging of other visualization libraries and tools, but
+ criticism is acceptable so long as it serves a constructive purpose.
+
+* Follow communication best practices:
+
+ * Do not share non-expert visualizations when it could cause harm:
+
+ * e.g. https://twitter.com/matplotlib/status/1244178154618605568
+
+ * Clearly state when the visualization data/conclusions cannot be verified.
+ * Do not rely on machine translations for sensitive visualization.
+
+* Verify sourcing of content (especially on instagram & blog):
+
+ * Instagram/blog: ensure mpl has right to repost/share content
+ * Make sure content is clearly cited:
+
+ * e.g. a tutorial reworking an example must credit the original example
+
+* Limited self/corporate promotion is acceptable.
+
+ * Should be no more than about a quarter of the content.
+
+Visual media guidelines
+-----------------------
+
+Visual media, such as images and videos, must not violate the
+:ref:`code of conduct `, nor any platform's rules.
+Specifically:
+
+* Visual media must conform to the guidelines of all sites it may be posted on:
+
+ * https://help.twitter.com/en/rules-and-policies/twitter-rules
+ * https://help.instagram.com/477434105621119
+
+* Emphasize the visualization techniques demonstrated by the visual media.
+* Clearly state that sharing is not an endorsement of the content.
+
+ * e.g. bitcoin related visualizations
+
+Accessibility
+^^^^^^^^^^^^^
+
+Visual media in communications should be made as accessible as possible:
+
+* Add alt text to images and videos when the platform allows:
+
+ * `alt text for data viz `_
+ * `general alt text guide `_
+
+* Warn on bright, strobing, images & turn off autoplay if possible.
+* For images and videos made by the social media team:
+
+ * Make graphic perceivable to people who cannot perceive color well due to
+ color-blindness, low vision, or any other reason.
+
+ * Do not make bright, strobing images.
+ * More guidelines at https://webaim.org/techniques/images/.
+
+
+Social media
+============
+
+Please follow these guidelines to maintain a consistent brand identity across
+platforms.
+
+Persona
+-------
+On social media, Matplotlib:
+
+* Acts as a sentient visualization library, so talks about itself as a we, us,
+ our, and it. Avoids talking about itself in the 3rd person. Never uses 1st person.
+* Is very earnest, eager to please, and aims to be patient & painfully oblivious
+ to snark and sarcasm.
+* Gets over-excited over shiny visualizations - lots of emojis and the like -
+ and encourages folks to share their work.
+* Highlights various parts of the library, especially the more obscure bits and
+ bobbles.
+* Acknowledges that it is a sometimes frustrating tangle of bits & bobbles that
+ can confuse even the folks who work on it & signal boosts their confuzzlment.
+
+
+Behavior
+--------
+When acting as a representative of the library, keep responses polite and assume
+user statements are in good faith unless they violate the :ref:`code of conduct `.
+
+Social graph
+------------
+
+Only follow **organizations and projects**, do not follow individual accounts for
+any reason, even maintainers/project leads/famous Python people!
+
+Following these types of accounts is encouraged:
+
+* NumFocus and Scientific Python projects
+* 3rd party packages
+* Visualization related projects and organizations
+* Open Source community projects
+* Sponsors
+
+Recurring campaigns
+-------------------
+
+Typically the social media accounts will promote the following:
+
+* Matplotlib releases:
+
+ * Highlight new features & major deprecations
+ * Link to download/install instructions
+ * Ask folks to try it out.
+
+* `third party packages `_
+* NumFocus/Scientific Python/open source visualization project releases
+* GSOC/GSOD recruiting and progress
+
+Retired campaigns
+^^^^^^^^^^^^^^^^^
+* John Hunter Excellence in Plotting, submission and winners
+
+
+Changing the guidelines
+=======================
+
+As the person tasked with implementing communications, the `community-manager`_
+should be alerted to proposed changes to the communications guidelines. Similarly,
+specific platform guidelines (e.g. twitter, instagram) should be reviewed by the
+person responsible for that platform, when different from the community manager.
+If there is no consensus, decisions about communications guidelines revert to
+the community manager.
+
+.. _community-manager: https://matplotlib.org/governance/people.html#deputy-project-leads
diff --git a/doc/devel/index.rst b/doc/devel/index.rst
index 2b358595255b..9537859c107a 100644
--- a/doc/devel/index.rst
+++ b/doc/devel/index.rst
@@ -167,6 +167,7 @@ Policies and guidelines
:maxdepth: 1
release_guide
+ communication_guide
min_dep_policy
MEP/index
diff --git a/doc/devel/release_guide.rst b/doc/devel/release_guide.rst
index 2bbe589282a3..4adc4546e879 100644
--- a/doc/devel/release_guide.rst
+++ b/doc/devel/release_guide.rst
@@ -455,22 +455,21 @@ Due to branch protections for the ``main`` branch, this is merged via a standard
request, though the PR cleanliness status check is expected to fail. The PR should not
be squashed because the intent is to merge the branch histories.
-Announcing
-==========
+Publicize this release
+======================
-The final step is to announce the release to the world. A short
-version of the release notes along with acknowledgments should be sent to
+After the release is published to PyPI and conda, it should be announced
+through our communication channels:
-- matplotlib-users@python.org
-- matplotlib-devel@python.org
-- matplotlib-announce@python.org
-
-In addition, announcements should be made on social networks (e.g., Twitter via the
-``@matplotlib`` account, any other via personal accounts).
-
-Add a release announcement to the ``mpl-brochure-site`` "News" section of
-``docs/body.html``, linking to the discourse page for the announcement.
+.. rst-class:: checklist
+* Send a short version of the release notes and acknowledgments to all the :ref:`mailing-lists`
+* Post highlights and link to :ref:`What's new ` on the
+ active :ref:`social media accounts `
+* Add a release announcement to the "News" section of
+ `matplotlib.org `_ by editing
+ ``docs/body.html``. Link to the auto-generated announcement discourse post,
+ which is in `Announcements > matplotlib-announcements `_.
Conda packages
==============
diff --git a/doc/users/project/code_of_conduct.rst b/doc/users/project/code_of_conduct.rst
index 8deda909bd4c..ac8b268a4e30 100644
--- a/doc/users/project/code_of_conduct.rst
+++ b/doc/users/project/code_of_conduct.rst
@@ -1,4 +1,4 @@
-.. code_of_conduct
+.. _code_of_conduct:
====================================
Contributor Covenant Code of Conduct
diff --git a/doc/users/release_notes.rst b/doc/users/release_notes.rst
index 12cb60d2fb0d..ca09d218cae4 100644
--- a/doc/users/release_notes.rst
+++ b/doc/users/release_notes.rst
@@ -1,6 +1,7 @@
.. redirect-from:: /api/api_changes_old
.. redirect-from:: /users/whats_new_old
+.. _release-notes:
=============
Release notes
From c80aaa1312ff2acad0d5f371df3fc184595dd241 Mon Sep 17 00:00:00 2001
From: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com>
Date: Thu, 2 Nov 2023 23:42:05 +0100
Subject: [PATCH 02/87] Backport PR #27249: DOC: reasoning for communications
guidelines
---
doc/devel/communication_guide.rst | 66 +++++++++++++++++++++++++------
doc/users/project/mission.rst | 2 +
2 files changed, 56 insertions(+), 12 deletions(-)
diff --git a/doc/devel/communication_guide.rst b/doc/devel/communication_guide.rst
index b9fa301c0e46..aed52be84e32 100644
--- a/doc/devel/communication_guide.rst
+++ b/doc/devel/communication_guide.rst
@@ -1,18 +1,41 @@
.. _communications-guidelines:
-========================
-Communication guidelines
-========================
+==========================
+Community management guide
+==========================
-These guidelines are applicable when acting as a representative of Matplotlib,
+These guidelines are applicable when **acting as a representative** of Matplotlib,
for example at sprints or when giving official talks or tutorials, and in any
community venue managed by Matplotlib.
+Our approach to community engagement is foremost guided by our :ref:`mission-statement`:
+
+* We demonstrate that we care about visualization as a practice
+* We deepen our practice and the community’s capacity to support users,
+ facilitate exploration, produce high quality visualizations, and be
+ understandable and extensible
+* We showcase advanced use of the library without adding maintenance burden to
+ the documentation and recognize contributions that happen outside of the github
+ workflow.
+* We use communications platforms to maintain relationships with contributors
+ who may no longer be active on GitHub, build relationships with potential
+ contributors, and connect with other projects and communities who use
+ Matplotlib.
+* In prioritizing understandability and extensiblity, we recognize that people
+ using Matplotlib, in whatever capacity, are part of our community. Doing so
+ empowers our community members to build community with each other, for example
+ by creating educational resources, building third party tools, and building
+ informal mentoring networks.
.. _communication-channels:
Official communication channels
===============================
+The Scientific Python community uses various communications platforms to stay
+updated on new features and projects, to contribute by telling us what is on
+their mind and suggest issues and bugs, and to showcase their use cases and the
+tools they have built.
+
The following venues are managed by Matplotlib maintainers and contributors:
* library and docs: https://github.com/matplotlib/matplotlib
@@ -148,12 +171,32 @@ Visual media in communications should be made as accessible as possible:
* Do not make bright, strobing images.
* More guidelines at https://webaim.org/techniques/images/.
+.. _social-media-brand:
Social media
============
-Please follow these guidelines to maintain a consistent brand identity across
-platforms.
+Matplotlib aims for a single voice across all social media platforms to build and
+maintain a consistent brand identity for Matplotlib as an organization. This
+depersonalization is the norm on social media platforms because it enables
+constructive and productive conversations; People generally feel more comfortable
+giving negative and constructive feedback to a brand than to specific contributors.
+
+The current Matplotlib voice and persona aims to be kind, patient, supportive and
+educational. This is so that it can de-escalate tensions and facilitate
+constructive conversations; being perceived as negative or
+argumentative can escalate very fast into long-lasting brand damage, being
+perceived as personal leads to aggression and accusations faster than an
+impersonal account, and being perceived as friendly and approachable leads to
+higher engagement. Instead of speaking with a directive authority, which can be
+intimidating and lead to negative engagement, it speaks as a peer or educator to
+empower participation. The current voice encourages more input from folks we
+engage with, and also makes it possible for folks who are not in the core team
+to participate in managing the account.
+
+While the :ref:`brand identity ` is casual, the showcased
+content is high quality, peer-led resource building. Please follow these
+guidelines to maintain a consistent brand identity across platforms.
Persona
-------
@@ -213,11 +256,10 @@ Retired campaigns
Changing the guidelines
=======================
-As the person tasked with implementing communications, the `community-manager`_
-should be alerted to proposed changes to the communications guidelines. Similarly,
-specific platform guidelines (e.g. twitter, instagram) should be reviewed by the
-person responsible for that platform, when different from the community manager.
-If there is no consensus, decisions about communications guidelines revert to
-the community manager.
+As the person tasked with implementing these guidelines, the `community-manager`_
+should be alerted to proposed changes. Similarly, specific platform guidelines
+(e.g. twitter, instagram) should be reviewed by the person responsible for that
+platform, when different from the community manager. If there is no consensus,
+decisions about guidelines revert to the community manager.
.. _community-manager: https://matplotlib.org/governance/people.html#deputy-project-leads
diff --git a/doc/users/project/mission.rst b/doc/users/project/mission.rst
index 431da04e4891..438d2fce8b1d 100644
--- a/doc/users/project/mission.rst
+++ b/doc/users/project/mission.rst
@@ -1,3 +1,5 @@
+.. _mission-statement:
+
Mission Statement
=================
From af7343c67cc93f0e1028d49e487a03c206d087fe Mon Sep 17 00:00:00 2001
From: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com>
Date: Thu, 2 Nov 2023 23:42:05 +0100
Subject: [PATCH 03/87] Backport PR #27249: DOC: reasoning for communications
guidelines
---
doc/devel/communication_guide.rst | 66 +++++++++++++++++++++++++------
doc/users/project/mission.rst | 2 +
2 files changed, 56 insertions(+), 12 deletions(-)
diff --git a/doc/devel/communication_guide.rst b/doc/devel/communication_guide.rst
index b9fa301c0e46..aed52be84e32 100644
--- a/doc/devel/communication_guide.rst
+++ b/doc/devel/communication_guide.rst
@@ -1,18 +1,41 @@
.. _communications-guidelines:
-========================
-Communication guidelines
-========================
+==========================
+Community management guide
+==========================
-These guidelines are applicable when acting as a representative of Matplotlib,
+These guidelines are applicable when **acting as a representative** of Matplotlib,
for example at sprints or when giving official talks or tutorials, and in any
community venue managed by Matplotlib.
+Our approach to community engagement is foremost guided by our :ref:`mission-statement`:
+
+* We demonstrate that we care about visualization as a practice
+* We deepen our practice and the community’s capacity to support users,
+ facilitate exploration, produce high quality visualizations, and be
+ understandable and extensible
+* We showcase advanced use of the library without adding maintenance burden to
+ the documentation and recognize contributions that happen outside of the github
+ workflow.
+* We use communications platforms to maintain relationships with contributors
+ who may no longer be active on GitHub, build relationships with potential
+ contributors, and connect with other projects and communities who use
+ Matplotlib.
+* In prioritizing understandability and extensiblity, we recognize that people
+ using Matplotlib, in whatever capacity, are part of our community. Doing so
+ empowers our community members to build community with each other, for example
+ by creating educational resources, building third party tools, and building
+ informal mentoring networks.
.. _communication-channels:
Official communication channels
===============================
+The Scientific Python community uses various communications platforms to stay
+updated on new features and projects, to contribute by telling us what is on
+their mind and suggest issues and bugs, and to showcase their use cases and the
+tools they have built.
+
The following venues are managed by Matplotlib maintainers and contributors:
* library and docs: https://github.com/matplotlib/matplotlib
@@ -148,12 +171,32 @@ Visual media in communications should be made as accessible as possible:
* Do not make bright, strobing images.
* More guidelines at https://webaim.org/techniques/images/.
+.. _social-media-brand:
Social media
============
-Please follow these guidelines to maintain a consistent brand identity across
-platforms.
+Matplotlib aims for a single voice across all social media platforms to build and
+maintain a consistent brand identity for Matplotlib as an organization. This
+depersonalization is the norm on social media platforms because it enables
+constructive and productive conversations; People generally feel more comfortable
+giving negative and constructive feedback to a brand than to specific contributors.
+
+The current Matplotlib voice and persona aims to be kind, patient, supportive and
+educational. This is so that it can de-escalate tensions and facilitate
+constructive conversations; being perceived as negative or
+argumentative can escalate very fast into long-lasting brand damage, being
+perceived as personal leads to aggression and accusations faster than an
+impersonal account, and being perceived as friendly and approachable leads to
+higher engagement. Instead of speaking with a directive authority, which can be
+intimidating and lead to negative engagement, it speaks as a peer or educator to
+empower participation. The current voice encourages more input from folks we
+engage with, and also makes it possible for folks who are not in the core team
+to participate in managing the account.
+
+While the :ref:`brand identity ` is casual, the showcased
+content is high quality, peer-led resource building. Please follow these
+guidelines to maintain a consistent brand identity across platforms.
Persona
-------
@@ -213,11 +256,10 @@ Retired campaigns
Changing the guidelines
=======================
-As the person tasked with implementing communications, the `community-manager`_
-should be alerted to proposed changes to the communications guidelines. Similarly,
-specific platform guidelines (e.g. twitter, instagram) should be reviewed by the
-person responsible for that platform, when different from the community manager.
-If there is no consensus, decisions about communications guidelines revert to
-the community manager.
+As the person tasked with implementing these guidelines, the `community-manager`_
+should be alerted to proposed changes. Similarly, specific platform guidelines
+(e.g. twitter, instagram) should be reviewed by the person responsible for that
+platform, when different from the community manager. If there is no consensus,
+decisions about guidelines revert to the community manager.
.. _community-manager: https://matplotlib.org/governance/people.html#deputy-project-leads
diff --git a/doc/users/project/mission.rst b/doc/users/project/mission.rst
index 431da04e4891..438d2fce8b1d 100644
--- a/doc/users/project/mission.rst
+++ b/doc/users/project/mission.rst
@@ -1,3 +1,5 @@
+.. _mission-statement:
+
Mission Statement
=================
From a614491070d443801c3e9a2a221ce85117bb667f Mon Sep 17 00:00:00 2001
From: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com>
Date: Fri, 3 Nov 2023 08:21:41 +0100
Subject: [PATCH 04/87] Backport PR #27213: DOC: consolidated coding guide and
added naming conventions table
---
doc/api/next_api_changes/README.rst | 12 +-
doc/devel/coding_guide.rst | 214 ++++++-------------------
doc/devel/contribute.rst | 237 ++++++++++++++++++++++++----
doc/devel/development_setup.rst | 2 +
doc/devel/development_workflow.rst | 17 ++
doc/users/next_whats_new/README.rst | 12 +-
6 files changed, 292 insertions(+), 202 deletions(-)
diff --git a/doc/api/next_api_changes/README.rst b/doc/api/next_api_changes/README.rst
index de494911e6b2..75e70b456eb9 100644
--- a/doc/api/next_api_changes/README.rst
+++ b/doc/api/next_api_changes/README.rst
@@ -22,11 +22,17 @@ author's initials. Typically, each change will get its own file, but you may
also amend existing files when suitable. The overall goal is a comprehensible
documentation of the changes.
-Please avoid using references in section titles, as it causes links to be
-confusing in the table of contents. Instead, ensure that a reference is
-included in the descriptive text. A typical entry could look like this::
+A typical entry could look like this::
Locators
~~~~~~~~
The unused `Locator.autoscale()` method is deprecated (pass the axis
limits to `Locator.view_limits()` instead).
+
+Please avoid using references in section titles, as it causes links to be
+confusing in the table of contents. Instead, ensure that a reference is
+included in the descriptive text.
+
+.. NOTE
+ Lines 5-30 of this file are include in :ref:`api_whats_new`;
+ therefore, please check the doc build after changing this file.
diff --git a/doc/devel/coding_guide.rst b/doc/devel/coding_guide.rst
index 0385d6d388f0..22873020f103 100644
--- a/doc/devel/coding_guide.rst
+++ b/doc/devel/coding_guide.rst
@@ -8,144 +8,82 @@ Pull request guidelines
`__
are the mechanism for contributing to Matplotlib's code and documentation.
-It is recommended to check that your contribution complies with the following
-rules before submitting a pull request:
+We value contributions from people with all levels of experience. In particular,
+if this is your first PR not everything has to be perfect. We'll guide you
+through the PR process. Nevertheless, please try to follow our guidelines as well
+as you can to help make the PR process quick and smooth. If your pull request is
+incomplete or a work-in-progress, please mark it as a `draft pull requests `_
+on GitHub and specify what feedback from the developers would be helpful.
-* If your pull request addresses an issue, please use the title to describe the
- issue (e.g. "Add ability to plot timedeltas") and mention the issue number
- in the pull request description to ensure that a link is created to the
- original issue (e.g. "Closes #8869" or "Fixes #8869"). This will ensure the
- original issue mentioned is automatically closed when your PR is merged. See
- `the GitHub documentation
- `__
- for more details.
-
-* Formatting should follow the recommendations of PEP8_, as enforced by
- flake8_. Matplotlib modifies PEP8 to extend the maximum line length to 88
- characters. You can check flake8 compliance from the command line with ::
-
- python -m pip install flake8
- flake8 /path/to/module.py
-
- or your editor may provide integration with it. Note that Matplotlib
- intentionally does not use the black_ auto-formatter (1__), in particular due
- to its inability to understand the semantics of mathematical expressions
- (2__, 3__).
-
- .. _PEP8: https://www.python.org/dev/peps/pep-0008/
- .. _flake8: https://flake8.pycqa.org/
- .. _black: https://black.readthedocs.io/
- .. __: https://github.com/matplotlib/matplotlib/issues/18796
- .. __: https://github.com/psf/black/issues/148
- .. __: https://github.com/psf/black/issues/1984
-
-* All public methods should have informative docstrings with sample usage when
- appropriate. Use the :ref:`docstring standards `.
-
-* For high-level plotting functions, consider adding a simple example either in
- the ``Example`` section of the docstring or the
- :ref:`examples gallery `.
-
-* Changes (both new features and bugfixes) should have good test coverage. See
- :ref:`testing` for more details.
-
-* Import the following modules using the standard scipy conventions::
+Please be patient with reviewers. We try our best to respond quickly, but we have
+limited bandwidth. If there is no feedback within a couple of days, please ping
+us by posting a comment to your PR or reaching out on a :ref:`communication channel `
- import numpy as np
- import numpy.ma as ma
- import matplotlib as mpl
- import matplotlib.pyplot as plt
- import matplotlib.cbook as cbook
- import matplotlib.patches as mpatches
- In general, Matplotlib modules should **not** import `.rcParams` using ``from
- matplotlib import rcParams``, but rather access it as ``mpl.rcParams``. This
- is because some modules are imported very early, before the `.rcParams`
- singleton is constructed.
-
-* If your change is a major new feature, add an entry to the ``What's new``
- section by adding a new file in ``doc/users/next_whats_new`` (see
- :file:`doc/users/next_whats_new/README.rst` for more information).
+Summary for pull request authors
+================================
-* If you change the API in a backward-incompatible way, please document it in
- :file:`doc/api/next_api_changes/behavior`, by adding a new file with the
- naming convention ``99999-ABC.rst`` where the pull request number is followed
- by the contributor's initials. (see :file:`doc/api/api_changes.rst` for more
- information)
+We recommend that you check that your contribution complies with the following
+guidelines before submitting a pull request:
-* If you add new public API or change public API, update or add the
- corresponding type hints. Most often this is found in the corresponding
- ``.pyi`` file for the ``.py`` file which was edited. Changes in ``pyplot.py``
- are type hinted inline.
+.. rst-class:: checklist
-* See below for additional points about :ref:`keyword-argument-processing`, if
- applicable for your pull request.
+* Changes, both new features and bugfixes, should have good test coverage. See
+ :ref:`testing` for more details.
-.. note::
+* Update the :ref:`documentation ` if necessary.
- The current state of the Matplotlib code base is not compliant with all
- of these guidelines, but we expect that enforcing these constraints on all
- new contributions will move the overall code base quality in the right
- direction.
+* All public methods should have informative docstrings with sample usage when
+ appropriate. Use the :ref:`docstring standards `.
+* For high-level plotting functions, consider adding a small example to the
+ :ref:`examples gallery `.
-.. seealso::
+* If you add a major new feature or change the API in a backward-incompatible
+ way, please document it as described in :ref:`new-changed-api`
- * :ref:`coding_guidelines`
- * :ref:`testing`
- * :ref:`documenting-matplotlib`
+* Code should follow our conventions as documented in our :ref:`coding_guidelines`
+* When adding or changing public function signatures, add :ref:`type hints `
+* When adding keyword arguments, see our guide to :ref:`keyword-argument-processing`.
-Summary for pull request authors
-================================
+When opening a pull request on Github, please ensure that:
-.. note::
+.. rst-class:: checklist
- * We value contributions from people with all levels of experience. In
- particular if this is your first PR not everything has to be perfect.
- We'll guide you through the PR process.
- * Nevertheless, please try to follow the guidelines below as well as you can to
- help make the PR process quick and smooth.
- * Be patient with reviewers. We try our best to respond quickly, but we
- have limited bandwidth. If there is no feedback within a couple of days,
- please ping us by posting a comment to your PR.
+* Changes were made on a :ref:`feature branch `.
-When making a PR, pay attention to:
+* :ref:`pre-commit ` checks for spelling, formatting, etc pass
-.. rst-class:: checklist
+* The pull request targets the :ref:`main branch `
-* :ref:`Target the main branch `.
-* Adhere to the :ref:`coding_guidelines`.
-* Update the :ref:`documentation ` if necessary.
-* Aim at making the PR as "ready-to-go" as you can. This helps to speed up
- the review process.
-* It is ok to open incomplete or work-in-progress PRs if you need help or
- feedback from the developers. You may mark these as
- `draft pull requests `_
- on GitHub.
-* When updating your PR, instead of adding new commits to fix something, please
- consider amending your initial commit(s) to keep the history clean.
- You can achieve this by using
+* If your pull request addresses an issue, please use the title to describe the
+ issue (e.g. "Add ability to plot timedeltas") and mention the issue number
+ in the pull request description to ensure that a link is created to the
+ original issue (e.g. "Closes #8869" or "Fixes #8869"). This will ensure the
+ original issue mentioned is automatically closed when your PR is merged. For more
+ details, see `linking an issue and pull request `__.
- .. code-block:: bash
+* :ref:`pr-automated-tests` pass
- git commit --amend --no-edit
- git push [your-remote-repo] [your-branch] --force-with-lease
+For guidance on creating and managing a pull request, please see our
+:ref:`contributing ` and :ref:`pull request workflow `
+guides.
-See also :ref:`contributing` for how to make a PR.
Summary for pull request reviewers
==================================
.. redirect-from:: /devel/maintainer_workflow
-.. note::
+**Please help review and merge PRs!**
+
+If you have commit rights, then you are trusted to use them. Please be patient
+and `kind `__ with contributors.
- * If you have commit rights, then you are trusted to use them.
- **Please help review and merge PRs!**
- * Be patient and `kind `__ with
- contributors.
+When reviewing, please ensure that the pull request satisfies the following
+requirements before merging it:
Content topics:
@@ -196,61 +134,6 @@ Documentation
* See :ref:`documenting-matplotlib` for our documentation style guide.
-.. _release_notes:
-
-New features and API changes
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-When adding a major new feature or changing the API in a backward incompatible
-way, please document it by including a versioning directive in the docstring
-and adding an entry to the folder for either the what's new or API change notes.
-
-+-------------------+-----------------------------+----------------------------------+
-| for this addition | include this directive | create entry in this folder |
-+===================+=============================+==================================+
-| new feature | ``.. versionadded:: 3.N`` | :file:`doc/users/next_whats_new/`|
-+-------------------+-----------------------------+----------------------------------+
-| API change | ``.. versionchanged:: 3.N`` | :file:`doc/api/next_api_changes/`|
-| | | |
-| | | probably in ``behavior/`` |
-+-------------------+-----------------------------+----------------------------------+
-
-The directives should be placed at the end of a description block. For example::
-
- class Foo:
- """
- This is the summary.
-
- Followed by a longer description block.
-
- Consisting of multiple lines and paragraphs.
-
- .. versionadded:: 3.5
-
- Parameters
- ----------
- a : int
- The first parameter.
- b: bool, default: False
- This was added later.
-
- .. versionadded:: 3.6
- """
-
- def set_b(b):
- """
- Set b.
-
- .. versionadded:: 3.6
-
- Parameters
- ----------
- b: bool
-
-For classes and functions, the directive should be placed before the
-*Parameters* section. For parameters, the directive should be placed at the
-end of the parameter description. The patch release version is omitted and
-the directive should not be added to entire modules.
-
.. _pr-labels:
Labels
@@ -330,7 +213,8 @@ Merging
Automated tests
---------------
-Before being merged, a PR should pass the :ref:`automated-tests`. If you are unsure why a test is failing, ask on the PR or in our `chat space `_
+Before being merged, a PR should pass the :ref:`automated-tests`. If you are
+unsure why a test is failing, ask on the PR or in our :ref:`communication-channels`
.. _pr-squashing:
diff --git a/doc/devel/contribute.rst b/doc/devel/contribute.rst
index a9bfb0f816dd..ee78beca0781 100644
--- a/doc/devel/contribute.rst
+++ b/doc/devel/contribute.rst
@@ -367,27 +367,160 @@ project that leads to a scientific publication, please follow the
Coding guidelines
=================
-API changes
------------
+While the current state of the Matplotlib code base is not compliant with all
+of these guidelines, our goal in enforcing these constraints on new
+contributions is that it improves the readability and consistency of the code base
+going forward.
-API consistency and stability are of great value. Therefore, API changes
-(e.g. signature changes, behavior changes, removals) will only be conducted
-if the added benefit is worth the user effort for adapting.
+PEP8, as enforced by flake8
+---------------------------
+
+Formatting should follow the recommendations of PEP8_, as enforced by flake8_.
+Matplotlib modifies PEP8 to extend the maximum line length to 88
+characters. You can check flake8 compliance from the command line with ::
+
+ python -m pip install flake8
+ flake8 /path/to/module.py
+
+or your editor may provide integration with it. Note that Matplotlib intentionally
+does not use the black_ auto-formatter (1__), in particular due to its inability
+to understand the semantics of mathematical expressions (2__, 3__).
+
+.. _PEP8: https://www.python.org/dev/peps/pep-0008/
+.. _flake8: https://flake8.pycqa.org/
+.. _black: https://black.readthedocs.io/
+.. __: https://github.com/matplotlib/matplotlib/issues/18796
+.. __: https://github.com/psf/black/issues/148
+.. __: https://github.com/psf/black/issues/1984
+
+
+Package imports
+---------------
+Import the following modules using the standard scipy conventions::
+
+ import numpy as np
+ import numpy.ma as ma
+ import matplotlib as mpl
+ import matplotlib.pyplot as plt
+ import matplotlib.cbook as cbook
+ import matplotlib.patches as mpatches
+
+In general, Matplotlib modules should **not** import `.rcParams` using ``from
+matplotlib import rcParams``, but rather access it as ``mpl.rcParams``. This
+is because some modules are imported very early, before the `.rcParams`
+singleton is constructed.
+
+Variable names
+--------------
+
+When feasible, please use our internal variable naming convention for objects
+of a given class and objects of any child class:
+
++------------------------------------+---------------+------------------------------------------+
+| base class | variable | multiples |
++====================================+===============+==========================================+
+| `~matplotlib.figure.FigureBase` | ``fig`` | |
++------------------------------------+---------------+------------------------------------------+
+| `~matplotlib.axes.Axes` | ``ax`` | |
++------------------------------------+---------------+------------------------------------------+
+| `~matplotlib.transforms.Transform` | ``trans`` | ``trans__`` |
++ + + +
+| | | ``trans_`` when target is screen |
++------------------------------------+---------------+------------------------------------------+
+
+Generally, denote more than one instance of the same class by adding suffixes to
+the variable names. If a format isn't specified in the table, use numbers or
+letters as appropriate.
+
+
+.. _type-hints:
+
+Type hints
+----------
+
+If you add new public API or change public API, update or add the
+corresponding `mypy `_ type hints.
+We generally use `stub files
+`_
+(``*.pyi``) to store the type information; for example ``colors.pyi`` contains
+the type information for ``colors.py``. A notable exception is ``pyplot.py``,
+which is type hinted inline.
+
+Type hints are checked by the mypy :ref:`pre-commit hook `
+and can often be verified using ``tools\stubtest.py`` and occasionally may
+require the use of ``tools\check_typehints.py``.
+
+
+.. _new-changed-api:
-Because we are a visualization library our primary output is the final
-visualization the user sees. Thus it is our :ref:`long standing
-` policy that the appearance of the figure is part of the API
-and any changes, either semantic or esthetic, will be treated as a
-backwards-incompatible API change.
+API changes and new features
+----------------------------
+API consistency and stability are of great value; Therefore, API changes
+(e.g. signature changes, behavior changes, removals) will only be conducted
+if the added benefit is worth the effort of adapting existing code.
+
+Because we are a visualization library, our primary output is the final
+visualization the user sees; therefore, the appearance of the figure is part of
+the API and any changes, either semantic or :ref:`esthetic `,
+are backwards-incompatible API changes.
+
+.. _api_whats_new:
+
+Announce changes, deprecations, and new features
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+When adding or changing the API in a backward in-compatible way, please add the
+appropriate :ref:`versioning directive ` and document it
+for the release notes and add the entry to the appropriate folder:
+
++-------------------+-----------------------------+----------------------------------------------+
+| addition | versioning directive | announcement folder |
++===================+=============================+==============================================+
+| new feature | ``.. versionadded:: 3.N`` | :file:`doc/users/next_whats_new/` |
++-------------------+-----------------------------+----------------------------------------------+
+| API change | ``.. versionchanged:: 3.N`` | :file:`doc/api/next_api_changes/[kind]` |
++-------------------+-----------------------------+----------------------------------------------+
+
+API deprecations are first introduced and then expired. During the introduction
+period, users are warned that the API *will* change in the future.
+During the expiration period, code is changed as described in the notice posted
+during the introductory period.
+
++-----------+--------------------------------------------------+----------------------------------------------+
+| stage | required changes | announcement folder |
++===========+==================================================+==============================================+
+| introduce | :ref:`introduce deprecation ` | :file:`doc/api/next_api_changes/deprecation` |
++-----------+--------------------------------------------------+----------------------------------------------+
+| expire | :ref:`expire deprecation ` | :file:`doc/api/next_api_changes/[kind]` |
++-----------+--------------------------------------------------+----------------------------------------------+
+
+For both change notes and what's new, please avoid using references in section
+titles, as it causes links to be confusing in the table of contents. Instead,
+ensure that a reference is included in the descriptive text.
+
+API Change Notes
+""""""""""""""""
+.. include:: ../api/next_api_changes/README.rst
+ :start-line: 5
+ :end-line: 31
+
+What's new
+""""""""""
+.. include:: ../users/next_whats_new/README.rst
+ :start-line: 5
+ :end-line: 24
+
+
+Deprecation
+^^^^^^^^^^^
API changes in Matplotlib have to be performed following the deprecation process
-below, except in very rare circumstances as deemed necessary by the development team.
-This ensures that users are notified before the change will take effect and thus
-prevents unexpected breaking of code.
+below, except in very rare circumstances as deemed necessary by the development
+team. This ensures that users are notified before the change will take effect
+and thus prevents unexpected breaking of code.
Rules
-^^^^^
-
+"""""
- Deprecations are targeted at the next point.release (e.g. 3.x)
- Deprecated API is generally removed two point-releases after introduction
of the deprecation. Longer deprecations can be imposed by core developers on
@@ -398,12 +531,12 @@ Rules
- If in doubt, decisions about API changes are finally made by the
API consistency lead developer
-Introducing
-^^^^^^^^^^^
+.. _intro-deprecation:
+
+Introduce deprecation
+"""""""""""""""""""""
-#. Announce the deprecation in a new file
- :file:`doc/api/next_api_changes/deprecations/99999-ABC.rst` where ``99999``
- is the pull request number and ``ABC`` are the contributor's initials.
+#. Create :ref:`deprecation notice `
#. If possible, issue a `~matplotlib.MatplotlibDeprecationWarning` when the
deprecated API is used. There are a number of helper tools for this:
@@ -439,16 +572,13 @@ Introducing
:file:`ci/mypy-stubtest-allowlist.txt` under a heading indicating the deprecation
version number.
-Expiring
-^^^^^^^^
+.. _expire-deprecation:
+
+Expire deprecation
+""""""""""""""""""
-#. Announce the API changes in a new file
- :file:`doc/api/next_api_changes/[kind]/99999-ABC.rst` where ``99999``
- is the pull request number and ``ABC`` are the contributor's initials, and
- ``[kind]`` is one of the folders :file:`behavior`, :file:`development`,
- :file:`removals`. See :file:`doc/api/next_api_changes/README.rst` for more
- information. For the content, you can usually copy the deprecation notice
- and adapt it slightly.
+#. Create :ref:`deprecation announcement `. For the content,
+ you can usually copy the deprecation notice and adapt it slightly.
#. Change the code functionality and remove any related deprecation warnings.
@@ -466,8 +596,8 @@ Expiring
require that mechanism for deprecation. For removed items that were not in the stub
file, only deleting from the allowlist is required.
-Adding new API
---------------
+Adding new API and features
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
Every new function, parameter and attribute that is not explicitly marked as
private (i.e., starts with an underscore) becomes part of Matplotlib's public
@@ -485,6 +615,51 @@ take particular care when adding new API:
__ https://emptysqua.re/blog/api-evolution-the-right-way/#adding-parameters
+.. _versioning-directives:
+
+Versioning directives
+"""""""""""""""""""""
+
+When making a backward incompatible change, please add a versioning directive in
+the docstring. The directives should be placed at the end of a description block.
+For example::
+
+ class Foo:
+ """
+ This is the summary.
+
+ Followed by a longer description block.
+
+ Consisting of multiple lines and paragraphs.
+
+ .. versionadded:: 3.5
+
+ Parameters
+ ----------
+ a : int
+ The first parameter.
+ b: bool, default: False
+ This was added later.
+
+ .. versionadded:: 3.6
+ """
+
+ def set_b(b):
+ """
+ Set b.
+
+ .. versionadded:: 3.6
+
+ Parameters
+ ----------
+ b: bool
+
+For classes and functions, the directive should be placed before the
+*Parameters* section. For parameters, the directive should be placed at the
+end of the parameter description. The patch release version is omitted and
+the directive should not be added to entire modules.
+
+
New modules and files: installation
-----------------------------------
diff --git a/doc/devel/development_setup.rst b/doc/devel/development_setup.rst
index 9da1c5737a36..e18d85cebde0 100644
--- a/doc/devel/development_setup.rst
+++ b/doc/devel/development_setup.rst
@@ -195,6 +195,8 @@ so that when you make code or document related changes you are aware of the exis
* Run test cases to verify installation :ref:`testing`
* Verify documentation build :ref:`documenting-matplotlib`
+.. _pre-commit-hooks:
+
Install pre-commit hooks
========================
`pre-commit `_ hooks save time in the review process by
diff --git a/doc/devel/development_workflow.rst b/doc/devel/development_workflow.rst
index 50170ee4ade3..3f4fe956e37e 100644
--- a/doc/devel/development_workflow.rst
+++ b/doc/devel/development_workflow.rst
@@ -151,6 +151,23 @@ If you don't think your request is ready to be merged, just say so in your pull
request message and use the "Draft PR" feature of GitHub. This is a good way of
getting some preliminary code review.
+.. _update-pull-request:
+
+Update a pull request
+=====================
+
+When updating your pull request after making revisions, instead of adding new
+commits, please consider amending your initial commit(s) to keep the commit
+history clean.
+
+You can achieve this by using
+
+ .. code-block:: bash
+
+ git commit -a --amend --no-edit
+ git push [your-remote-repo] [your-branch] --force-with-lease
+
+
Manage commit history
=====================
diff --git a/doc/users/next_whats_new/README.rst b/doc/users/next_whats_new/README.rst
index e1b27ef97f1e..98b601ee32d8 100644
--- a/doc/users/next_whats_new/README.rst
+++ b/doc/users/next_whats_new/README.rst
@@ -11,9 +11,7 @@ something like :file:`cool_new_feature.rst` if you have added a brand new
feature or something like :file:`updated_feature.rst` for extensions of
existing features.
-Please avoid using references in section titles, as it causes links to be
-confusing in the table of contents. Instead, ensure that a reference is
-included in the descriptive text. Include contents of the form: ::
+Include contents of the form::
Section title for feature
-------------------------
@@ -23,3 +21,11 @@ included in the descriptive text. Include contents of the form: ::
A sub-section
~~~~~~~~~~~~~
+
+Please avoid using references in section titles, as it causes links to be
+confusing in the table of contents. Instead, ensure that a reference is
+included in the descriptive text.
+
+.. NOTE
+ Lines 5-24 of this file are include in :ref:`api_whats_new`;
+ therefore, please check the doc build after changing this file.
From ef107caf3951f164571e28237413aabe68a73c79 Mon Sep 17 00:00:00 2001
From: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com>
Date: Fri, 3 Nov 2023 08:21:41 +0100
Subject: [PATCH 05/87] Backport PR #27213: DOC: consolidated coding guide and
added naming conventions table
---
doc/api/next_api_changes/README.rst | 12 +-
doc/devel/coding_guide.rst | 214 ++++++-------------------
doc/devel/contribute.rst | 237 ++++++++++++++++++++++++----
doc/devel/development_setup.rst | 2 +
doc/devel/development_workflow.rst | 17 ++
doc/users/next_whats_new/README.rst | 12 +-
6 files changed, 292 insertions(+), 202 deletions(-)
diff --git a/doc/api/next_api_changes/README.rst b/doc/api/next_api_changes/README.rst
index de494911e6b2..75e70b456eb9 100644
--- a/doc/api/next_api_changes/README.rst
+++ b/doc/api/next_api_changes/README.rst
@@ -22,11 +22,17 @@ author's initials. Typically, each change will get its own file, but you may
also amend existing files when suitable. The overall goal is a comprehensible
documentation of the changes.
-Please avoid using references in section titles, as it causes links to be
-confusing in the table of contents. Instead, ensure that a reference is
-included in the descriptive text. A typical entry could look like this::
+A typical entry could look like this::
Locators
~~~~~~~~
The unused `Locator.autoscale()` method is deprecated (pass the axis
limits to `Locator.view_limits()` instead).
+
+Please avoid using references in section titles, as it causes links to be
+confusing in the table of contents. Instead, ensure that a reference is
+included in the descriptive text.
+
+.. NOTE
+ Lines 5-30 of this file are include in :ref:`api_whats_new`;
+ therefore, please check the doc build after changing this file.
diff --git a/doc/devel/coding_guide.rst b/doc/devel/coding_guide.rst
index 0385d6d388f0..22873020f103 100644
--- a/doc/devel/coding_guide.rst
+++ b/doc/devel/coding_guide.rst
@@ -8,144 +8,82 @@ Pull request guidelines
`__
are the mechanism for contributing to Matplotlib's code and documentation.
-It is recommended to check that your contribution complies with the following
-rules before submitting a pull request:
+We value contributions from people with all levels of experience. In particular,
+if this is your first PR not everything has to be perfect. We'll guide you
+through the PR process. Nevertheless, please try to follow our guidelines as well
+as you can to help make the PR process quick and smooth. If your pull request is
+incomplete or a work-in-progress, please mark it as a `draft pull requests `_
+on GitHub and specify what feedback from the developers would be helpful.
-* If your pull request addresses an issue, please use the title to describe the
- issue (e.g. "Add ability to plot timedeltas") and mention the issue number
- in the pull request description to ensure that a link is created to the
- original issue (e.g. "Closes #8869" or "Fixes #8869"). This will ensure the
- original issue mentioned is automatically closed when your PR is merged. See
- `the GitHub documentation
- `__
- for more details.
-
-* Formatting should follow the recommendations of PEP8_, as enforced by
- flake8_. Matplotlib modifies PEP8 to extend the maximum line length to 88
- characters. You can check flake8 compliance from the command line with ::
-
- python -m pip install flake8
- flake8 /path/to/module.py
-
- or your editor may provide integration with it. Note that Matplotlib
- intentionally does not use the black_ auto-formatter (1__), in particular due
- to its inability to understand the semantics of mathematical expressions
- (2__, 3__).
-
- .. _PEP8: https://www.python.org/dev/peps/pep-0008/
- .. _flake8: https://flake8.pycqa.org/
- .. _black: https://black.readthedocs.io/
- .. __: https://github.com/matplotlib/matplotlib/issues/18796
- .. __: https://github.com/psf/black/issues/148
- .. __: https://github.com/psf/black/issues/1984
-
-* All public methods should have informative docstrings with sample usage when
- appropriate. Use the :ref:`docstring standards `.
-
-* For high-level plotting functions, consider adding a simple example either in
- the ``Example`` section of the docstring or the
- :ref:`examples gallery `.
-
-* Changes (both new features and bugfixes) should have good test coverage. See
- :ref:`testing` for more details.
-
-* Import the following modules using the standard scipy conventions::
+Please be patient with reviewers. We try our best to respond quickly, but we have
+limited bandwidth. If there is no feedback within a couple of days, please ping
+us by posting a comment to your PR or reaching out on a :ref:`communication channel `
- import numpy as np
- import numpy.ma as ma
- import matplotlib as mpl
- import matplotlib.pyplot as plt
- import matplotlib.cbook as cbook
- import matplotlib.patches as mpatches
- In general, Matplotlib modules should **not** import `.rcParams` using ``from
- matplotlib import rcParams``, but rather access it as ``mpl.rcParams``. This
- is because some modules are imported very early, before the `.rcParams`
- singleton is constructed.
-
-* If your change is a major new feature, add an entry to the ``What's new``
- section by adding a new file in ``doc/users/next_whats_new`` (see
- :file:`doc/users/next_whats_new/README.rst` for more information).
+Summary for pull request authors
+================================
-* If you change the API in a backward-incompatible way, please document it in
- :file:`doc/api/next_api_changes/behavior`, by adding a new file with the
- naming convention ``99999-ABC.rst`` where the pull request number is followed
- by the contributor's initials. (see :file:`doc/api/api_changes.rst` for more
- information)
+We recommend that you check that your contribution complies with the following
+guidelines before submitting a pull request:
-* If you add new public API or change public API, update or add the
- corresponding type hints. Most often this is found in the corresponding
- ``.pyi`` file for the ``.py`` file which was edited. Changes in ``pyplot.py``
- are type hinted inline.
+.. rst-class:: checklist
-* See below for additional points about :ref:`keyword-argument-processing`, if
- applicable for your pull request.
+* Changes, both new features and bugfixes, should have good test coverage. See
+ :ref:`testing` for more details.
-.. note::
+* Update the :ref:`documentation ` if necessary.
- The current state of the Matplotlib code base is not compliant with all
- of these guidelines, but we expect that enforcing these constraints on all
- new contributions will move the overall code base quality in the right
- direction.
+* All public methods should have informative docstrings with sample usage when
+ appropriate. Use the :ref:`docstring standards `.
+* For high-level plotting functions, consider adding a small example to the
+ :ref:`examples gallery `.
-.. seealso::
+* If you add a major new feature or change the API in a backward-incompatible
+ way, please document it as described in :ref:`new-changed-api`
- * :ref:`coding_guidelines`
- * :ref:`testing`
- * :ref:`documenting-matplotlib`
+* Code should follow our conventions as documented in our :ref:`coding_guidelines`
+* When adding or changing public function signatures, add :ref:`type hints `
+* When adding keyword arguments, see our guide to :ref:`keyword-argument-processing`.
-Summary for pull request authors
-================================
+When opening a pull request on Github, please ensure that:
-.. note::
+.. rst-class:: checklist
- * We value contributions from people with all levels of experience. In
- particular if this is your first PR not everything has to be perfect.
- We'll guide you through the PR process.
- * Nevertheless, please try to follow the guidelines below as well as you can to
- help make the PR process quick and smooth.
- * Be patient with reviewers. We try our best to respond quickly, but we
- have limited bandwidth. If there is no feedback within a couple of days,
- please ping us by posting a comment to your PR.
+* Changes were made on a :ref:`feature branch `.
-When making a PR, pay attention to:
+* :ref:`pre-commit ` checks for spelling, formatting, etc pass
-.. rst-class:: checklist
+* The pull request targets the :ref:`main branch `
-* :ref:`Target the main branch `.
-* Adhere to the :ref:`coding_guidelines`.
-* Update the :ref:`documentation ` if necessary.
-* Aim at making the PR as "ready-to-go" as you can. This helps to speed up
- the review process.
-* It is ok to open incomplete or work-in-progress PRs if you need help or
- feedback from the developers. You may mark these as
- `draft pull requests `_
- on GitHub.
-* When updating your PR, instead of adding new commits to fix something, please
- consider amending your initial commit(s) to keep the history clean.
- You can achieve this by using
+* If your pull request addresses an issue, please use the title to describe the
+ issue (e.g. "Add ability to plot timedeltas") and mention the issue number
+ in the pull request description to ensure that a link is created to the
+ original issue (e.g. "Closes #8869" or "Fixes #8869"). This will ensure the
+ original issue mentioned is automatically closed when your PR is merged. For more
+ details, see `linking an issue and pull request `__.
- .. code-block:: bash
+* :ref:`pr-automated-tests` pass
- git commit --amend --no-edit
- git push [your-remote-repo] [your-branch] --force-with-lease
+For guidance on creating and managing a pull request, please see our
+:ref:`contributing ` and :ref:`pull request workflow `
+guides.
-See also :ref:`contributing` for how to make a PR.
Summary for pull request reviewers
==================================
.. redirect-from:: /devel/maintainer_workflow
-.. note::
+**Please help review and merge PRs!**
+
+If you have commit rights, then you are trusted to use them. Please be patient
+and `kind `__ with contributors.
- * If you have commit rights, then you are trusted to use them.
- **Please help review and merge PRs!**
- * Be patient and `kind `__ with
- contributors.
+When reviewing, please ensure that the pull request satisfies the following
+requirements before merging it:
Content topics:
@@ -196,61 +134,6 @@ Documentation
* See :ref:`documenting-matplotlib` for our documentation style guide.
-.. _release_notes:
-
-New features and API changes
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-When adding a major new feature or changing the API in a backward incompatible
-way, please document it by including a versioning directive in the docstring
-and adding an entry to the folder for either the what's new or API change notes.
-
-+-------------------+-----------------------------+----------------------------------+
-| for this addition | include this directive | create entry in this folder |
-+===================+=============================+==================================+
-| new feature | ``.. versionadded:: 3.N`` | :file:`doc/users/next_whats_new/`|
-+-------------------+-----------------------------+----------------------------------+
-| API change | ``.. versionchanged:: 3.N`` | :file:`doc/api/next_api_changes/`|
-| | | |
-| | | probably in ``behavior/`` |
-+-------------------+-----------------------------+----------------------------------+
-
-The directives should be placed at the end of a description block. For example::
-
- class Foo:
- """
- This is the summary.
-
- Followed by a longer description block.
-
- Consisting of multiple lines and paragraphs.
-
- .. versionadded:: 3.5
-
- Parameters
- ----------
- a : int
- The first parameter.
- b: bool, default: False
- This was added later.
-
- .. versionadded:: 3.6
- """
-
- def set_b(b):
- """
- Set b.
-
- .. versionadded:: 3.6
-
- Parameters
- ----------
- b: bool
-
-For classes and functions, the directive should be placed before the
-*Parameters* section. For parameters, the directive should be placed at the
-end of the parameter description. The patch release version is omitted and
-the directive should not be added to entire modules.
-
.. _pr-labels:
Labels
@@ -330,7 +213,8 @@ Merging
Automated tests
---------------
-Before being merged, a PR should pass the :ref:`automated-tests`. If you are unsure why a test is failing, ask on the PR or in our `chat space `_
+Before being merged, a PR should pass the :ref:`automated-tests`. If you are
+unsure why a test is failing, ask on the PR or in our :ref:`communication-channels`
.. _pr-squashing:
diff --git a/doc/devel/contribute.rst b/doc/devel/contribute.rst
index a9bfb0f816dd..ee78beca0781 100644
--- a/doc/devel/contribute.rst
+++ b/doc/devel/contribute.rst
@@ -367,27 +367,160 @@ project that leads to a scientific publication, please follow the
Coding guidelines
=================
-API changes
------------
+While the current state of the Matplotlib code base is not compliant with all
+of these guidelines, our goal in enforcing these constraints on new
+contributions is that it improves the readability and consistency of the code base
+going forward.
-API consistency and stability are of great value. Therefore, API changes
-(e.g. signature changes, behavior changes, removals) will only be conducted
-if the added benefit is worth the user effort for adapting.
+PEP8, as enforced by flake8
+---------------------------
+
+Formatting should follow the recommendations of PEP8_, as enforced by flake8_.
+Matplotlib modifies PEP8 to extend the maximum line length to 88
+characters. You can check flake8 compliance from the command line with ::
+
+ python -m pip install flake8
+ flake8 /path/to/module.py
+
+or your editor may provide integration with it. Note that Matplotlib intentionally
+does not use the black_ auto-formatter (1__), in particular due to its inability
+to understand the semantics of mathematical expressions (2__, 3__).
+
+.. _PEP8: https://www.python.org/dev/peps/pep-0008/
+.. _flake8: https://flake8.pycqa.org/
+.. _black: https://black.readthedocs.io/
+.. __: https://github.com/matplotlib/matplotlib/issues/18796
+.. __: https://github.com/psf/black/issues/148
+.. __: https://github.com/psf/black/issues/1984
+
+
+Package imports
+---------------
+Import the following modules using the standard scipy conventions::
+
+ import numpy as np
+ import numpy.ma as ma
+ import matplotlib as mpl
+ import matplotlib.pyplot as plt
+ import matplotlib.cbook as cbook
+ import matplotlib.patches as mpatches
+
+In general, Matplotlib modules should **not** import `.rcParams` using ``from
+matplotlib import rcParams``, but rather access it as ``mpl.rcParams``. This
+is because some modules are imported very early, before the `.rcParams`
+singleton is constructed.
+
+Variable names
+--------------
+
+When feasible, please use our internal variable naming convention for objects
+of a given class and objects of any child class:
+
++------------------------------------+---------------+------------------------------------------+
+| base class | variable | multiples |
++====================================+===============+==========================================+
+| `~matplotlib.figure.FigureBase` | ``fig`` | |
++------------------------------------+---------------+------------------------------------------+
+| `~matplotlib.axes.Axes` | ``ax`` | |
++------------------------------------+---------------+------------------------------------------+
+| `~matplotlib.transforms.Transform` | ``trans`` | ``trans__`` |
++ + + +
+| | | ``trans_`` when target is screen |
++------------------------------------+---------------+------------------------------------------+
+
+Generally, denote more than one instance of the same class by adding suffixes to
+the variable names. If a format isn't specified in the table, use numbers or
+letters as appropriate.
+
+
+.. _type-hints:
+
+Type hints
+----------
+
+If you add new public API or change public API, update or add the
+corresponding `mypy `_ type hints.
+We generally use `stub files
+`_
+(``*.pyi``) to store the type information; for example ``colors.pyi`` contains
+the type information for ``colors.py``. A notable exception is ``pyplot.py``,
+which is type hinted inline.
+
+Type hints are checked by the mypy :ref:`pre-commit hook `
+and can often be verified using ``tools\stubtest.py`` and occasionally may
+require the use of ``tools\check_typehints.py``.
+
+
+.. _new-changed-api:
-Because we are a visualization library our primary output is the final
-visualization the user sees. Thus it is our :ref:`long standing
-` policy that the appearance of the figure is part of the API
-and any changes, either semantic or esthetic, will be treated as a
-backwards-incompatible API change.
+API changes and new features
+----------------------------
+API consistency and stability are of great value; Therefore, API changes
+(e.g. signature changes, behavior changes, removals) will only be conducted
+if the added benefit is worth the effort of adapting existing code.
+
+Because we are a visualization library, our primary output is the final
+visualization the user sees; therefore, the appearance of the figure is part of
+the API and any changes, either semantic or :ref:`esthetic `,
+are backwards-incompatible API changes.
+
+.. _api_whats_new:
+
+Announce changes, deprecations, and new features
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+When adding or changing the API in a backward in-compatible way, please add the
+appropriate :ref:`versioning directive ` and document it
+for the release notes and add the entry to the appropriate folder:
+
++-------------------+-----------------------------+----------------------------------------------+
+| addition | versioning directive | announcement folder |
++===================+=============================+==============================================+
+| new feature | ``.. versionadded:: 3.N`` | :file:`doc/users/next_whats_new/` |
++-------------------+-----------------------------+----------------------------------------------+
+| API change | ``.. versionchanged:: 3.N`` | :file:`doc/api/next_api_changes/[kind]` |
++-------------------+-----------------------------+----------------------------------------------+
+
+API deprecations are first introduced and then expired. During the introduction
+period, users are warned that the API *will* change in the future.
+During the expiration period, code is changed as described in the notice posted
+during the introductory period.
+
++-----------+--------------------------------------------------+----------------------------------------------+
+| stage | required changes | announcement folder |
++===========+==================================================+==============================================+
+| introduce | :ref:`introduce deprecation ` | :file:`doc/api/next_api_changes/deprecation` |
++-----------+--------------------------------------------------+----------------------------------------------+
+| expire | :ref:`expire deprecation ` | :file:`doc/api/next_api_changes/[kind]` |
++-----------+--------------------------------------------------+----------------------------------------------+
+
+For both change notes and what's new, please avoid using references in section
+titles, as it causes links to be confusing in the table of contents. Instead,
+ensure that a reference is included in the descriptive text.
+
+API Change Notes
+""""""""""""""""
+.. include:: ../api/next_api_changes/README.rst
+ :start-line: 5
+ :end-line: 31
+
+What's new
+""""""""""
+.. include:: ../users/next_whats_new/README.rst
+ :start-line: 5
+ :end-line: 24
+
+
+Deprecation
+^^^^^^^^^^^
API changes in Matplotlib have to be performed following the deprecation process
-below, except in very rare circumstances as deemed necessary by the development team.
-This ensures that users are notified before the change will take effect and thus
-prevents unexpected breaking of code.
+below, except in very rare circumstances as deemed necessary by the development
+team. This ensures that users are notified before the change will take effect
+and thus prevents unexpected breaking of code.
Rules
-^^^^^
-
+"""""
- Deprecations are targeted at the next point.release (e.g. 3.x)
- Deprecated API is generally removed two point-releases after introduction
of the deprecation. Longer deprecations can be imposed by core developers on
@@ -398,12 +531,12 @@ Rules
- If in doubt, decisions about API changes are finally made by the
API consistency lead developer
-Introducing
-^^^^^^^^^^^
+.. _intro-deprecation:
+
+Introduce deprecation
+"""""""""""""""""""""
-#. Announce the deprecation in a new file
- :file:`doc/api/next_api_changes/deprecations/99999-ABC.rst` where ``99999``
- is the pull request number and ``ABC`` are the contributor's initials.
+#. Create :ref:`deprecation notice `
#. If possible, issue a `~matplotlib.MatplotlibDeprecationWarning` when the
deprecated API is used. There are a number of helper tools for this:
@@ -439,16 +572,13 @@ Introducing
:file:`ci/mypy-stubtest-allowlist.txt` under a heading indicating the deprecation
version number.
-Expiring
-^^^^^^^^
+.. _expire-deprecation:
+
+Expire deprecation
+""""""""""""""""""
-#. Announce the API changes in a new file
- :file:`doc/api/next_api_changes/[kind]/99999-ABC.rst` where ``99999``
- is the pull request number and ``ABC`` are the contributor's initials, and
- ``[kind]`` is one of the folders :file:`behavior`, :file:`development`,
- :file:`removals`. See :file:`doc/api/next_api_changes/README.rst` for more
- information. For the content, you can usually copy the deprecation notice
- and adapt it slightly.
+#. Create :ref:`deprecation announcement `. For the content,
+ you can usually copy the deprecation notice and adapt it slightly.
#. Change the code functionality and remove any related deprecation warnings.
@@ -466,8 +596,8 @@ Expiring
require that mechanism for deprecation. For removed items that were not in the stub
file, only deleting from the allowlist is required.
-Adding new API
---------------
+Adding new API and features
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
Every new function, parameter and attribute that is not explicitly marked as
private (i.e., starts with an underscore) becomes part of Matplotlib's public
@@ -485,6 +615,51 @@ take particular care when adding new API:
__ https://emptysqua.re/blog/api-evolution-the-right-way/#adding-parameters
+.. _versioning-directives:
+
+Versioning directives
+"""""""""""""""""""""
+
+When making a backward incompatible change, please add a versioning directive in
+the docstring. The directives should be placed at the end of a description block.
+For example::
+
+ class Foo:
+ """
+ This is the summary.
+
+ Followed by a longer description block.
+
+ Consisting of multiple lines and paragraphs.
+
+ .. versionadded:: 3.5
+
+ Parameters
+ ----------
+ a : int
+ The first parameter.
+ b: bool, default: False
+ This was added later.
+
+ .. versionadded:: 3.6
+ """
+
+ def set_b(b):
+ """
+ Set b.
+
+ .. versionadded:: 3.6
+
+ Parameters
+ ----------
+ b: bool
+
+For classes and functions, the directive should be placed before the
+*Parameters* section. For parameters, the directive should be placed at the
+end of the parameter description. The patch release version is omitted and
+the directive should not be added to entire modules.
+
+
New modules and files: installation
-----------------------------------
diff --git a/doc/devel/development_setup.rst b/doc/devel/development_setup.rst
index 9da1c5737a36..e18d85cebde0 100644
--- a/doc/devel/development_setup.rst
+++ b/doc/devel/development_setup.rst
@@ -195,6 +195,8 @@ so that when you make code or document related changes you are aware of the exis
* Run test cases to verify installation :ref:`testing`
* Verify documentation build :ref:`documenting-matplotlib`
+.. _pre-commit-hooks:
+
Install pre-commit hooks
========================
`pre-commit `_ hooks save time in the review process by
diff --git a/doc/devel/development_workflow.rst b/doc/devel/development_workflow.rst
index 50170ee4ade3..3f4fe956e37e 100644
--- a/doc/devel/development_workflow.rst
+++ b/doc/devel/development_workflow.rst
@@ -151,6 +151,23 @@ If you don't think your request is ready to be merged, just say so in your pull
request message and use the "Draft PR" feature of GitHub. This is a good way of
getting some preliminary code review.
+.. _update-pull-request:
+
+Update a pull request
+=====================
+
+When updating your pull request after making revisions, instead of adding new
+commits, please consider amending your initial commit(s) to keep the commit
+history clean.
+
+You can achieve this by using
+
+ .. code-block:: bash
+
+ git commit -a --amend --no-edit
+ git push [your-remote-repo] [your-branch] --force-with-lease
+
+
Manage commit history
=====================
diff --git a/doc/users/next_whats_new/README.rst b/doc/users/next_whats_new/README.rst
index e1b27ef97f1e..98b601ee32d8 100644
--- a/doc/users/next_whats_new/README.rst
+++ b/doc/users/next_whats_new/README.rst
@@ -11,9 +11,7 @@ something like :file:`cool_new_feature.rst` if you have added a brand new
feature or something like :file:`updated_feature.rst` for extensions of
existing features.
-Please avoid using references in section titles, as it causes links to be
-confusing in the table of contents. Instead, ensure that a reference is
-included in the descriptive text. Include contents of the form: ::
+Include contents of the form::
Section title for feature
-------------------------
@@ -23,3 +21,11 @@ included in the descriptive text. Include contents of the form: ::
A sub-section
~~~~~~~~~~~~~
+
+Please avoid using references in section titles, as it causes links to be
+confusing in the table of contents. Instead, ensure that a reference is
+included in the descriptive text.
+
+.. NOTE
+ Lines 5-24 of this file are include in :ref:`api_whats_new`;
+ therefore, please check the doc build after changing this file.
From 917df66a80e44dd5f1588028eae00d5313dcfb86 Mon Sep 17 00:00:00 2001
From: Antony Lee
Date: Sun, 5 Nov 2023 22:26:26 +0100
Subject: [PATCH 06/87] Backport PR #27268: Copy-edit various examples.
---
galleries/examples/color/README.txt | 3 +--
galleries/examples/color/named_colors.py | 2 +-
.../images_contours_and_fields/image_demo.py | 8 +++-----
.../images_contours_and_fields/pcolor_demo.py | 12 +++++-------
.../text_labels_and_annotations/accented_text.py | 6 +++---
.../annotation_demo.py | 2 +-
.../text_labels_and_annotations/font_file.py | 6 +++---
.../text_labels_and_annotations/legend_demo.py | 2 --
.../axes/constrainedlayout_guide.py | 8 +++-----
galleries/users_explain/axes/legend_guide.py | 11 ++++-------
.../users_explain/axes/tight_layout_guide.py | 16 ++++++----------
.../colors/colormap-manipulation.py | 15 ++++++---------
galleries/users_explain/colors/colormaps.py | 6 +++---
galleries/users_explain/text/text_intro.py | 6 +++---
14 files changed, 42 insertions(+), 61 deletions(-)
diff --git a/galleries/examples/color/README.txt b/galleries/examples/color/README.txt
index 4bcdb526f4d4..4b8b3bc4b751 100644
--- a/galleries/examples/color/README.txt
+++ b/galleries/examples/color/README.txt
@@ -3,6 +3,5 @@
Color
=====
-For more in-depth information about the colormaps available in matplotlib
-as well as a description of their properties,
+For a description of the colormaps available in Matplotlib,
see the :ref:`colormaps tutorial `.
diff --git a/galleries/examples/color/named_colors.py b/galleries/examples/color/named_colors.py
index 9ae4ec4957f3..d9a7259da773 100644
--- a/galleries/examples/color/named_colors.py
+++ b/galleries/examples/color/named_colors.py
@@ -3,7 +3,7 @@
List of named colors
====================
-This plots a list of the named colors supported in matplotlib.
+This plots a list of the named colors supported by Matplotlib.
For more information on colors in matplotlib see
* the :ref:`colors_def` tutorial;
diff --git a/galleries/examples/images_contours_and_fields/image_demo.py b/galleries/examples/images_contours_and_fields/image_demo.py
index 884e68172698..213b6cdd28c2 100644
--- a/galleries/examples/images_contours_and_fields/image_demo.py
+++ b/galleries/examples/images_contours_and_fields/image_demo.py
@@ -1,9 +1,7 @@
"""
-==========
-Image demo
-==========
-
-Many ways to plot images in Matplotlib.
+========================
+Many ways to plot images
+========================
The most common way to plot images in Matplotlib is with
`~.axes.Axes.imshow`. The following examples demonstrate much of the
diff --git a/galleries/examples/images_contours_and_fields/pcolor_demo.py b/galleries/examples/images_contours_and_fields/pcolor_demo.py
index a783c83409df..7a8ef35caf96 100644
--- a/galleries/examples/images_contours_and_fields/pcolor_demo.py
+++ b/galleries/examples/images_contours_and_fields/pcolor_demo.py
@@ -1,13 +1,11 @@
"""
-===========
-Pcolor demo
-===========
+=============
+pcolor images
+=============
-Generating images with `~.axes.Axes.pcolor`.
-
-Pcolor allows you to generate 2D image-style plots. Below we will show how
-to do so in Matplotlib.
+`~.Axes.pcolor` generates 2D image-style plots, as illustrated below.
"""
+
import matplotlib.pyplot as plt
import numpy as np
diff --git a/galleries/examples/text_labels_and_annotations/accented_text.py b/galleries/examples/text_labels_and_annotations/accented_text.py
index f57b19532a43..7ff080afefd9 100644
--- a/galleries/examples/text_labels_and_annotations/accented_text.py
+++ b/galleries/examples/text_labels_and_annotations/accented_text.py
@@ -1,7 +1,7 @@
r"""
-=================================
-Using accented text in Matplotlib
-=================================
+=============
+Accented text
+=============
Matplotlib supports accented characters via TeX mathtext or Unicode.
diff --git a/galleries/examples/text_labels_and_annotations/annotation_demo.py b/galleries/examples/text_labels_and_annotations/annotation_demo.py
index 8b310a7a1865..26f3b80bf203 100644
--- a/galleries/examples/text_labels_and_annotations/annotation_demo.py
+++ b/galleries/examples/text_labels_and_annotations/annotation_demo.py
@@ -3,7 +3,7 @@
Annotating Plots
================
-The following examples show how it is possible to annotate plots in Matplotlib.
+The following examples show ways to annotate plots in Matplotlib.
This includes highlighting specific points of interest and using various
visual tools to call attention to this point. For a more complete and in-depth
description of the annotation and text tools in Matplotlib, see the
diff --git a/galleries/examples/text_labels_and_annotations/font_file.py b/galleries/examples/text_labels_and_annotations/font_file.py
index 8242b57839aa..b4a58808d716 100644
--- a/galleries/examples/text_labels_and_annotations/font_file.py
+++ b/galleries/examples/text_labels_and_annotations/font_file.py
@@ -1,7 +1,7 @@
r"""
-===================================
-Using a ttf font file in Matplotlib
-===================================
+====================
+Using ttf font files
+====================
Although it is usually not a good idea to explicitly point to a single ttf file
for a font instance, you can do so by passing a `pathlib.Path` instance as the
diff --git a/galleries/examples/text_labels_and_annotations/legend_demo.py b/galleries/examples/text_labels_and_annotations/legend_demo.py
index a425d39b7d8f..2f550729837e 100644
--- a/galleries/examples/text_labels_and_annotations/legend_demo.py
+++ b/galleries/examples/text_labels_and_annotations/legend_demo.py
@@ -3,8 +3,6 @@
Legend Demo
===========
-Plotting legends in Matplotlib.
-
There are many ways to create and customize legends in Matplotlib. Below
we'll show a few examples for how to do so.
diff --git a/galleries/users_explain/axes/constrainedlayout_guide.py b/galleries/users_explain/axes/constrainedlayout_guide.py
index 260a4f76bf71..4581f5f67808 100644
--- a/galleries/users_explain/axes/constrainedlayout_guide.py
+++ b/galleries/users_explain/axes/constrainedlayout_guide.py
@@ -40,15 +40,13 @@
.. warning::
- Calling ``plt.tight_layout()`` will turn off *constrained layout*!
+ Calling `~.pyplot.tight_layout` will turn off *constrained layout*!
Simple example
==============
-In Matplotlib, the location of Axes (including subplots) are specified in
-normalized figure coordinates. It can happen that your axis labels or titles
-(or sometimes even ticklabels) go outside the figure area, and are thus
-clipped.
+With the default Axes positioning, the axes title, axis labels, or tick labels
+can sometimes go outside the figure area, and thus get clipped.
"""
# sphinx_gallery_thumbnail_number = 18
diff --git a/galleries/users_explain/axes/legend_guide.py b/galleries/users_explain/axes/legend_guide.py
index 9900b0aa4bdd..3b138fe8ada3 100644
--- a/galleries/users_explain/axes/legend_guide.py
+++ b/galleries/users_explain/axes/legend_guide.py
@@ -7,13 +7,10 @@
Legend guide
============
-Generating legends flexibly in Matplotlib.
-
.. currentmodule:: matplotlib.pyplot
-This legend guide is an extension of the documentation available at
-:func:`~matplotlib.pyplot.legend` - please ensure you are familiar with
-contents of that documentation before proceeding with this guide.
+This legend guide extends the `~.Axes.legend` docstring -
+please read it before proceeding with this guide.
This guide makes use of some common terms, which are documented here for
clarity:
@@ -62,8 +59,8 @@
line_down, = ax.plot([3, 2, 1], label='Line 1')
ax.legend(handles=[line_up, line_down])
-In some cases, it is not possible to set the label of the handle, so it is
-possible to pass through the list of labels to :func:`legend`::
+In the rare case where the labels cannot directly be set on the handles, they
+can also be directly passed to :func:`legend`::
fig, ax = plt.subplots()
line_up, = ax.plot([1, 2, 3], label='Line 2')
diff --git a/galleries/users_explain/axes/tight_layout_guide.py b/galleries/users_explain/axes/tight_layout_guide.py
index 42c227b2e360..8525b9773f91 100644
--- a/galleries/users_explain/axes/tight_layout_guide.py
+++ b/galleries/users_explain/axes/tight_layout_guide.py
@@ -17,15 +17,11 @@
An alternative to *tight_layout* is :ref:`constrained_layout
`.
-
-Simple Example
+Simple example
==============
-In matplotlib, the location of axes (including subplots) are specified in
-normalized figure coordinates. It can happen that your axis labels or
-titles (or sometimes even ticklabels) go outside the figure area, and are thus
-clipped.
-
+With the default Axes positioning, the axes title, axis labels, or tick labels
+can sometimes go outside the figure area, and thus get clipped.
"""
# sphinx_gallery_thumbnail_number = 7
@@ -190,8 +186,8 @@ def example_plot(ax, fontsize=12):
# %%
# You may provide an optional *rect* parameter, which specifies the bounding
-# box that the subplots will be fit inside. The coordinates must be in
-# normalized figure coordinates and the default is (0, 0, 1, 1).
+# box that the subplots will be fit inside. The coordinates are in
+# normalized figure coordinates and default to (0, 0, 1, 1) (the whole figure).
fig = plt.figure()
@@ -245,7 +241,7 @@ def example_plot(ax, fontsize=12):
# Use with AxesGrid1
# ==================
#
-# While limited, :mod:`mpl_toolkits.axes_grid1` is also supported.
+# Limited support for :mod:`mpl_toolkits.axes_grid1` is provided.
from mpl_toolkits.axes_grid1 import Grid
diff --git a/galleries/users_explain/colors/colormap-manipulation.py b/galleries/users_explain/colors/colormap-manipulation.py
index 88e4c5befaf0..87269b87befa 100644
--- a/galleries/users_explain/colors/colormap-manipulation.py
+++ b/galleries/users_explain/colors/colormap-manipulation.py
@@ -3,9 +3,9 @@
.. _colormap-manipulation:
-********************************
-Creating Colormaps in Matplotlib
-********************************
+******************
+Creating Colormaps
+******************
Matplotlib has a number of built-in colormaps accessible via
`.matplotlib.colormaps`. There are also external libraries like
@@ -13,17 +13,15 @@
.. _palettable: https://jiffyclub.github.io/palettable/
-However, we often want to create or manipulate colormaps in Matplotlib.
+However, we may also want to create or manipulate our own colormaps.
This can be done using the class `.ListedColormap` or
`.LinearSegmentedColormap`.
-Seen from the outside, both colormap classes map values between 0 and 1 to
-a bunch of colors. There are, however, slight differences, some of which are
-shown in the following.
+Both colormap classes map values between 0 and 1 to colors. There are however
+differences, as explained below.
Before manually creating or manipulating colormaps, let us first see how we
can obtain colormaps and their colors from existing colormap classes.
-
Getting colormaps and accessing their values
============================================
@@ -32,7 +30,6 @@
which returns a colormap object. The length of the list of colors used
internally to define the colormap can be adjusted via `.Colormap.resampled`.
Below we use a modest value of 8 so there are not a lot of values to look at.
-
"""
import matplotlib.pyplot as plt
diff --git a/galleries/users_explain/colors/colormaps.py b/galleries/users_explain/colors/colormaps.py
index 92b56d298976..b5db551cb5b5 100644
--- a/galleries/users_explain/colors/colormaps.py
+++ b/galleries/users_explain/colors/colormaps.py
@@ -3,9 +3,9 @@
.. _colormaps:
-********************************
-Choosing Colormaps in Matplotlib
-********************************
+******************
+Choosing Colormaps
+******************
Matplotlib has a number of built-in colormaps accessible via
`.matplotlib.colormaps`. There are also external libraries that
diff --git a/galleries/users_explain/text/text_intro.py b/galleries/users_explain/text/text_intro.py
index 54fcb00c7a86..948545667fa9 100644
--- a/galleries/users_explain/text/text_intro.py
+++ b/galleries/users_explain/text/text_intro.py
@@ -4,9 +4,9 @@
.. _text_intro:
-========================
-Text in Matplotlib Plots
-========================
+==================
+Text in Matplotlib
+==================
Introduction to plotting and working with text in Matplotlib.
From f32d0f18bf20075129f55f339e427fadd1470ed5 Mon Sep 17 00:00:00 2001
From: Antony Lee
Date: Sun, 5 Nov 2023 22:26:26 +0100
Subject: [PATCH 07/87] Backport PR #27268: Copy-edit various examples.
---
galleries/examples/color/README.txt | 3 +--
galleries/examples/color/named_colors.py | 2 +-
.../images_contours_and_fields/image_demo.py | 8 +++-----
.../images_contours_and_fields/pcolor_demo.py | 12 +++++-------
.../text_labels_and_annotations/accented_text.py | 6 +++---
.../annotation_demo.py | 2 +-
.../text_labels_and_annotations/font_file.py | 6 +++---
.../text_labels_and_annotations/legend_demo.py | 2 --
.../axes/constrainedlayout_guide.py | 8 +++-----
galleries/users_explain/axes/legend_guide.py | 11 ++++-------
.../users_explain/axes/tight_layout_guide.py | 16 ++++++----------
.../colors/colormap-manipulation.py | 15 ++++++---------
galleries/users_explain/colors/colormaps.py | 6 +++---
galleries/users_explain/text/text_intro.py | 6 +++---
14 files changed, 42 insertions(+), 61 deletions(-)
diff --git a/galleries/examples/color/README.txt b/galleries/examples/color/README.txt
index 4bcdb526f4d4..4b8b3bc4b751 100644
--- a/galleries/examples/color/README.txt
+++ b/galleries/examples/color/README.txt
@@ -3,6 +3,5 @@
Color
=====
-For more in-depth information about the colormaps available in matplotlib
-as well as a description of their properties,
+For a description of the colormaps available in Matplotlib,
see the :ref:`colormaps tutorial `.
diff --git a/galleries/examples/color/named_colors.py b/galleries/examples/color/named_colors.py
index 9ae4ec4957f3..d9a7259da773 100644
--- a/galleries/examples/color/named_colors.py
+++ b/galleries/examples/color/named_colors.py
@@ -3,7 +3,7 @@
List of named colors
====================
-This plots a list of the named colors supported in matplotlib.
+This plots a list of the named colors supported by Matplotlib.
For more information on colors in matplotlib see
* the :ref:`colors_def` tutorial;
diff --git a/galleries/examples/images_contours_and_fields/image_demo.py b/galleries/examples/images_contours_and_fields/image_demo.py
index 884e68172698..213b6cdd28c2 100644
--- a/galleries/examples/images_contours_and_fields/image_demo.py
+++ b/galleries/examples/images_contours_and_fields/image_demo.py
@@ -1,9 +1,7 @@
"""
-==========
-Image demo
-==========
-
-Many ways to plot images in Matplotlib.
+========================
+Many ways to plot images
+========================
The most common way to plot images in Matplotlib is with
`~.axes.Axes.imshow`. The following examples demonstrate much of the
diff --git a/galleries/examples/images_contours_and_fields/pcolor_demo.py b/galleries/examples/images_contours_and_fields/pcolor_demo.py
index a783c83409df..7a8ef35caf96 100644
--- a/galleries/examples/images_contours_and_fields/pcolor_demo.py
+++ b/galleries/examples/images_contours_and_fields/pcolor_demo.py
@@ -1,13 +1,11 @@
"""
-===========
-Pcolor demo
-===========
+=============
+pcolor images
+=============
-Generating images with `~.axes.Axes.pcolor`.
-
-Pcolor allows you to generate 2D image-style plots. Below we will show how
-to do so in Matplotlib.
+`~.Axes.pcolor` generates 2D image-style plots, as illustrated below.
"""
+
import matplotlib.pyplot as plt
import numpy as np
diff --git a/galleries/examples/text_labels_and_annotations/accented_text.py b/galleries/examples/text_labels_and_annotations/accented_text.py
index f57b19532a43..7ff080afefd9 100644
--- a/galleries/examples/text_labels_and_annotations/accented_text.py
+++ b/galleries/examples/text_labels_and_annotations/accented_text.py
@@ -1,7 +1,7 @@
r"""
-=================================
-Using accented text in Matplotlib
-=================================
+=============
+Accented text
+=============
Matplotlib supports accented characters via TeX mathtext or Unicode.
diff --git a/galleries/examples/text_labels_and_annotations/annotation_demo.py b/galleries/examples/text_labels_and_annotations/annotation_demo.py
index 8b310a7a1865..26f3b80bf203 100644
--- a/galleries/examples/text_labels_and_annotations/annotation_demo.py
+++ b/galleries/examples/text_labels_and_annotations/annotation_demo.py
@@ -3,7 +3,7 @@
Annotating Plots
================
-The following examples show how it is possible to annotate plots in Matplotlib.
+The following examples show ways to annotate plots in Matplotlib.
This includes highlighting specific points of interest and using various
visual tools to call attention to this point. For a more complete and in-depth
description of the annotation and text tools in Matplotlib, see the
diff --git a/galleries/examples/text_labels_and_annotations/font_file.py b/galleries/examples/text_labels_and_annotations/font_file.py
index 8242b57839aa..b4a58808d716 100644
--- a/galleries/examples/text_labels_and_annotations/font_file.py
+++ b/galleries/examples/text_labels_and_annotations/font_file.py
@@ -1,7 +1,7 @@
r"""
-===================================
-Using a ttf font file in Matplotlib
-===================================
+====================
+Using ttf font files
+====================
Although it is usually not a good idea to explicitly point to a single ttf file
for a font instance, you can do so by passing a `pathlib.Path` instance as the
diff --git a/galleries/examples/text_labels_and_annotations/legend_demo.py b/galleries/examples/text_labels_and_annotations/legend_demo.py
index a425d39b7d8f..2f550729837e 100644
--- a/galleries/examples/text_labels_and_annotations/legend_demo.py
+++ b/galleries/examples/text_labels_and_annotations/legend_demo.py
@@ -3,8 +3,6 @@
Legend Demo
===========
-Plotting legends in Matplotlib.
-
There are many ways to create and customize legends in Matplotlib. Below
we'll show a few examples for how to do so.
diff --git a/galleries/users_explain/axes/constrainedlayout_guide.py b/galleries/users_explain/axes/constrainedlayout_guide.py
index 260a4f76bf71..4581f5f67808 100644
--- a/galleries/users_explain/axes/constrainedlayout_guide.py
+++ b/galleries/users_explain/axes/constrainedlayout_guide.py
@@ -40,15 +40,13 @@
.. warning::
- Calling ``plt.tight_layout()`` will turn off *constrained layout*!
+ Calling `~.pyplot.tight_layout` will turn off *constrained layout*!
Simple example
==============
-In Matplotlib, the location of Axes (including subplots) are specified in
-normalized figure coordinates. It can happen that your axis labels or titles
-(or sometimes even ticklabels) go outside the figure area, and are thus
-clipped.
+With the default Axes positioning, the axes title, axis labels, or tick labels
+can sometimes go outside the figure area, and thus get clipped.
"""
# sphinx_gallery_thumbnail_number = 18
diff --git a/galleries/users_explain/axes/legend_guide.py b/galleries/users_explain/axes/legend_guide.py
index 9900b0aa4bdd..3b138fe8ada3 100644
--- a/galleries/users_explain/axes/legend_guide.py
+++ b/galleries/users_explain/axes/legend_guide.py
@@ -7,13 +7,10 @@
Legend guide
============
-Generating legends flexibly in Matplotlib.
-
.. currentmodule:: matplotlib.pyplot
-This legend guide is an extension of the documentation available at
-:func:`~matplotlib.pyplot.legend` - please ensure you are familiar with
-contents of that documentation before proceeding with this guide.
+This legend guide extends the `~.Axes.legend` docstring -
+please read it before proceeding with this guide.
This guide makes use of some common terms, which are documented here for
clarity:
@@ -62,8 +59,8 @@
line_down, = ax.plot([3, 2, 1], label='Line 1')
ax.legend(handles=[line_up, line_down])
-In some cases, it is not possible to set the label of the handle, so it is
-possible to pass through the list of labels to :func:`legend`::
+In the rare case where the labels cannot directly be set on the handles, they
+can also be directly passed to :func:`legend`::
fig, ax = plt.subplots()
line_up, = ax.plot([1, 2, 3], label='Line 2')
diff --git a/galleries/users_explain/axes/tight_layout_guide.py b/galleries/users_explain/axes/tight_layout_guide.py
index 42c227b2e360..8525b9773f91 100644
--- a/galleries/users_explain/axes/tight_layout_guide.py
+++ b/galleries/users_explain/axes/tight_layout_guide.py
@@ -17,15 +17,11 @@
An alternative to *tight_layout* is :ref:`constrained_layout
`.
-
-Simple Example
+Simple example
==============
-In matplotlib, the location of axes (including subplots) are specified in
-normalized figure coordinates. It can happen that your axis labels or
-titles (or sometimes even ticklabels) go outside the figure area, and are thus
-clipped.
-
+With the default Axes positioning, the axes title, axis labels, or tick labels
+can sometimes go outside the figure area, and thus get clipped.
"""
# sphinx_gallery_thumbnail_number = 7
@@ -190,8 +186,8 @@ def example_plot(ax, fontsize=12):
# %%
# You may provide an optional *rect* parameter, which specifies the bounding
-# box that the subplots will be fit inside. The coordinates must be in
-# normalized figure coordinates and the default is (0, 0, 1, 1).
+# box that the subplots will be fit inside. The coordinates are in
+# normalized figure coordinates and default to (0, 0, 1, 1) (the whole figure).
fig = plt.figure()
@@ -245,7 +241,7 @@ def example_plot(ax, fontsize=12):
# Use with AxesGrid1
# ==================
#
-# While limited, :mod:`mpl_toolkits.axes_grid1` is also supported.
+# Limited support for :mod:`mpl_toolkits.axes_grid1` is provided.
from mpl_toolkits.axes_grid1 import Grid
diff --git a/galleries/users_explain/colors/colormap-manipulation.py b/galleries/users_explain/colors/colormap-manipulation.py
index 88e4c5befaf0..87269b87befa 100644
--- a/galleries/users_explain/colors/colormap-manipulation.py
+++ b/galleries/users_explain/colors/colormap-manipulation.py
@@ -3,9 +3,9 @@
.. _colormap-manipulation:
-********************************
-Creating Colormaps in Matplotlib
-********************************
+******************
+Creating Colormaps
+******************
Matplotlib has a number of built-in colormaps accessible via
`.matplotlib.colormaps`. There are also external libraries like
@@ -13,17 +13,15 @@
.. _palettable: https://jiffyclub.github.io/palettable/
-However, we often want to create or manipulate colormaps in Matplotlib.
+However, we may also want to create or manipulate our own colormaps.
This can be done using the class `.ListedColormap` or
`.LinearSegmentedColormap`.
-Seen from the outside, both colormap classes map values between 0 and 1 to
-a bunch of colors. There are, however, slight differences, some of which are
-shown in the following.
+Both colormap classes map values between 0 and 1 to colors. There are however
+differences, as explained below.
Before manually creating or manipulating colormaps, let us first see how we
can obtain colormaps and their colors from existing colormap classes.
-
Getting colormaps and accessing their values
============================================
@@ -32,7 +30,6 @@
which returns a colormap object. The length of the list of colors used
internally to define the colormap can be adjusted via `.Colormap.resampled`.
Below we use a modest value of 8 so there are not a lot of values to look at.
-
"""
import matplotlib.pyplot as plt
diff --git a/galleries/users_explain/colors/colormaps.py b/galleries/users_explain/colors/colormaps.py
index 92b56d298976..b5db551cb5b5 100644
--- a/galleries/users_explain/colors/colormaps.py
+++ b/galleries/users_explain/colors/colormaps.py
@@ -3,9 +3,9 @@
.. _colormaps:
-********************************
-Choosing Colormaps in Matplotlib
-********************************
+******************
+Choosing Colormaps
+******************
Matplotlib has a number of built-in colormaps accessible via
`.matplotlib.colormaps`. There are also external libraries that
diff --git a/galleries/users_explain/text/text_intro.py b/galleries/users_explain/text/text_intro.py
index 54fcb00c7a86..948545667fa9 100644
--- a/galleries/users_explain/text/text_intro.py
+++ b/galleries/users_explain/text/text_intro.py
@@ -4,9 +4,9 @@
.. _text_intro:
-========================
-Text in Matplotlib Plots
-========================
+==================
+Text in Matplotlib
+==================
Introduction to plotting and working with text in Matplotlib.
From 966d7e48e601d6b6b2e98c81ae9dc03fba6a437f Mon Sep 17 00:00:00 2001
From: Ruth Comer <10599679+rcomer@users.noreply.github.com>
Date: Mon, 6 Nov 2023 09:00:08 +0000
Subject: [PATCH 08/87] Backport PR #27271: DOC: minor fixes to dev workflow
---
doc/devel/development_setup.rst | 7 ++++---
doc/devel/development_workflow.rst | 6 +++---
2 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/doc/devel/development_setup.rst b/doc/devel/development_setup.rst
index e18d85cebde0..d5f491a82563 100644
--- a/doc/devel/development_setup.rst
+++ b/doc/devel/development_setup.rst
@@ -25,11 +25,12 @@ Fork the Matplotlib repository
==============================
Matplotlib is hosted at https://github.com/matplotlib/matplotlib.git. If you
-plan on solving issues or submit pull requests to the main Matplotlib
+plan on solving issues or submitting pull requests to the main Matplotlib
repository, you should first *fork* this repository by visiting
https://github.com/matplotlib/matplotlib.git and clicking on the
-``Fork`` button on the top right of the page (see
-`the GitHub documentation `__ for more details.)
+``Fork`` :octicon:`repo-forked` button on the top right of the page. See
+`the GitHub documentation `__
+for more details.
Retrieve the latest version of the code
=======================================
diff --git a/doc/devel/development_workflow.rst b/doc/devel/development_workflow.rst
index 3f4fe956e37e..edb21bb862cd 100644
--- a/doc/devel/development_workflow.rst
+++ b/doc/devel/development_workflow.rst
@@ -162,10 +162,10 @@ history clean.
You can achieve this by using
- .. code-block:: bash
+.. code-block:: bash
- git commit -a --amend --no-edit
- git push [your-remote-repo] [your-branch] --force-with-lease
+ git commit -a --amend --no-edit
+ git push [your-remote-repo] [your-branch] --force-with-lease
Manage commit history
From c5af4a4a813ba1dfb83ae7c047166b9825da84eb Mon Sep 17 00:00:00 2001
From: Ruth Comer <10599679+rcomer@users.noreply.github.com>
Date: Mon, 6 Nov 2023 09:00:08 +0000
Subject: [PATCH 09/87] Backport PR #27271: DOC: minor fixes to dev workflow
---
doc/devel/development_setup.rst | 7 ++++---
doc/devel/development_workflow.rst | 6 +++---
2 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/doc/devel/development_setup.rst b/doc/devel/development_setup.rst
index e18d85cebde0..d5f491a82563 100644
--- a/doc/devel/development_setup.rst
+++ b/doc/devel/development_setup.rst
@@ -25,11 +25,12 @@ Fork the Matplotlib repository
==============================
Matplotlib is hosted at https://github.com/matplotlib/matplotlib.git. If you
-plan on solving issues or submit pull requests to the main Matplotlib
+plan on solving issues or submitting pull requests to the main Matplotlib
repository, you should first *fork* this repository by visiting
https://github.com/matplotlib/matplotlib.git and clicking on the
-``Fork`` button on the top right of the page (see
-`the GitHub documentation `__ for more details.)
+``Fork`` :octicon:`repo-forked` button on the top right of the page. See
+`the GitHub documentation `__
+for more details.
Retrieve the latest version of the code
=======================================
diff --git a/doc/devel/development_workflow.rst b/doc/devel/development_workflow.rst
index 3f4fe956e37e..edb21bb862cd 100644
--- a/doc/devel/development_workflow.rst
+++ b/doc/devel/development_workflow.rst
@@ -162,10 +162,10 @@ history clean.
You can achieve this by using
- .. code-block:: bash
+.. code-block:: bash
- git commit -a --amend --no-edit
- git push [your-remote-repo] [your-branch] --force-with-lease
+ git commit -a --amend --no-edit
+ git push [your-remote-repo] [your-branch] --force-with-lease
Manage commit history
From 0800a480d15a0b5971dbc4dd3c150b3d5e9e073c Mon Sep 17 00:00:00 2001
From: hannah
Date: Mon, 6 Nov 2023 15:37:11 -0500
Subject: [PATCH 10/87] Backport PR #27276: Clarify behavior of `prune`
parameter to MaxNLocator.
---
lib/matplotlib/ticker.py | 12 +++++-------
1 file changed, 5 insertions(+), 7 deletions(-)
diff --git a/lib/matplotlib/ticker.py b/lib/matplotlib/ticker.py
index 958e25d7b2c7..5b1b7e11408c 100644
--- a/lib/matplotlib/ticker.py
+++ b/lib/matplotlib/ticker.py
@@ -1996,13 +1996,11 @@ def __init__(self, nbins=None, **kwargs):
If True, autoscaling will result in a range symmetric about zero.
prune : {'lower', 'upper', 'both', None}, default: None
- Remove edge ticks -- useful for stacked or ganged plots where
- the upper tick of one axes overlaps with the lower tick of the
- axes above it, primarily when :rc:`axes.autolimit_mode` is
- ``'round_numbers'``. If ``prune=='lower'``, the smallest tick will
- be removed. If ``prune == 'upper'``, the largest tick will be
- removed. If ``prune == 'both'``, the largest and smallest ticks
- will be removed. If *prune* is *None*, no ticks will be removed.
+ Remove the 'lower' tick, the 'upper' tick, or ticks on 'both' sides
+ *if they fall exactly on an axis' edge* (this typically occurs when
+ :rc:`axes.autolimit_mode` is 'round_numbers'). Removing such ticks
+ is mostly useful for stacked or ganged plots, where the upper tick
+ of an axes overlaps with the lower tick of the axes above it.
min_n_ticks : int, default: 2
Relax *nbins* and *integer* constraints if necessary to obtain
From e3eb638135a59155f9f00b30c70e95533f1c181c Mon Sep 17 00:00:00 2001
From: Thomas A Caswell
Date: Tue, 7 Nov 2023 10:51:56 -0500
Subject: [PATCH 11/87] Backport PR #27280: DOC: added rest of licenses to
license page
---
doc/_static/mpl.css | 19 ++++++++
doc/users/project/license.rst | 85 ++++++++++++++++++++++++++++++++++-
2 files changed, 102 insertions(+), 2 deletions(-)
diff --git a/doc/_static/mpl.css b/doc/_static/mpl.css
index a37fb76a0436..2b57f7608d26 100644
--- a/doc/_static/mpl.css
+++ b/doc/_static/mpl.css
@@ -180,3 +180,22 @@ div.wide-table table th.stub {
.checklist li p {
display: inline;
}
+
+.sdd.sd-dropdown {
+ box-shadow: none!important;
+}
+
+.sdd.sd-dropdown.sd-card{
+ border-style: solid !important;
+ border-color: var(--pst-color-border) !important;
+ border-width: thin !important;
+ border-radius: .05
+}
+
+.sdd.sd-dropdown .sd-card-header{
+ --pst-sd-dropdown-color: none;
+}
+
+.sdd.sd-dropdown .sd-card-header +.sd-card-body{
+ --pst-sd-dropdown-color: none;
+}
diff --git a/doc/users/project/license.rst b/doc/users/project/license.rst
index a55927d9f2c5..3f9c1e30531b 100644
--- a/doc/users/project/license.rst
+++ b/doc/users/project/license.rst
@@ -46,5 +46,86 @@ control logs.
License agreement
=================
-.. literalinclude:: ../../../LICENSE/LICENSE
- :language: none
+.. dropdown:: License agreement for Matplotlib versions 1.3.0 and later
+ :open:
+ :class-container: sdd
+
+ .. literalinclude:: ../../../LICENSE/LICENSE
+ :language: none
+
+
+
+Bundled software
+================
+
+.. dropdown:: JSX Tools Resize Observer
+ :class-container: sdd
+
+ .. literalinclude:: ../../../LICENSE/LICENSE_JSXTOOLS_RESIZE_OBSERVER
+ :language: none
+
+.. dropdown:: QT4 Editor
+ :class-container: sdd
+
+ .. literalinclude:: ../../../LICENSE/LICENSE_QT4_EDITOR
+ :language: none
+
+
+.. _licenses-cmaps-styles:
+
+Colormaps and themes
+--------------------
+
+.. dropdown:: ColorBrewer
+ :class-container: sdd
+
+ .. literalinclude:: ../../../LICENSE/LICENSE_COLORBREWER
+ :language: none
+
+.. dropdown:: Solarized
+ :class-container: sdd
+
+ .. literalinclude:: ../../../LICENSE/LICENSE_SOLARIZED
+ :language: none
+
+.. dropdown:: Yorick
+ :class-container: sdd
+
+ .. literalinclude:: ../../../LICENSE/LICENSE_YORICK
+ :language: none
+
+
+.. _licenses-fonts:
+
+Fonts
+-----
+
+.. dropdown:: American Mathematical Society (AMS) fonts
+ :class-container: sdd
+
+ .. literalinclude:: ../../../LICENSE/LICENSE_AMSFONTS
+ :language: none
+
+.. dropdown:: BaKoMa
+ :class-container: sdd
+
+ .. literalinclude:: ../../../LICENSE/LICENSE_BAKOMA
+ :language: none
+
+.. dropdown:: Carlogo
+ :class-container: sdd
+
+ .. literalinclude:: ../../../LICENSE/LICENSE_CARLOGO
+ :language: none
+
+.. dropdown:: Courier 10
+ :class-container: sdd
+
+ .. literalinclude:: ../../../LICENSE/LICENSE_COURIERTEN
+ :language: none
+
+.. dropdown:: STIX
+ :class-container: sdd
+
+ .. literalinclude:: ../../../LICENSE/LICENSE_STIX
+ :language: none
From c143710e08ee95aa6c4cd5bd32a6605f843b1ac6 Mon Sep 17 00:00:00 2001
From: Thomas A Caswell
Date: Wed, 8 Nov 2023 19:41:23 -0500
Subject: [PATCH 12/87] Backport PR #27290: Ensure GIL while releasing buffer
---
src/_macosx.m | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/_macosx.m b/src/_macosx.m
index 6df00d0eca8e..a580362f676f 100755
--- a/src/_macosx.m
+++ b/src/_macosx.m
@@ -1132,8 +1132,10 @@ - (void)setCanvas: (PyObject*)newCanvas
}
static void _buffer_release(void* info, const void* data, size_t size) {
+ PyGILState_STATE gstate = PyGILState_Ensure();
PyBuffer_Release((Py_buffer *)info);
free(info);
+ PyGILState_Release(gstate);
}
static int _copy_agg_buffer(CGContextRef cr, PyObject *renderer)
From d88a3d347aeb9aa3621eeaf5b689ffe6fbc4162d Mon Sep 17 00:00:00 2001
From: Oscar Gustafsson
Date: Thu, 9 Nov 2023 10:03:51 +0100
Subject: [PATCH 13/87] Backport PR #27291: Expand 3D import to handle any
exception not just ImportError
---
lib/matplotlib/projections/__init__.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/matplotlib/projections/__init__.py b/lib/matplotlib/projections/__init__.py
index 8ce118986065..4c5ef8e2508d 100644
--- a/lib/matplotlib/projections/__init__.py
+++ b/lib/matplotlib/projections/__init__.py
@@ -58,7 +58,7 @@
try:
from mpl_toolkits.mplot3d import Axes3D
-except ImportError:
+except Exception:
import warnings
warnings.warn("Unable to import Axes3D. This may be due to multiple versions of "
"Matplotlib being installed (e.g. as a system package and as a pip "
From 62364314d3d4a9d27d82d08fe09cba2f05e80988 Mon Sep 17 00:00:00 2001
From: Oscar Gustafsson
Date: Mon, 13 Nov 2023 12:35:22 +0100
Subject: [PATCH 14/87] Backport PR #27312: Doc: Step redirect
---
galleries/plot_types/basic/stairs.py | 2 ++
1 file changed, 2 insertions(+)
diff --git a/galleries/plot_types/basic/stairs.py b/galleries/plot_types/basic/stairs.py
index e8ca455c0e2f..9bc5d025f1e1 100644
--- a/galleries/plot_types/basic/stairs.py
+++ b/galleries/plot_types/basic/stairs.py
@@ -4,6 +4,8 @@
==============
See `~matplotlib.axes.Axes.stairs`.
+
+.. redirect-from:: /plot_types/basic/step
"""
import matplotlib.pyplot as plt
import numpy as np
From c1349f6f27d78eb05750ba540328b8f985a006ac Mon Sep 17 00:00:00 2001
From: Oscar Gustafsson
Date: Mon, 13 Nov 2023 12:35:22 +0100
Subject: [PATCH 15/87] Backport PR #27312: Doc: Step redirect
---
galleries/plot_types/basic/stairs.py | 2 ++
1 file changed, 2 insertions(+)
diff --git a/galleries/plot_types/basic/stairs.py b/galleries/plot_types/basic/stairs.py
index e8ca455c0e2f..9bc5d025f1e1 100644
--- a/galleries/plot_types/basic/stairs.py
+++ b/galleries/plot_types/basic/stairs.py
@@ -4,6 +4,8 @@
==============
See `~matplotlib.axes.Axes.stairs`.
+
+.. redirect-from:: /plot_types/basic/step
"""
import matplotlib.pyplot as plt
import numpy as np
From 2b587481f9e93461f770d63c5e7f5759b662a27a Mon Sep 17 00:00:00 2001
From: hannah
Date: Tue, 14 Nov 2023 12:40:19 -0500
Subject: [PATCH 16/87] Backport PR #27323: [DOC] Minor fixes for
savefig-docstring
---
lib/matplotlib/figure.py | 40 ++++++++++++++++++++--------------------
1 file changed, 20 insertions(+), 20 deletions(-)
diff --git a/lib/matplotlib/figure.py b/lib/matplotlib/figure.py
index b2d75bcdd736..e8a5f154d593 100644
--- a/lib/matplotlib/figure.py
+++ b/lib/matplotlib/figure.py
@@ -3237,10 +3237,10 @@ def savefig(self, fname, *, transparent=None, **kwargs):
Call signature::
- savefig(fname, *, dpi='figure', format=None, metadata=None,
- bbox_inches=None, pad_inches=0.1,
- facecolor='auto', edgecolor='auto',
- backend=None, **kwargs
+ savefig(fname, *, transparent=None, dpi='figure', format=None,
+ metadata=None, bbox_inches=None, pad_inches=0.1,
+ facecolor='auto', edgecolor='auto', backend=None,
+ **kwargs
)
The available output formats depend on the backend being used.
@@ -3265,6 +3265,22 @@ def savefig(self, fname, *, transparent=None, **kwargs):
Other Parameters
----------------
+ transparent : bool, default: :rc:`savefig.transparent`
+ If *True*, the Axes patches will all be transparent; the
+ Figure patch will also be transparent unless *facecolor*
+ and/or *edgecolor* are specified via kwargs.
+
+ If *False* has no effect and the color of the Axes and
+ Figure patches are unchanged (unless the Figure patch
+ is specified via the *facecolor* and/or *edgecolor* keyword
+ arguments in which case those colors are used).
+
+ The transparency of these patches will be restored to their
+ original values upon exit of this function.
+
+ This is useful, for example, for displaying
+ a plot on top of a colored background on a web page.
+
dpi : float or 'figure', default: :rc:`savefig.dpi`
The resolution in dots per inch. If 'figure', use the figure's
dpi value.
@@ -3324,22 +3340,6 @@ def savefig(self, fname, *, transparent=None, **kwargs):
'a10', 'b0' through 'b10'. Only supported for postscript
output.
- transparent : bool
- If *True*, the Axes patches will all be transparent; the
- Figure patch will also be transparent unless *facecolor*
- and/or *edgecolor* are specified via kwargs.
-
- If *False* has no effect and the color of the Axes and
- Figure patches are unchanged (unless the Figure patch
- is specified via the *facecolor* and/or *edgecolor* keyword
- arguments in which case those colors are used).
-
- The transparency of these patches will be restored to their
- original values upon exit of this function.
-
- This is useful, for example, for displaying
- a plot on top of a colored background on a web page.
-
bbox_extra_artists : list of `~matplotlib.artist.Artist`, optional
A list of extra artists that will be considered when the
tight bbox is calculated.
From 26fd30a34f26009ef7b8a3c4f623d87b8829e31e Mon Sep 17 00:00:00 2001
From: Thomas A Caswell
Date: Thu, 16 Nov 2023 18:58:32 -0500
Subject: [PATCH 17/87] Backport PR #27334: Omit MOVETO lines from nearest
contour logic
---
lib/matplotlib/contour.py | 21 ++++++++++++---------
lib/matplotlib/tests/test_contour.py | 19 +++++++++++++++++++
2 files changed, 31 insertions(+), 9 deletions(-)
diff --git a/lib/matplotlib/contour.py b/lib/matplotlib/contour.py
index f5ac14dff34d..6e889968642f 100644
--- a/lib/matplotlib/contour.py
+++ b/lib/matplotlib/contour.py
@@ -1392,15 +1392,18 @@ def _find_nearest_contour(self, xy, indices=None):
for idx_level in indices:
path = self._paths[idx_level]
- if not len(path.vertices):
- continue
- lc = self.get_transform().transform(path.vertices)
- d2, proj, leg = _find_closest_point_on_path(lc, xy)
- if d2 < d2min:
- d2min = d2
- idx_level_min = idx_level
- idx_vtx_min = leg[1]
- proj_min = proj
+ idx_vtx_start = 0
+ for subpath in path._iter_connected_components():
+ if not len(subpath.vertices):
+ continue
+ lc = self.get_transform().transform(subpath.vertices)
+ d2, proj, leg = _find_closest_point_on_path(lc, xy)
+ if d2 < d2min:
+ d2min = d2
+ idx_level_min = idx_level
+ idx_vtx_min = leg[1] + idx_vtx_start
+ proj_min = proj
+ idx_vtx_start += len(subpath)
return idx_level_min, idx_vtx_min, proj_min
diff --git a/lib/matplotlib/tests/test_contour.py b/lib/matplotlib/tests/test_contour.py
index db8ef03925cd..f79584be4086 100644
--- a/lib/matplotlib/tests/test_contour.py
+++ b/lib/matplotlib/tests/test_contour.py
@@ -125,6 +125,25 @@ def test_contour_manual_labels(split_collections):
plt.clabel(cs, manual=pts, fontsize='small', colors=('r', 'g'))
+def test_contour_manual_moveto():
+ x = np.linspace(-10, 10)
+ y = np.linspace(-10, 10)
+
+ X, Y = np.meshgrid(x, y)
+
+ Z = X**2 * 1 / Y**2 - 1
+
+ contours = plt.contour(X, Y, Z, levels=[0, 100])
+
+ # This point lies on the `MOVETO` line for the 100 contour
+ # but is actually closest to the 0 contour
+ point = (1.3, 1)
+ clabels = plt.clabel(contours, manual=[point])
+
+ # Ensure that the 0 contour was chosen, not the 100 contour
+ assert clabels[0].get_text() == "0"
+
+
@pytest.mark.parametrize("split_collections", [False, True])
@image_comparison(['contour_disconnected_segments'],
remove_text=True, style='mpl20', extensions=['png'])
From cfb494f815ec9ee1318c8e810dbaf10d3be5112f Mon Sep 17 00:00:00 2001
From: Kyle Sunden
Date: Thu, 16 Nov 2023 18:40:44 -0600
Subject: [PATCH 18/87] Backport PR #27299: [MNT] swap xkcd script for humor
sans
---
.circleci/config.yml | 6 +++---
.devcontainer/devcontainer.json | 2 +-
doc/devel/dependencies.rst | 3 +--
lib/matplotlib/mpl-data/matplotlibrc | 2 +-
lib/matplotlib/mpl-data/stylelib/classic.mplstyle | 2 +-
lib/matplotlib/pyplot.py | 12 ++++++------
lib/matplotlib/tests/test_axes.py | 2 +-
lib/matplotlib/textpath.py | 2 +-
8 files changed, 15 insertions(+), 16 deletions(-)
diff --git a/.circleci/config.yml b/.circleci/config.yml
index 8f1f3d6e313d..0668f436ddac 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -59,22 +59,22 @@ commands:
graphviz \
fonts-crosextra-carlito \
fonts-freefont-otf \
- fonts-humor-sans \
fonts-noto-cjk \
optipng
fonts-install:
steps:
- restore_cache:
- key: fonts-2
+ key: fonts-4
- run:
name: Install custom fonts
command: |
mkdir -p ~/.local/share/fonts
wget -nc https://github.com/google/fonts/blob/master/ofl/felipa/Felipa-Regular.ttf?raw=true -O ~/.local/share/fonts/Felipa-Regular.ttf || true
+ wget -nc https://github.com/ipython/xkcd-font/blob/master/xkcd-script/font/xkcd-script.ttf?raw=true -O ~/.local/share/fonts/xkcd-Script.ttf || true
fc-cache -f -v
- save_cache:
- key: fonts-2
+ key: fonts-4
paths:
- ~/.local/share/fonts/
diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
index 814c066c43b1..ddec2754d03a 100644
--- a/.devcontainer/devcontainer.json
+++ b/.devcontainer/devcontainer.json
@@ -7,7 +7,7 @@
"features": {
"ghcr.io/devcontainers/features/desktop-lite:1": {},
"ghcr.io/rocker-org/devcontainer-features/apt-packages:1": {
- "packages": "inkscape,ffmpeg,dvipng,lmodern,cm-super,texlive-latex-base,texlive-latex-extra,texlive-fonts-recommended,texlive-latex-recommended,texlive-pictures,texlive-xetex,fonts-wqy-zenhei,graphviz,fonts-crosextra-carlito,fonts-freefont-otf,fonts-humor-sans,fonts-noto-cjk,optipng"
+ "packages": "inkscape,ffmpeg,dvipng,lmodern,cm-super,texlive-latex-base,texlive-latex-extra,texlive-fonts-recommended,texlive-latex-recommended,texlive-pictures,texlive-xetex,fonts-wqy-zenhei,graphviz,fonts-crosextra-carlito,fonts-freefont-otf,fonts-comic-neue,fonts-noto-cjk,optipng"
}
},
"onCreateCommand": ".devcontainer/setup.sh",
diff --git a/doc/devel/dependencies.rst b/doc/devel/dependencies.rst
index 400bc63d42ac..7c14d90180d6 100644
--- a/doc/devel/dependencies.rst
+++ b/doc/devel/dependencies.rst
@@ -399,8 +399,7 @@ Optional, but recommended:
* `Inkscape `_
* `optipng `_
-* the font "Humor Sans" (aka the "XKCD" font), or the free alternative
- `Comic Neue `_
+* the font `xkcd script `_ or `Comic Neue `_
* the font "Times New Roman"
.. note::
diff --git a/lib/matplotlib/mpl-data/matplotlibrc b/lib/matplotlib/mpl-data/matplotlibrc
index 2c53651da3d6..5014aa448968 100644
--- a/lib/matplotlib/mpl-data/matplotlibrc
+++ b/lib/matplotlib/mpl-data/matplotlibrc
@@ -269,7 +269,7 @@
#font.serif: DejaVu Serif, Bitstream Vera Serif, Computer Modern Roman, New Century Schoolbook, Century Schoolbook L, Utopia, ITC Bookman, Bookman, Nimbus Roman No9 L, Times New Roman, Times, Palatino, Charter, serif
#font.sans-serif: DejaVu Sans, Bitstream Vera Sans, Computer Modern Sans Serif, Lucida Grande, Verdana, Geneva, Lucid, Arial, Helvetica, Avant Garde, sans-serif
#font.cursive: Apple Chancery, Textile, Zapf Chancery, Sand, Script MT, Felipa, Comic Neue, Comic Sans MS, cursive
-#font.fantasy: Chicago, Charcoal, Impact, Western, Humor Sans, xkcd, fantasy
+#font.fantasy: Chicago, Charcoal, Impact, Western, xkcd script, fantasy
#font.monospace: DejaVu Sans Mono, Bitstream Vera Sans Mono, Computer Modern Typewriter, Andale Mono, Nimbus Mono L, Courier New, Courier, Fixed, Terminal, monospace
diff --git a/lib/matplotlib/mpl-data/stylelib/classic.mplstyle b/lib/matplotlib/mpl-data/stylelib/classic.mplstyle
index 09a38df282f1..e1768e5a6145 100644
--- a/lib/matplotlib/mpl-data/stylelib/classic.mplstyle
+++ b/lib/matplotlib/mpl-data/stylelib/classic.mplstyle
@@ -91,7 +91,7 @@ font.size : 12.0
font.serif : DejaVu Serif, New Century Schoolbook, Century Schoolbook L, Utopia, ITC Bookman, Bookman, Nimbus Roman No9 L, Times New Roman, Times, Palatino, Charter, serif
font.sans-serif: DejaVu Sans, Lucida Grande, Verdana, Geneva, Lucid, Arial, Helvetica, Avant Garde, sans-serif
font.cursive : Apple Chancery, Textile, Zapf Chancery, Sand, Script MT, Felipa, cursive
-font.fantasy : Comic Sans MS, Chicago, Charcoal, ImpactWestern, Humor Sans, fantasy
+font.fantasy : Comic Sans MS, Chicago, Charcoal, ImpactWestern, xkcd script, fantasy
font.monospace : DejaVu Sans Mono, Andale Mono, Nimbus Mono L, Courier New, Courier, Fixed, Terminal, monospace
### TEXT
diff --git a/lib/matplotlib/pyplot.py b/lib/matplotlib/pyplot.py
index 42ea405c17cc..62f7eba74eea 100644
--- a/lib/matplotlib/pyplot.py
+++ b/lib/matplotlib/pyplot.py
@@ -707,11 +707,12 @@ def xkcd(
scale: float = 1, length: float = 100, randomness: float = 2
) -> ExitStack:
"""
- Turn on `xkcd `_ sketch-style drawing mode. This will
- only have effect on things drawn after this function is called.
+ Turn on `xkcd `_ sketch-style drawing mode.
- For best results, the "Humor Sans" font should be installed: it is
- not included with Matplotlib.
+ This will only have an effect on things drawn after this function is called.
+
+ For best results, install the `xkcd script `_
+ font; xkcd fonts are not packaged with Matplotlib.
Parameters
----------
@@ -750,8 +751,7 @@ def xkcd(
from matplotlib import patheffects
rcParams.update({
- 'font.family': ['xkcd', 'xkcd Script', 'Humor Sans', 'Comic Neue',
- 'Comic Sans MS'],
+ 'font.family': ['xkcd', 'xkcd Script', 'Comic Neue', 'Comic Sans MS'],
'font.size': 14.0,
'path.sketch': (scale, length, randomness),
'path.effects': [
diff --git a/lib/matplotlib/tests/test_axes.py b/lib/matplotlib/tests/test_axes.py
index 6c5dd712b7fd..edc040eff3dd 100644
--- a/lib/matplotlib/tests/test_axes.py
+++ b/lib/matplotlib/tests/test_axes.py
@@ -8813,7 +8813,7 @@ def test_tick_param_labelfont():
fig, ax = plt.subplots()
ax.plot([1, 2, 3, 4], [1, 2, 3, 4])
ax.set_xlabel('X label in Impact font', fontname='Impact')
- ax.set_ylabel('Y label in Humor Sans', fontname='Humor Sans')
+ ax.set_ylabel('Y label in xkcd script', fontname='xkcd script')
ax.tick_params(color='r', labelfontfamily='monospace')
plt.title('Title in sans-serif')
for text in ax.get_xticklabels():
diff --git a/lib/matplotlib/textpath.py b/lib/matplotlib/textpath.py
index de97899f8a72..c00966d6e6c3 100644
--- a/lib/matplotlib/textpath.py
+++ b/lib/matplotlib/textpath.py
@@ -99,7 +99,7 @@ def get_text_path(self, prop, s, ismath=False):
from matplotlib.text import TextToPath
from matplotlib.font_manager import FontProperties
- fp = FontProperties(family="Humor Sans", style="italic")
+ fp = FontProperties(family="Comic Neue", style="italic")
verts, codes = TextToPath().get_text_path(fp, "ABC")
path = Path(verts, codes, closed=False)
From dfb7a469d6e3e398ae87de48b284c5c29b7715d5 Mon Sep 17 00:00:00 2001
From: Kyle Sunden
Date: Fri, 17 Nov 2023 11:55:15 -0600
Subject: [PATCH 19/87] Github stats fo v3.8.2
---
doc/users/github_stats.rst | 182 ++++--------------
doc/users/installing/index.rst | 2 +-
.../prev_whats_new/github_stats_3.8.1.rst | 168 ++++++++++++++++
doc/users/release_notes.rst | 1 +
4 files changed, 208 insertions(+), 145 deletions(-)
create mode 100644 doc/users/prev_whats_new/github_stats_3.8.1.rst
diff --git a/doc/users/github_stats.rst b/doc/users/github_stats.rst
index d521df2080fb..ab2660464ceb 100644
--- a/doc/users/github_stats.rst
+++ b/doc/users/github_stats.rst
@@ -1,171 +1,65 @@
.. _github-stats:
-GitHub statistics for 3.8.1 (Oct 31, 2023)
+GitHub statistics for 3.8.2 (Nov 17, 2023)
==========================================
-GitHub statistics for 2023/09/15 (tag: v3.8.0) - 2023/10/31
+GitHub statistics for 2023/10/31 (tag: v3.8.1) - 2023/11/17
These lists are automatically generated, and may be incomplete or contain duplicates.
-We closed 24 issues and merged 95 pull requests.
-The full list can be seen `on GitHub `__
+We closed 3 issues and merged 27 pull requests.
+The full list can be seen `on GitHub `__
-The following 27 authors contributed 165 commits.
+The following 10 authors contributed 39 commits.
-* 0taj
* Antony Lee
-* Anvi Verma
-* Artyom Romanov
-* Augusto Borges
-* Chiraag Balu
-* David Stansby
-* dependabot[bot]
+* dohyun
* Elliott Sales de Andrade
-* Eric Firing
-* Gaurav-Kumar-Soni
-* Greg Lucas
-* Gurudatta Shanbhag
* hannah
-* Hugues Hoppe
* Jody Klymak
-* Joshua Stevenson
-* Junpei Ota
-* katotaisei
* Kyle Sunden
-* Lucia Korpas
-* Matthew Morrison
* Oscar Gustafsson
* Ruth Comer
* Thomas A Caswell
* Tim Hoffmann
-* wemi3
GitHub issues and pull requests:
-Pull Requests (95):
+Pull Requests (27):
-* :ghpull:`27239`: Backport PR #27237 on branch v3.8.x (DOC: Add command to install appropriate ``requirements.txt`` during dev venv setup)
-* :ghpull:`27238`: Backport PR #27165 on branch v3.8.x (Fixing Matplotlib Notebook Text)
-* :ghpull:`27165`: Fixing Matplotlib Notebook Text
-* :ghpull:`27229`: Backport PR #27226 on branch v3.8.x (DOC: link out to troubleshooting guide in install)
-* :ghpull:`27226`: DOC: link out to troubleshooting guide in install
-* :ghpull:`27227`: Backport PR #27221 on branch v3.8.x (FIX: Enable interrupts on macosx event loops)
-* :ghpull:`27221`: FIX: Enable interrupts on macosx event loops
-* :ghpull:`27220`: Backport PR #27217 on branch v3.8.x: Fix type hints for undeprecated contour APIs
-* :ghpull:`27217`: Fix type hints for undeprecated contour APIs
-* :ghpull:`27212`: Backport PR #27088 on branch v3.8.x (Update ``find_nearest_contour`` and revert contour deprecations)
-* :ghpull:`27207`: Backport PR #26970 on branch v3.8.x (FIX: Add PyOS_InputHook back to macos backend)
-* :ghpull:`27088`: Update ``find_nearest_contour`` and revert contour deprecations
-* :ghpull:`27206`: Backport PR #27205 on branch v3.8.x (Improve legend picking example)
-* :ghpull:`26970`: FIX: Add PyOS_InputHook back to macos backend
-* :ghpull:`27205`: Improve legend picking example
-* :ghpull:`27202`: Backport PR #27178 on branch v3.8.x (Try/except import of Axes3D)
-* :ghpull:`27178`: Try/except import of Axes3D
-* :ghpull:`27201`: Backport PR #27179 on branch v3.8.x (Restore default behavior of hexbin mincnt with C provided)
-* :ghpull:`27197`: Backport PR #27045 on branch v3.8.x (Ensure valid path mangling for ContourLabeler)
-* :ghpull:`27179`: Restore default behavior of hexbin mincnt with C provided
-* :ghpull:`27045`: Ensure valid path mangling for ContourLabeler
-* :ghpull:`27191`: Backport PR #27189 on branch v3.8.x (Fix typo in docstring of ``matplotlib.colors.from_levels_and_colors``)
-* :ghpull:`27189`: Fix typo in docstring of ``matplotlib.colors.from_levels_and_colors``
-* :ghpull:`27154`: Backport PR #27153 on branch v3.8.x (Link xkcd color survey in named colors example)
-* :ghpull:`27133`: Backport PR #27132 on branch v3.8.x (changed automated tests from subsection to section in workflow)
-* :ghpull:`27131`: Backport PR #27118 on branch v3.8.x (Update developer release guide to follow conventions)
-* :ghpull:`27118`: Update developer release guide to follow conventions
-* :ghpull:`27122`: Backport PR #26930 on branch v3.8.x (Added documentation on getting full list of registered colormaps re: issue #26244)
-* :ghpull:`26930`: Added documentation on getting full list of registered colormaps re: issue #26244
-* :ghpull:`27113`: Backport PR #27039 on branch v3.8.x (Formatted docs)
-* :ghpull:`27039`: Formatted release note docs
-* :ghpull:`27101`: Backport PR #27096 on branch v3.8.x (make fonts.py, mathtext.py, text_intro.py confirm to docs guidelines)
-* :ghpull:`27097`: Backport PR #27093 on branch v3.8.x ([Doc]: Move Automated Tests section to workflow docs #26998)
-* :ghpull:`27065`: Backport PR #26943 on branch v3.8.x (ci: Run mypy against typed cycler)
-* :ghpull:`26943`: ci: Run mypy against typed cycler
-* :ghpull:`27060`: Backport PR #27059: ci: Clean up Python 3.12 builds
-* :ghpull:`27057`: Backport PR #27040 on branch v3.8.x (Bump pypa/cibuildwheel from 2.16.1 to 2.16.2)
-* :ghpull:`27059`: ci: Clean up Python 3.12 builds
-* :ghpull:`27055`: Backport PR #27054 on branch v3.8.x (updated interactive.rst)
-* :ghpull:`27052`: Backport PR #27036 on branch v3.8.x (updated artist_intro.rst)
-* :ghpull:`27051`: Backport PR #26995 on branch v3.8.x (user/project/citing updated)
-* :ghpull:`27046`: Backport PR #27043 on branch v3.8.x (updated api_interfaces.rst)
-* :ghpull:`27040`: Bump pypa/cibuildwheel from 2.16.1 to 2.16.2
-* :ghpull:`27041`: Backport PR #26908 on branch v3.8.x (``allsegs`` and ``allkinds`` return individual segments)
-* :ghpull:`26908`: ``allsegs`` and ``allkinds`` return individual segments
-* :ghpull:`27034`: Backport PR #27017 on branch v3.8.x (DOC: clarify usetex versus mathtext)
-* :ghpull:`27017`: DOC: clarify usetex versus mathtext
-* :ghpull:`27031`: Backport PR #27015 on branch v3.8.x (ValueError exception added to handle mix of {} and % string in colorbar format)
-* :ghpull:`27015`: ValueError exception added to handle mix of {} and % string in colorbar format
-* :ghpull:`27022`: BLD: Remove development dependencies from sdists
-* :ghpull:`27023`: Backport PR #26883 on branch v3.8.x ([TYP] Type changes from running against Pandas)
-* :ghpull:`26883`: [TYP] Type changes from running against Pandas
-* :ghpull:`27018`: Backport PR #26961 on branch v3.8.x (DOC: made "open PR on MPL" a section in contribute guide)
-* :ghpull:`27009`: Backport PR #27006 on branch v3.8.x (DOC: Fix resizing of animation examples)
-* :ghpull:`26999`: Backport PR #26940 on branch v3.8.x (Add typing to pyplot.show() to avoid errors with mypy --strict.)
-* :ghpull:`27000`: Backport PR #26605 on branch v3.8.x (ci: Install GTK4 from brew on macOS)
-* :ghpull:`26982`: Backport PR #26976 on branch v3.8.x (Bump pypa/cibuildwheel from 2.16.0 to 2.16.1)
-* :ghpull:`26940`: Add typing to pyplot.show() to avoid errors with mypy --strict.
-* :ghpull:`26997`: Backport PR #26850 on branch v3.8.x (DOC: Fix missing-reference generation on Windows)
-* :ghpull:`26860`: Backport PR #26849 on branch v3.8.x (Bump setuptools required version because of setuptools_scm v8)
-* :ghpull:`26850`: DOC: Fix missing-reference generation on Windows
-* :ghpull:`26987`: Backport PR #26985 on branch v3.8.x (Reformatted documentation under toolkits and tutorials directory )
-* :ghpull:`26979`: Backport PR #26959 on branch v3.8.x (Move papersize="auto" deprecation to backend_bases.)
-* :ghpull:`26976`: Bump pypa/cibuildwheel from 2.16.0 to 2.16.1
-* :ghpull:`26959`: Move papersize="auto" deprecation to backend_bases.
-* :ghpull:`26939`: Backport PR #26937 on branch v3.8.x (Add ArrayLike to scatter c arg type hint)
-* :ghpull:`26964`: Backport PR #26952 on branch v3.8.x (FIX 2-tuple of colors in to_rgba_array)
-* :ghpull:`26956`: Backport PR #26955 on branch v3.8.x (Fix incorrect skip check in test_backend_ps.)
-* :ghpull:`26952`: FIX 2-tuple of colors in to_rgba_array
-* :ghpull:`26955`: Fix incorrect skip check in test_backend_ps.
-* :ghpull:`26945`: Backport PR #26927 on branch v3.8.x ([TYP] Remove some stubtest allowlist entries)
-* :ghpull:`26927`: [TYP] Remove some stubtest allowlist entries
-* :ghpull:`26937`: Add ArrayLike to scatter c arg type hint
-* :ghpull:`26933`: Backport PR #26914 on branch v3.8.x (DOC: add a couple more placement examples, crosslink axes_grid [ci doc])
-* :ghpull:`26849`: Bump setuptools required version because of setuptools_scm v8
-* :ghpull:`26844`: Backport PR #26843 on branch v3.8.x (DOC: Use ax.xaxis rather ax.get_xaxis())
-* :ghpull:`26836`: Backport PR #26834 on branch v3.8.x (Fix Issue 26821: [Bug]: ValueError: The truth value... when an ndarray is passed to the color kwarg of axes3d.scatter)
-* :ghpull:`26834`: Fix Issue 26821: [Bug]: ValueError: The truth value... when an ndarray is passed to the color kwarg of axes3d.scatter
-* :ghpull:`26835`: Backport PR #26814 on branch v3.8.x (Bump pypa/cibuildwheel from 2.15.0 to 2.16.0)
-* :ghpull:`26828`: Backport PR #26825 on branch v3.8.x (Fix issue with non-string labels and legend)
-* :ghpull:`26825`: Fix issue with non-string labels and legend
-* :ghpull:`26814`: Bump pypa/cibuildwheel from 2.15.0 to 2.16.0
-* :ghpull:`26816`: Backport PR #26799 on branch v3.8.x (Update kiwisolver and pillow versions to be consistent with requirements)
-* :ghpull:`26820`: Backport PR #26811 on branch v3.8.x (Add overload for slice to Spines.__getitem__)
-* :ghpull:`26811`: Add overload for slice to Spines.__getitem__
-* :ghpull:`26799`: Update kiwisolver and pillow versions to be consistent with requirements
-* :ghpull:`26809`: Backport PR #26804 on branch v3.8.x (Fix issue with locale comma when not using math text)
-* :ghpull:`26789`: Backport changes to contribute from PR #26737
-* :ghpull:`26810`: Backport PR #26807 on branch v3.8.x (Catch ValueError to support pytorch (and others) plotting)
-* :ghpull:`26807`: Catch ValueError to support pytorch (and others) plotting
-* :ghpull:`26804`: Fix issue with locale comma when not using math text
-* :ghpull:`26781`: Backport PR #26780 on branch v3.8.x (fix Axes.errorbar docstring)
-* :ghpull:`26780`: fix Axes.errorbar docstring
-* :ghpull:`26699`: Improve naming of cibuildwheel jobs
-* :ghpull:`26605`: ci: Install GTK4 from brew on macOS
+* :ghpull:`27339`: Backport PR #27299 on branch v3.8.x ([MNT] swap xkcd script for humor sans)
+* :ghpull:`27338`: Backport PR #27334 on branch v3.8.x (Omit MOVETO lines from nearest contour logic)
+* :ghpull:`27299`: [MNT] swap xkcd script for humor sans
+* :ghpull:`27334`: Omit MOVETO lines from nearest contour logic
+* :ghpull:`27324`: Backport PR #27323 on branch v3.8.x ([DOC] Minor fixes for savefig-docstring)
+* :ghpull:`27323`: [DOC] Minor fixes for savefig-docstring
+* :ghpull:`27314`: Backport PR #27312 on branch v3.8.x (Doc: Step redirect)
+* :ghpull:`27294`: Backport PR #27291 on branch v3.8.x (Expand 3D import to handle any exception not just ImportError)
+* :ghpull:`27291`: Expand 3D import to handle any exception not just ImportError
+* :ghpull:`27293`: Backport PR #27290 on branch v3.8.x (Ensure GIL while releasing buffer)
+* :ghpull:`27283`: Backport PR #27280 on branch v3.8.x (DOC: added rest of licenses to license page)
+* :ghpull:`27280`: DOC: added rest of licenses to license page
+* :ghpull:`27278`: Backport PR #27276 on branch v3.8.x (Clarify behavior of ``prune`` parameter to MaxNLocator.)
+* :ghpull:`27276`: Clarify behavior of ``prune`` parameter to MaxNLocator.
+* :ghpull:`27272`: Backport PR #27271 on branch v3.8.x (DOC: minor fixes to dev workflow)
+* :ghpull:`27269`: Backport PR #27268 on branch v3.8.x (Copy-edit various examples.)
+* :ghpull:`27263`: Backport PR #27213 on branch v3.8.x (DOC: consolidated coding guide and added naming conventions table)
+* :ghpull:`27258`: Backport PR #27249 on branch v3.8.x (DOC: reasoning for communications guidelines)
+* :ghpull:`27255`: Backport PR #27253 on branch v3.8.x (Copy-edit the standalone colorbar tutorial)
+* :ghpull:`27253`: Copy-edit the standalone colorbar tutorial
+* :ghpull:`27252`: Backport PR #26669 on branch v3.8.x ([DOC] debug backends)
+* :ghpull:`26669`: [DOC] debug backends
+* :ghpull:`27250`: Backport PR #27219 on branch v3.8.x (Updated axes_box_aspect.py and angle_annotation.py to regularize formatting)
+* :ghpull:`27219`: Updated axes_box_aspect.py and angle_annotation.py to regularize formatting
+* :ghpull:`27247`: Backport PR #26703 on branch v3.8.x (moved communications guidelines from governance, updated and clarified process )
+* :ghpull:`27246`: Backport PR #27244 on branch v3.8.x (Clarify semantics of plt.matshow(..., fignum=...).)
+* :ghpull:`27244`: Clarify semantics of plt.matshow(..., fignum=...).
-Issues (24):
+Issues (3):
-* :ghissue:`27120`: [Bug]: macosx backend pause() cannot be ctrl-c'd
-* :ghissue:`27070`: [Bug]: find_nearest_contour deprecated with no replacement?
-* :ghissue:`26913`: Should ``ContourSet.allsegs`` and ``.allkinds`` be deprecated?
-* :ghissue:`26869`: [Bug]: Plot window not shown in Mac OS with backend set to default MacOSX
-* :ghissue:`16865`: Hexbin mincnt parameter docstring should say "more than or equal to" not "more than"
-* :ghissue:`27103`: [Bug]: hexbin cannot always accept np.max like functions as reduce_C_function
-* :ghissue:`27062`: [Bug]: ContourLabeler.clabel with manual != False breaks unconnected contours
-* :ghissue:`26971`: [Bug]: plt.clabel raises exception at very low DPI: ``ValueError: 'codes' must be a 1D list or array with the same length of 'vertices'. Your vertices have shape (2, 2) but your codes have shape (1,)``
-* :ghissue:`27188`: Small error in docstring of matplotlib.colors.from_levels_and_colors
-* :ghissue:`27126`: [Bug]: LinearSegmentedColormap.from_list cannot process list with two colors
-* :ghissue:`26244`: [Doc]: document how to get list of registered colormaps
-* :ghissue:`26863`: [Doc]: ``ContourSet`` ``allsegs`` and ``allkinds`` after #25247
-* :ghissue:`26932`: [Bug]: Poetry installs setuptools-scm and setuptools
-* :ghissue:`27007`: [Bug]: Colorbar format string kind guess could be made more robust
-* :ghissue:`26919`: [Bug]: Missing file pyplot.pyi for mypy typing
-* :ghissue:`26949`: [Bug]: colors.LinearSegmentedColormap.from_list does not take two tuples in 3.8.0
-* :ghissue:`26936`: [Bug/TYPE]: Scatter ``c`` Typehint does not support list of numbers when using ``cmap``
-* :ghissue:`26846`: [MNT]: setuptools-scm v8.0.1 compatibility
-* :ghissue:`26821`: [Bug]: ``ValueError: The truth value...`` when an ndarray is passed to the ``color`` kwarg of ``axes3d.scatter``
-* :ghissue:`26822`: [Bug]: QuadMesh.get_array change breaks seaborn heatmap annotation
-* :ghissue:`26824`: [Bug]: Legend fails for bar plot with numeric label
-* :ghissue:`26808`: [Bug]: No overload variant of "__getitem__" of "Spines" matches argument type "slice" [call-overload]
-* :ghissue:`26806`: [Bug]: ValueError when plotting 2D pytorch tensor using matplotlib==3.8.0
-* :ghissue:`26803`: [Bug]: use_locale leads to curly brackets around decimal separator
+* :ghissue:`27333`: [Bug]: Spurious lines added with some manually add contour labels
+* :ghissue:`27274`: [Bug]: prune parameter of MaxNLocator has no effect
+* :ghissue:`27262`: [Bug]: Segmentation fault when resizing on Python 3.12 and MacOS 14
Previous GitHub statistics
diff --git a/doc/users/installing/index.rst b/doc/users/installing/index.rst
index c8c9ba549775..65fd8ee4182a 100644
--- a/doc/users/installing/index.rst
+++ b/doc/users/installing/index.rst
@@ -125,7 +125,7 @@ process. For example, which default backend to use, whether some of the
optional libraries that Matplotlib ships with are installed, and so on. This
file will be particularly useful to those packaging Matplotlib.
-.. _mplsetup.cfg: https://raw.githubusercontent.com/matplotlib/matplotlib/main/mplsetup.cfg.template
+.. _mplsetup.cfg: https://raw.githubusercontent.com/matplotlib/matplotlib/v3.8.x/mplsetup.cfg.template
If you are building your own Matplotlib wheels (or sdists) on Windows, note
that any DLLs that you copy into the source tree will be packaged too.
diff --git a/doc/users/prev_whats_new/github_stats_3.8.1.rst b/doc/users/prev_whats_new/github_stats_3.8.1.rst
new file mode 100644
index 000000000000..86de0e3b70a9
--- /dev/null
+++ b/doc/users/prev_whats_new/github_stats_3.8.1.rst
@@ -0,0 +1,168 @@
+.. _github-stats-3-8-1:
+
+GitHub statistics for 3.8.1 (Oct 31, 2023)
+==========================================
+
+GitHub statistics for 2023/09/15 (tag: v3.8.0) - 2023/10/31
+
+These lists are automatically generated, and may be incomplete or contain duplicates.
+
+We closed 24 issues and merged 95 pull requests.
+The full list can be seen `on GitHub `__
+
+The following 27 authors contributed 165 commits.
+
+* 0taj
+* Antony Lee
+* Anvi Verma
+* Artyom Romanov
+* Augusto Borges
+* Chiraag Balu
+* David Stansby
+* dependabot[bot]
+* Elliott Sales de Andrade
+* Eric Firing
+* Gaurav-Kumar-Soni
+* Greg Lucas
+* Gurudatta Shanbhag
+* hannah
+* Hugues Hoppe
+* Jody Klymak
+* Joshua Stevenson
+* Junpei Ota
+* katotaisei
+* Kyle Sunden
+* Lucia Korpas
+* Matthew Morrison
+* Oscar Gustafsson
+* Ruth Comer
+* Thomas A Caswell
+* Tim Hoffmann
+* wemi3
+
+GitHub issues and pull requests:
+
+Pull Requests (95):
+
+* :ghpull:`27239`: Backport PR #27237 on branch v3.8.x (DOC: Add command to install appropriate ``requirements.txt`` during dev venv setup)
+* :ghpull:`27238`: Backport PR #27165 on branch v3.8.x (Fixing Matplotlib Notebook Text)
+* :ghpull:`27165`: Fixing Matplotlib Notebook Text
+* :ghpull:`27229`: Backport PR #27226 on branch v3.8.x (DOC: link out to troubleshooting guide in install)
+* :ghpull:`27226`: DOC: link out to troubleshooting guide in install
+* :ghpull:`27227`: Backport PR #27221 on branch v3.8.x (FIX: Enable interrupts on macosx event loops)
+* :ghpull:`27221`: FIX: Enable interrupts on macosx event loops
+* :ghpull:`27220`: Backport PR #27217 on branch v3.8.x: Fix type hints for undeprecated contour APIs
+* :ghpull:`27217`: Fix type hints for undeprecated contour APIs
+* :ghpull:`27212`: Backport PR #27088 on branch v3.8.x (Update ``find_nearest_contour`` and revert contour deprecations)
+* :ghpull:`27207`: Backport PR #26970 on branch v3.8.x (FIX: Add PyOS_InputHook back to macos backend)
+* :ghpull:`27088`: Update ``find_nearest_contour`` and revert contour deprecations
+* :ghpull:`27206`: Backport PR #27205 on branch v3.8.x (Improve legend picking example)
+* :ghpull:`26970`: FIX: Add PyOS_InputHook back to macos backend
+* :ghpull:`27205`: Improve legend picking example
+* :ghpull:`27202`: Backport PR #27178 on branch v3.8.x (Try/except import of Axes3D)
+* :ghpull:`27178`: Try/except import of Axes3D
+* :ghpull:`27201`: Backport PR #27179 on branch v3.8.x (Restore default behavior of hexbin mincnt with C provided)
+* :ghpull:`27197`: Backport PR #27045 on branch v3.8.x (Ensure valid path mangling for ContourLabeler)
+* :ghpull:`27179`: Restore default behavior of hexbin mincnt with C provided
+* :ghpull:`27045`: Ensure valid path mangling for ContourLabeler
+* :ghpull:`27191`: Backport PR #27189 on branch v3.8.x (Fix typo in docstring of ``matplotlib.colors.from_levels_and_colors``)
+* :ghpull:`27189`: Fix typo in docstring of ``matplotlib.colors.from_levels_and_colors``
+* :ghpull:`27154`: Backport PR #27153 on branch v3.8.x (Link xkcd color survey in named colors example)
+* :ghpull:`27133`: Backport PR #27132 on branch v3.8.x (changed automated tests from subsection to section in workflow)
+* :ghpull:`27131`: Backport PR #27118 on branch v3.8.x (Update developer release guide to follow conventions)
+* :ghpull:`27118`: Update developer release guide to follow conventions
+* :ghpull:`27122`: Backport PR #26930 on branch v3.8.x (Added documentation on getting full list of registered colormaps re: issue #26244)
+* :ghpull:`26930`: Added documentation on getting full list of registered colormaps re: issue #26244
+* :ghpull:`27113`: Backport PR #27039 on branch v3.8.x (Formatted docs)
+* :ghpull:`27039`: Formatted release note docs
+* :ghpull:`27101`: Backport PR #27096 on branch v3.8.x (make fonts.py, mathtext.py, text_intro.py confirm to docs guidelines)
+* :ghpull:`27097`: Backport PR #27093 on branch v3.8.x ([Doc]: Move Automated Tests section to workflow docs #26998)
+* :ghpull:`27065`: Backport PR #26943 on branch v3.8.x (ci: Run mypy against typed cycler)
+* :ghpull:`26943`: ci: Run mypy against typed cycler
+* :ghpull:`27060`: Backport PR #27059: ci: Clean up Python 3.12 builds
+* :ghpull:`27057`: Backport PR #27040 on branch v3.8.x (Bump pypa/cibuildwheel from 2.16.1 to 2.16.2)
+* :ghpull:`27059`: ci: Clean up Python 3.12 builds
+* :ghpull:`27055`: Backport PR #27054 on branch v3.8.x (updated interactive.rst)
+* :ghpull:`27052`: Backport PR #27036 on branch v3.8.x (updated artist_intro.rst)
+* :ghpull:`27051`: Backport PR #26995 on branch v3.8.x (user/project/citing updated)
+* :ghpull:`27046`: Backport PR #27043 on branch v3.8.x (updated api_interfaces.rst)
+* :ghpull:`27040`: Bump pypa/cibuildwheel from 2.16.1 to 2.16.2
+* :ghpull:`27041`: Backport PR #26908 on branch v3.8.x (``allsegs`` and ``allkinds`` return individual segments)
+* :ghpull:`26908`: ``allsegs`` and ``allkinds`` return individual segments
+* :ghpull:`27034`: Backport PR #27017 on branch v3.8.x (DOC: clarify usetex versus mathtext)
+* :ghpull:`27017`: DOC: clarify usetex versus mathtext
+* :ghpull:`27031`: Backport PR #27015 on branch v3.8.x (ValueError exception added to handle mix of {} and % string in colorbar format)
+* :ghpull:`27015`: ValueError exception added to handle mix of {} and % string in colorbar format
+* :ghpull:`27022`: BLD: Remove development dependencies from sdists
+* :ghpull:`27023`: Backport PR #26883 on branch v3.8.x ([TYP] Type changes from running against Pandas)
+* :ghpull:`26883`: [TYP] Type changes from running against Pandas
+* :ghpull:`27018`: Backport PR #26961 on branch v3.8.x (DOC: made "open PR on MPL" a section in contribute guide)
+* :ghpull:`27009`: Backport PR #27006 on branch v3.8.x (DOC: Fix resizing of animation examples)
+* :ghpull:`26999`: Backport PR #26940 on branch v3.8.x (Add typing to pyplot.show() to avoid errors with mypy --strict.)
+* :ghpull:`27000`: Backport PR #26605 on branch v3.8.x (ci: Install GTK4 from brew on macOS)
+* :ghpull:`26982`: Backport PR #26976 on branch v3.8.x (Bump pypa/cibuildwheel from 2.16.0 to 2.16.1)
+* :ghpull:`26940`: Add typing to pyplot.show() to avoid errors with mypy --strict.
+* :ghpull:`26997`: Backport PR #26850 on branch v3.8.x (DOC: Fix missing-reference generation on Windows)
+* :ghpull:`26860`: Backport PR #26849 on branch v3.8.x (Bump setuptools required version because of setuptools_scm v8)
+* :ghpull:`26850`: DOC: Fix missing-reference generation on Windows
+* :ghpull:`26987`: Backport PR #26985 on branch v3.8.x (Reformatted documentation under toolkits and tutorials directory )
+* :ghpull:`26979`: Backport PR #26959 on branch v3.8.x (Move papersize="auto" deprecation to backend_bases.)
+* :ghpull:`26976`: Bump pypa/cibuildwheel from 2.16.0 to 2.16.1
+* :ghpull:`26959`: Move papersize="auto" deprecation to backend_bases.
+* :ghpull:`26939`: Backport PR #26937 on branch v3.8.x (Add ArrayLike to scatter c arg type hint)
+* :ghpull:`26964`: Backport PR #26952 on branch v3.8.x (FIX 2-tuple of colors in to_rgba_array)
+* :ghpull:`26956`: Backport PR #26955 on branch v3.8.x (Fix incorrect skip check in test_backend_ps.)
+* :ghpull:`26952`: FIX 2-tuple of colors in to_rgba_array
+* :ghpull:`26955`: Fix incorrect skip check in test_backend_ps.
+* :ghpull:`26945`: Backport PR #26927 on branch v3.8.x ([TYP] Remove some stubtest allowlist entries)
+* :ghpull:`26927`: [TYP] Remove some stubtest allowlist entries
+* :ghpull:`26937`: Add ArrayLike to scatter c arg type hint
+* :ghpull:`26933`: Backport PR #26914 on branch v3.8.x (DOC: add a couple more placement examples, crosslink axes_grid [ci doc])
+* :ghpull:`26849`: Bump setuptools required version because of setuptools_scm v8
+* :ghpull:`26844`: Backport PR #26843 on branch v3.8.x (DOC: Use ax.xaxis rather ax.get_xaxis())
+* :ghpull:`26836`: Backport PR #26834 on branch v3.8.x (Fix Issue 26821: [Bug]: ValueError: The truth value... when an ndarray is passed to the color kwarg of axes3d.scatter)
+* :ghpull:`26834`: Fix Issue 26821: [Bug]: ValueError: The truth value... when an ndarray is passed to the color kwarg of axes3d.scatter
+* :ghpull:`26835`: Backport PR #26814 on branch v3.8.x (Bump pypa/cibuildwheel from 2.15.0 to 2.16.0)
+* :ghpull:`26828`: Backport PR #26825 on branch v3.8.x (Fix issue with non-string labels and legend)
+* :ghpull:`26825`: Fix issue with non-string labels and legend
+* :ghpull:`26814`: Bump pypa/cibuildwheel from 2.15.0 to 2.16.0
+* :ghpull:`26816`: Backport PR #26799 on branch v3.8.x (Update kiwisolver and pillow versions to be consistent with requirements)
+* :ghpull:`26820`: Backport PR #26811 on branch v3.8.x (Add overload for slice to Spines.__getitem__)
+* :ghpull:`26811`: Add overload for slice to Spines.__getitem__
+* :ghpull:`26799`: Update kiwisolver and pillow versions to be consistent with requirements
+* :ghpull:`26809`: Backport PR #26804 on branch v3.8.x (Fix issue with locale comma when not using math text)
+* :ghpull:`26789`: Backport changes to contribute from PR #26737
+* :ghpull:`26810`: Backport PR #26807 on branch v3.8.x (Catch ValueError to support pytorch (and others) plotting)
+* :ghpull:`26807`: Catch ValueError to support pytorch (and others) plotting
+* :ghpull:`26804`: Fix issue with locale comma when not using math text
+* :ghpull:`26781`: Backport PR #26780 on branch v3.8.x (fix Axes.errorbar docstring)
+* :ghpull:`26780`: fix Axes.errorbar docstring
+* :ghpull:`26699`: Improve naming of cibuildwheel jobs
+* :ghpull:`26605`: ci: Install GTK4 from brew on macOS
+
+Issues (24):
+
+* :ghissue:`27120`: [Bug]: macosx backend pause() cannot be ctrl-c'd
+* :ghissue:`27070`: [Bug]: find_nearest_contour deprecated with no replacement?
+* :ghissue:`26913`: Should ``ContourSet.allsegs`` and ``.allkinds`` be deprecated?
+* :ghissue:`26869`: [Bug]: Plot window not shown in Mac OS with backend set to default MacOSX
+* :ghissue:`16865`: Hexbin mincnt parameter docstring should say "more than or equal to" not "more than"
+* :ghissue:`27103`: [Bug]: hexbin cannot always accept np.max like functions as reduce_C_function
+* :ghissue:`27062`: [Bug]: ContourLabeler.clabel with manual != False breaks unconnected contours
+* :ghissue:`26971`: [Bug]: plt.clabel raises exception at very low DPI: ``ValueError: 'codes' must be a 1D list or array with the same length of 'vertices'. Your vertices have shape (2, 2) but your codes have shape (1,)``
+* :ghissue:`27188`: Small error in docstring of matplotlib.colors.from_levels_and_colors
+* :ghissue:`27126`: [Bug]: LinearSegmentedColormap.from_list cannot process list with two colors
+* :ghissue:`26244`: [Doc]: document how to get list of registered colormaps
+* :ghissue:`26863`: [Doc]: ``ContourSet`` ``allsegs`` and ``allkinds`` after #25247
+* :ghissue:`26932`: [Bug]: Poetry installs setuptools-scm and setuptools
+* :ghissue:`27007`: [Bug]: Colorbar format string kind guess could be made more robust
+* :ghissue:`26919`: [Bug]: Missing file pyplot.pyi for mypy typing
+* :ghissue:`26949`: [Bug]: colors.LinearSegmentedColormap.from_list does not take two tuples in 3.8.0
+* :ghissue:`26936`: [Bug/TYPE]: Scatter ``c`` Typehint does not support list of numbers when using ``cmap``
+* :ghissue:`26846`: [MNT]: setuptools-scm v8.0.1 compatibility
+* :ghissue:`26821`: [Bug]: ``ValueError: The truth value...`` when an ndarray is passed to the ``color`` kwarg of ``axes3d.scatter``
+* :ghissue:`26822`: [Bug]: QuadMesh.get_array change breaks seaborn heatmap annotation
+* :ghissue:`26824`: [Bug]: Legend fails for bar plot with numeric label
+* :ghissue:`26808`: [Bug]: No overload variant of "__getitem__" of "Spines" matches argument type "slice" [call-overload]
+* :ghissue:`26806`: [Bug]: ValueError when plotting 2D pytorch tensor using matplotlib==3.8.0
+* :ghissue:`26803`: [Bug]: use_locale leads to curly brackets around decimal separator
diff --git a/doc/users/release_notes.rst b/doc/users/release_notes.rst
index ca09d218cae4..bb0ee1e67a7e 100644
--- a/doc/users/release_notes.rst
+++ b/doc/users/release_notes.rst
@@ -22,6 +22,7 @@ Version 3.8
../api/prev_api_changes/api_changes_3.8.1.rst
../api/prev_api_changes/api_changes_3.8.0.rst
github_stats.rst
+ prev_whats_new/github_stats_3.8.1.rst
prev_whats_new/github_stats_3.8.0.rst
Version 3.7
From eb02b108ea181930ab37717c75e07ba792e01f1d Mon Sep 17 00:00:00 2001
From: Kyle Sunden
Date: Fri, 17 Nov 2023 13:49:43 -0600
Subject: [PATCH 20/87] REL: v3.8.2
This is the second bugfix release of the 3.8 series.
Highlights of this release include:
- Fix a segfault in the MacOS backend when running on Python 3.12
- Fix Contour labeling manual positions selecting incorrect contours.
- Various documentation improvements
From 9621965f309610d148b0a8a26a53a7f8b6804acf Mon Sep 17 00:00:00 2001
From: Kyle Sunden
Date: Fri, 17 Nov 2023 13:54:17 -0600
Subject: [PATCH 21/87] REL: Bump post v3.8.2 tag
From d98fee6e0edee5bee74f0665472bd0c1cdfe60b6 Mon Sep 17 00:00:00 2001
From: Kyle Sunden
Date: Fri, 17 Nov 2023 14:54:02 -0600
Subject: [PATCH 22/87] Update zenodo for 3.8.2
---
doc/_static/zenodo_cache/10150955.svg | 35 +++++++++++++++++++++++++++
doc/users/project/citing.rst | 3 +++
tools/cache_zenodo_svg.py | 1 +
3 files changed, 39 insertions(+)
create mode 100644 doc/_static/zenodo_cache/10150955.svg
diff --git a/doc/_static/zenodo_cache/10150955.svg b/doc/_static/zenodo_cache/10150955.svg
new file mode 100644
index 000000000000..132bc97ab61d
--- /dev/null
+++ b/doc/_static/zenodo_cache/10150955.svg
@@ -0,0 +1,35 @@
+
\ No newline at end of file
diff --git a/doc/users/project/citing.rst b/doc/users/project/citing.rst
index d6b924afec2f..68a57650ea9c 100644
--- a/doc/users/project/citing.rst
+++ b/doc/users/project/citing.rst
@@ -29,6 +29,9 @@ By version
.. START OF AUTOGENERATED
+v3.8.2
+ .. image:: ../../_static/zenodo_cache/10150955.svg
+ :target: https://doi.org/10.5281/zenodo.10150955
v3.8.1
.. image:: ../../_static/zenodo_cache/10059757.svg
:target: https://doi.org/10.5281/zenodo.10059757
diff --git a/tools/cache_zenodo_svg.py b/tools/cache_zenodo_svg.py
index cbd1304bd14c..5ac425b3efd9 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.8.2": "10150955",
"v3.8.1": "10059757",
"v3.8.0": "8347255",
"v3.7.3": "8336761",
From 58b353dc5b8f0970ace6d5172cc1ad99a5acd201 Mon Sep 17 00:00:00 2001
From: hannah
Date: Mon, 20 Nov 2023 11:05:39 -0500
Subject: [PATCH 23/87] Backport PR #27348: updated api/animation documentation
as per standards
---
doc/api/animation_api.rst | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/doc/api/animation_api.rst b/doc/api/animation_api.rst
index c7134e302d2f..df39b5942199 100644
--- a/doc/api/animation_api.rst
+++ b/doc/api/animation_api.rst
@@ -166,7 +166,7 @@ A third method is to use closures to build up the required
artists and functions. A fourth method is to create a class.
Examples
-~~~~~~~~
+^^^^^^^^
* :doc:`../gallery/animation/animate_decay`
* :doc:`../gallery/animation/bayes_update`
@@ -182,7 +182,7 @@ Examples
-------------------
Examples
-~~~~~~~~
+^^^^^^^^
* :doc:`../gallery/animation/dynamic_image`
From 372948e69685c642d802f2e3a98753a790b39923 Mon Sep 17 00:00:00 2001
From: hannah
Date: Mon, 20 Nov 2023 11:05:39 -0500
Subject: [PATCH 24/87] Backport PR #27348: updated api/animation documentation
as per standards
---
doc/api/animation_api.rst | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/doc/api/animation_api.rst b/doc/api/animation_api.rst
index c7134e302d2f..df39b5942199 100644
--- a/doc/api/animation_api.rst
+++ b/doc/api/animation_api.rst
@@ -166,7 +166,7 @@ A third method is to use closures to build up the required
artists and functions. A fourth method is to create a class.
Examples
-~~~~~~~~
+^^^^^^^^
* :doc:`../gallery/animation/animate_decay`
* :doc:`../gallery/animation/bayes_update`
@@ -182,7 +182,7 @@ Examples
-------------------
Examples
-~~~~~~~~
+^^^^^^^^
* :doc:`../gallery/animation/dynamic_image`
From 9501407646aa0e76ba42361b58b3585b451b849d Mon Sep 17 00:00:00 2001
From: Elliott Sales de Andrade
Date: Fri, 24 Nov 2023 00:45:33 -0500
Subject: [PATCH 25/87] Backport PR #27365: [DOC]: Fix menu example
---
galleries/examples/widgets/menu.py | 25 +++++++++++++------------
1 file changed, 13 insertions(+), 12 deletions(-)
diff --git a/galleries/examples/widgets/menu.py b/galleries/examples/widgets/menu.py
index b8f5268a6477..8d3db3d1b9c3 100644
--- a/galleries/examples/widgets/menu.py
+++ b/galleries/examples/widgets/menu.py
@@ -3,13 +3,12 @@
Menu
====
+Using texts to construct a simple menu.
"""
-
import matplotlib.pyplot as plt
import matplotlib.artist as artist
import matplotlib.patches as patches
-from matplotlib.transforms import IdentityTransform
class ItemProperties:
@@ -22,8 +21,8 @@ def __init__(self, fontsize=14, labelcolor='black', bgcolor='yellow',
class MenuItem(artist.Artist):
- padx = 5
- pady = 5
+ padx = 0.05 # inches
+ pady = 0.05
def __init__(self, fig, labelstr, props=None, hoverprops=None,
on_select=None):
@@ -41,14 +40,16 @@ def __init__(self, fig, labelstr, props=None, hoverprops=None,
self.on_select = on_select
- # Setting the transform to IdentityTransform() lets us specify
- # coordinates directly in pixels.
- self.label = fig.text(0, 0, labelstr, transform=IdentityTransform(),
+ # specify coordinates in inches.
+ self.label = fig.text(0, 0, labelstr, transform=fig.dpi_scale_trans,
size=props.fontsize)
self.text_bbox = self.label.get_window_extent(
fig.canvas.get_renderer())
+ self.text_bbox = fig.dpi_scale_trans.inverted().transform_bbox(self.text_bbox)
- self.rect = patches.Rectangle((0, 0), 1, 1) # Will be updated later.
+ self.rect = patches.Rectangle(
+ (0, 0), 1, 1, transform=fig.dpi_scale_trans
+ ) # Will be updated later.
self.set_hover_props(False)
@@ -63,7 +64,7 @@ def check_select(self, event):
def set_extent(self, x, y, w, h, depth):
self.rect.set(x=x, y=y, width=w, height=h)
- self.label.set(position=(x + self.padx, y + depth + self.pady/2))
+ self.label.set(position=(x + self.padx, y + depth + self.pady / 2))
self.hover = False
def draw(self, renderer):
@@ -97,10 +98,10 @@ def __init__(self, fig, menuitems):
maxh = max(item.text_bbox.height for item in menuitems)
depth = max(-item.text_bbox.y0 for item in menuitems)
- x0 = 100
- y0 = 400
+ x0 = 1
+ y0 = 4
- width = maxw + 2*MenuItem.padx
+ width = maxw + 2 * MenuItem.padx
height = maxh + MenuItem.pady
for item in menuitems:
From 696ac947f2c888e4af82583ebaed1f754853462b Mon Sep 17 00:00:00 2001
From: Samuel Diebolt
Date: Mon, 27 Nov 2023 17:22:21 +0100
Subject: [PATCH 26/87] Backport PR #27376: [MNT] fix type annotations of
`fignum_exists`
---
lib/matplotlib/pyplot.py | 21 ++++++++++++++++++---
1 file changed, 18 insertions(+), 3 deletions(-)
diff --git a/lib/matplotlib/pyplot.py b/lib/matplotlib/pyplot.py
index 62f7eba74eea..42c177490cbb 100644
--- a/lib/matplotlib/pyplot.py
+++ b/lib/matplotlib/pyplot.py
@@ -1000,9 +1000,24 @@ def gcf() -> Figure:
return figure()
-def fignum_exists(num: int) -> bool:
- """Return whether the figure with the given id exists."""
- return _pylab_helpers.Gcf.has_fignum(num) or num in get_figlabels()
+def fignum_exists(num: int | str) -> bool:
+ """Return whether the figure with the given id exists.
+
+ Parameters
+ ----------
+ num : int or str
+ A figure identifier.
+
+ Returns
+ -------
+ bool
+ Whether or not a figure with id *num* exists.
+ """
+ return (
+ _pylab_helpers.Gcf.has_fignum(num)
+ if isinstance(num, int)
+ else num in get_figlabels()
+ )
def get_fignums() -> list[int]:
From c302598057775c75c9139cefbab886b630fecfb9 Mon Sep 17 00:00:00 2001
From: hannah
Date: Mon, 27 Nov 2023 19:46:42 -0500
Subject: [PATCH 27/87] Backport PR #27377: TST: Make
test_movie_writer_invalid_path locale-agnostic
---
lib/matplotlib/tests/test_animation.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/lib/matplotlib/tests/test_animation.py b/lib/matplotlib/tests/test_animation.py
index a4de96d77b62..d026dae59533 100644
--- a/lib/matplotlib/tests/test_animation.py
+++ b/lib/matplotlib/tests/test_animation.py
@@ -545,9 +545,9 @@ def test_disable_cache_warning(anim):
def test_movie_writer_invalid_path(anim):
if sys.platform == "win32":
- match_str = re.escape("[WinError 3] The system cannot find the path specified:")
+ match_str = r"\[WinError 3] .*'\\\\foo\\\\bar\\\\aardvark'"
else:
- match_str = re.escape("[Errno 2] No such file or directory: '/foo")
+ match_str = r"\[Errno 2] .*'/foo"
with pytest.raises(FileNotFoundError, match=match_str):
anim.save("/foo/bar/aardvark/thiscannotreallyexist.mp4",
writer=animation.FFMpegFileWriter())
From 2783fd47c0a334f67855f74de7e5f8edfb145a00 Mon Sep 17 00:00:00 2001
From: Elliott Sales de Andrade
Date: Thu, 30 Nov 2023 05:48:02 -0500
Subject: [PATCH 28/87] Backport PR #27386: Doc: add a "please use dev version"
to top of contribute docs
---
doc/devel/index.rst | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/doc/devel/index.rst b/doc/devel/index.rst
index 9537859c107a..47ea39d29c4b 100644
--- a/doc/devel/index.rst
+++ b/doc/devel/index.rst
@@ -4,6 +4,15 @@
Contribute
##########
+.. ifconfig:: releaselevel != 'dev'
+
+ .. important::
+
+ If you plan to contribute to Matplotlib, please read the
+ `development version `_
+ of this document as it will have the most up to date installation
+ instructions, workflow process, and contributing guidelines.
+
Thank you for your interest in helping to improve Matplotlib! There are various
ways to contribute: optimizing and refactoring code, detailing unclear
documentation and writing new examples, reporting and fixing bugs and requesting
From 96b50413a3b04d2169469d4e488b0866341578b4 Mon Sep 17 00:00:00 2001
From: Elliott Sales de Andrade
Date: Thu, 30 Nov 2023 05:48:02 -0500
Subject: [PATCH 29/87] Backport PR #27386: Doc: add a "please use dev version"
to top of contribute docs
---
doc/devel/index.rst | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/doc/devel/index.rst b/doc/devel/index.rst
index 9537859c107a..47ea39d29c4b 100644
--- a/doc/devel/index.rst
+++ b/doc/devel/index.rst
@@ -4,6 +4,15 @@
Contribute
##########
+.. ifconfig:: releaselevel != 'dev'
+
+ .. important::
+
+ If you plan to contribute to Matplotlib, please read the
+ `development version `_
+ of this document as it will have the most up to date installation
+ instructions, workflow process, and contributing guidelines.
+
Thank you for your interest in helping to improve Matplotlib! There are various
ways to contribute: optimizing and refactoring code, detailing unclear
documentation and writing new examples, reporting and fixing bugs and requesting
From 85f221c6d062e4bbfc370a6cf96149f379907fa8 Mon Sep 17 00:00:00 2001
From: Elliott Sales de Andrade
Date: Fri, 1 Dec 2023 01:53:47 -0500
Subject: [PATCH 30/87] Backport PR #27412: ci: Block PyQt6 6.6.0 on Ubuntu
---
.github/workflows/tests.yml | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 0a81e7212a00..4f0a1c0196de 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -62,23 +62,30 @@ jobs:
extra-requirements: '-r requirements/testing/extra.txt'
CFLAGS: "-fno-lto" # Ensure that disabling LTO works.
# https://github.com/matplotlib/matplotlib/pull/26052#issuecomment-1574595954
- pyqt6-ver: '!=6.5.1'
+ # https://www.riverbankcomputing.com/pipermail/pyqt/2023-November/045606.html
+ pyqt6-ver: '!=6.5.1,!=6.6.0'
# https://bugreports.qt.io/projects/PYSIDE/issues/PYSIDE-2346
pyside6-ver: '!=6.5.1'
- os: ubuntu-20.04
python-version: '3.10'
extra-requirements: '-r requirements/testing/extra.txt'
# https://github.com/matplotlib/matplotlib/pull/26052#issuecomment-1574595954
- pyqt6-ver: '!=6.5.1'
+ # https://www.riverbankcomputing.com/pipermail/pyqt/2023-November/045606.html
+ pyqt6-ver: '!=6.5.1,!=6.6.0'
# https://bugreports.qt.io/projects/PYSIDE/issues/PYSIDE-2346
pyside6-ver: '!=6.5.1'
- os: ubuntu-22.04
python-version: '3.11'
+ # https://www.riverbankcomputing.com/pipermail/pyqt/2023-November/045606.html
+ pyqt6-ver: '!=6.6.0'
# https://bugreports.qt.io/projects/PYSIDE/issues/PYSIDE-2346
pyside6-ver: '!=6.5.1'
extra-requirements: '-r requirements/testing/extra.txt'
- os: ubuntu-22.04
python-version: '3.12'
+ # https://www.riverbankcomputing.com/pipermail/pyqt/2023-November/045606.html
+ pyqt6-ver: '!=6.6.0'
+ # https://bugreports.qt.io/projects/PYSIDE/issues/PYSIDE-2346
pyside6-ver: '!=6.5.1'
- os: macos-latest
python-version: 3.9
From 08cc8cb26db1886507e639e4a1afb9fa275ec9f8 Mon Sep 17 00:00:00 2001
From: Matthew Morrison <120498834+mattymo30@users.noreply.github.com>
Date: Fri, 1 Dec 2023 23:55:54 -0500
Subject: [PATCH 31/87] Backport PR #27325: Fixing Sentence Case on Section
Titles in users_explain
---
galleries/users_explain/animations/animations.py | 4 ++--
galleries/users_explain/artists/patheffects_guide.py | 4 ++--
galleries/users_explain/axes/autoscale.py | 4 ++--
galleries/users_explain/axes/axes_ticks.py | 2 +-
galleries/users_explain/axes/colorbar_placement.py | 2 +-
galleries/users_explain/axes/constrainedlayout_guide.py | 2 +-
galleries/users_explain/axes/legend_guide.py | 2 +-
galleries/users_explain/axes/tight_layout_guide.py | 5 +++--
galleries/users_explain/colors/colorbar_only.py | 6 +++---
galleries/users_explain/colors/colormap-manipulation.py | 6 +++---
galleries/users_explain/colors/colormapnorms.py | 2 +-
galleries/users_explain/colors/colormaps.py | 6 +++---
galleries/users_explain/toolkits/axes_grid.rst | 2 +-
galleries/users_explain/toolkits/axisartist.rst | 6 +++---
14 files changed, 27 insertions(+), 26 deletions(-)
diff --git a/galleries/users_explain/animations/animations.py b/galleries/users_explain/animations/animations.py
index b022350c8985..fb8564f8318e 100644
--- a/galleries/users_explain/animations/animations.py
+++ b/galleries/users_explain/animations/animations.py
@@ -20,7 +20,7 @@
import matplotlib.animation as animation
# %%
-# Animation Classes
+# Animation classes
# =================
#
# The animation process in Matplotlib can be thought of in 2 different ways:
@@ -158,7 +158,7 @@ def update(frame):
plt.show()
# %%
-# Animation Writers
+# Animation writers
# =================
#
# Animation objects can be saved to disk using various multimedia writers
diff --git a/galleries/users_explain/artists/patheffects_guide.py b/galleries/users_explain/artists/patheffects_guide.py
index 259261fb09d4..28a6b9dd1d03 100644
--- a/galleries/users_explain/artists/patheffects_guide.py
+++ b/galleries/users_explain/artists/patheffects_guide.py
@@ -64,7 +64,7 @@
# automatically followed with the "normal" effect, whereas the latter
# explicitly defines the two path effects to draw.
#
-# Making an artist stand out
+# Making an Artist stand out
# --------------------------
#
# One nice way of making artists visually stand out is to draw an outline in
@@ -93,7 +93,7 @@
# its user interface.
#
#
-# Greater control of the path effect artist
+# Greater control of the path effect Artist
# -----------------------------------------
#
# As already mentioned, some of the path effects operate at a lower level
diff --git a/galleries/users_explain/axes/autoscale.py b/galleries/users_explain/axes/autoscale.py
index a9d6b728866c..53435f4086c9 100644
--- a/galleries/users_explain/axes/autoscale.py
+++ b/galleries/users_explain/axes/autoscale.py
@@ -3,8 +3,8 @@
.. _autoscale:
-Autoscaling
-===========
+Autoscaling Axis
+================
The limits on an axis can be set manually (e.g. ``ax.set_xlim(xmin, xmax)``)
or Matplotlib can set them automatically based on the data already on the axes.
diff --git a/galleries/users_explain/axes/axes_ticks.py b/galleries/users_explain/axes/axes_ticks.py
index aaec87c6a239..3870c26af70e 100644
--- a/galleries/users_explain/axes/axes_ticks.py
+++ b/galleries/users_explain/axes/axes_ticks.py
@@ -2,7 +2,7 @@
.. _user_axes_ticks:
==========
-Axis Ticks
+Axis ticks
==========
The x and y Axis on each Axes have default tick "locators" and "formatters"
diff --git a/galleries/users_explain/axes/colorbar_placement.py b/galleries/users_explain/axes/colorbar_placement.py
index 1e43d4940a98..8dbc2a356cb1 100644
--- a/galleries/users_explain/axes/colorbar_placement.py
+++ b/galleries/users_explain/axes/colorbar_placement.py
@@ -4,7 +4,7 @@
.. redirect-from:: /gallery/subplots_axes_and_figures/colorbar_placement
=================
-Placing Colorbars
+Placing colorbars
=================
Colorbars indicate the quantitative extent of image data. Placing in
diff --git a/galleries/users_explain/axes/constrainedlayout_guide.py b/galleries/users_explain/axes/constrainedlayout_guide.py
index 4581f5f67808..d96b829df372 100644
--- a/galleries/users_explain/axes/constrainedlayout_guide.py
+++ b/galleries/users_explain/axes/constrainedlayout_guide.py
@@ -5,7 +5,7 @@
.. _constrainedlayout_guide:
========================
-Constrained Layout Guide
+Constrained layout guide
========================
Use *constrained layout* to fit plots within your figure cleanly.
diff --git a/galleries/users_explain/axes/legend_guide.py b/galleries/users_explain/axes/legend_guide.py
index 3b138fe8ada3..1482cdbc4a81 100644
--- a/galleries/users_explain/axes/legend_guide.py
+++ b/galleries/users_explain/axes/legend_guide.py
@@ -213,7 +213,7 @@
plt.show()
# %%
-# Legend Handlers
+# Legend handlers
# ===============
#
# In order to create legend entries, handles are given as an argument to an
diff --git a/galleries/users_explain/axes/tight_layout_guide.py b/galleries/users_explain/axes/tight_layout_guide.py
index 8525b9773f91..9074641d39ab 100644
--- a/galleries/users_explain/axes/tight_layout_guide.py
+++ b/galleries/users_explain/axes/tight_layout_guide.py
@@ -4,7 +4,7 @@
.. _tight_layout_guide:
==================
-Tight Layout guide
+Tight layout guide
==================
How to use tight-layout to fit plots within your figure cleanly.
@@ -17,6 +17,7 @@
An alternative to *tight_layout* is :ref:`constrained_layout
`.
+
Simple example
==============
@@ -209,7 +210,7 @@ def example_plot(ax, fontsize=12):
# %%
-# Legends and Annotations
+# Legends and annotations
# =======================
#
# Pre Matplotlib 2.2, legends and annotations were excluded from the bounding
diff --git a/galleries/users_explain/colors/colorbar_only.py b/galleries/users_explain/colors/colorbar_only.py
index a47ced0a4ea6..4140ea454b99 100644
--- a/galleries/users_explain/colors/colorbar_only.py
+++ b/galleries/users_explain/colors/colorbar_only.py
@@ -1,9 +1,9 @@
"""
.. redirect-from:: /tutorials/colors/colorbar_only
-====================
-Standalone colorbars
-====================
+=============================
+Customized Colorbars Tutorial
+=============================
This tutorial shows how to build and customize standalone colorbars, i.e.
without an attached plot.
diff --git a/galleries/users_explain/colors/colormap-manipulation.py b/galleries/users_explain/colors/colormap-manipulation.py
index 87269b87befa..0cd488857257 100644
--- a/galleries/users_explain/colors/colormap-manipulation.py
+++ b/galleries/users_explain/colors/colormap-manipulation.py
@@ -3,9 +3,9 @@
.. _colormap-manipulation:
-******************
-Creating Colormaps
-******************
+********************************
+Creating Colormaps in Matplotlib
+********************************
Matplotlib has a number of built-in colormaps accessible via
`.matplotlib.colormaps`. There are also external libraries like
diff --git a/galleries/users_explain/colors/colormapnorms.py b/galleries/users_explain/colors/colormapnorms.py
index f375b3af805b..3aa0ab729371 100644
--- a/galleries/users_explain/colors/colormapnorms.py
+++ b/galleries/users_explain/colors/colormapnorms.py
@@ -4,7 +4,7 @@
.. _colormapnorms:
-Colormap Normalization
+Colormap normalization
======================
Objects that use colormaps by default linearly map the colors in the
diff --git a/galleries/users_explain/colors/colormaps.py b/galleries/users_explain/colors/colormaps.py
index b5db551cb5b5..92b56d298976 100644
--- a/galleries/users_explain/colors/colormaps.py
+++ b/galleries/users_explain/colors/colormaps.py
@@ -3,9 +3,9 @@
.. _colormaps:
-******************
-Choosing Colormaps
-******************
+********************************
+Choosing Colormaps in Matplotlib
+********************************
Matplotlib has a number of built-in colormaps accessible via
`.matplotlib.colormaps`. There are also external libraries that
diff --git a/galleries/users_explain/toolkits/axes_grid.rst b/galleries/users_explain/toolkits/axes_grid.rst
index ba37c4cf7d78..7ef8b1e582b6 100644
--- a/galleries/users_explain/toolkits/axes_grid.rst
+++ b/galleries/users_explain/toolkits/axes_grid.rst
@@ -60,7 +60,7 @@ The examples below show what you can do with ImageGrid.
:target: /gallery/axes_grid1/demo_axes_grid.html
:align: center
-AxesDivider Class
+AxesDivider class
-----------------
Behind the scenes, ImageGrid (and RGBAxes, described below) rely on
diff --git a/galleries/users_explain/toolkits/axisartist.rst b/galleries/users_explain/toolkits/axisartist.rst
index 9246fb27271b..ed1161fb92a7 100644
--- a/galleries/users_explain/toolkits/axisartist.rst
+++ b/galleries/users_explain/toolkits/axisartist.rst
@@ -99,7 +99,7 @@ Here is an example that uses ParasiteAxes.
:target: /gallery/axisartist/demo_parasite_axes2.html
:align: center
-Curvilinear Grid
+Curvilinear grid
----------------
The motivation behind the AxisArtist module is to support a curvilinear grid
@@ -298,7 +298,7 @@ HowTo
To change the pad between ticklabels and axis label,
axis.label.set_pad method.
-Rotation and Alignment of TickLabels
+Rotation and alignment of TickLabels
====================================
This is also quite different from standard Matplotlib and can be
@@ -547,7 +547,7 @@ way is to add it as an item of Axes's axis attribute.::
See the first example of this page.
-Current Limitations and TODO's
+Current limitations and TODO's
==============================
The code need more refinement. Here is a incomplete list of issues and TODO's
From f0d7435eb5f9f14916ebdc82934af3eeb99ab4d2 Mon Sep 17 00:00:00 2001
From: Matthew Morrison <120498834+mattymo30@users.noreply.github.com>
Date: Fri, 1 Dec 2023 23:55:54 -0500
Subject: [PATCH 32/87] Backport PR #27325: Fixing Sentence Case on Section
Titles in users_explain
---
galleries/users_explain/animations/animations.py | 4 ++--
galleries/users_explain/artists/patheffects_guide.py | 4 ++--
galleries/users_explain/axes/autoscale.py | 4 ++--
galleries/users_explain/axes/axes_ticks.py | 2 +-
galleries/users_explain/axes/colorbar_placement.py | 2 +-
galleries/users_explain/axes/constrainedlayout_guide.py | 2 +-
galleries/users_explain/axes/legend_guide.py | 2 +-
galleries/users_explain/axes/tight_layout_guide.py | 5 +++--
galleries/users_explain/colors/colorbar_only.py | 6 +++---
galleries/users_explain/colors/colormap-manipulation.py | 6 +++---
galleries/users_explain/colors/colormapnorms.py | 2 +-
galleries/users_explain/colors/colormaps.py | 6 +++---
galleries/users_explain/toolkits/axes_grid.rst | 2 +-
galleries/users_explain/toolkits/axisartist.rst | 6 +++---
14 files changed, 27 insertions(+), 26 deletions(-)
diff --git a/galleries/users_explain/animations/animations.py b/galleries/users_explain/animations/animations.py
index b022350c8985..fb8564f8318e 100644
--- a/galleries/users_explain/animations/animations.py
+++ b/galleries/users_explain/animations/animations.py
@@ -20,7 +20,7 @@
import matplotlib.animation as animation
# %%
-# Animation Classes
+# Animation classes
# =================
#
# The animation process in Matplotlib can be thought of in 2 different ways:
@@ -158,7 +158,7 @@ def update(frame):
plt.show()
# %%
-# Animation Writers
+# Animation writers
# =================
#
# Animation objects can be saved to disk using various multimedia writers
diff --git a/galleries/users_explain/artists/patheffects_guide.py b/galleries/users_explain/artists/patheffects_guide.py
index 259261fb09d4..28a6b9dd1d03 100644
--- a/galleries/users_explain/artists/patheffects_guide.py
+++ b/galleries/users_explain/artists/patheffects_guide.py
@@ -64,7 +64,7 @@
# automatically followed with the "normal" effect, whereas the latter
# explicitly defines the two path effects to draw.
#
-# Making an artist stand out
+# Making an Artist stand out
# --------------------------
#
# One nice way of making artists visually stand out is to draw an outline in
@@ -93,7 +93,7 @@
# its user interface.
#
#
-# Greater control of the path effect artist
+# Greater control of the path effect Artist
# -----------------------------------------
#
# As already mentioned, some of the path effects operate at a lower level
diff --git a/galleries/users_explain/axes/autoscale.py b/galleries/users_explain/axes/autoscale.py
index a9d6b728866c..53435f4086c9 100644
--- a/galleries/users_explain/axes/autoscale.py
+++ b/galleries/users_explain/axes/autoscale.py
@@ -3,8 +3,8 @@
.. _autoscale:
-Autoscaling
-===========
+Autoscaling Axis
+================
The limits on an axis can be set manually (e.g. ``ax.set_xlim(xmin, xmax)``)
or Matplotlib can set them automatically based on the data already on the axes.
diff --git a/galleries/users_explain/axes/axes_ticks.py b/galleries/users_explain/axes/axes_ticks.py
index aaec87c6a239..3870c26af70e 100644
--- a/galleries/users_explain/axes/axes_ticks.py
+++ b/galleries/users_explain/axes/axes_ticks.py
@@ -2,7 +2,7 @@
.. _user_axes_ticks:
==========
-Axis Ticks
+Axis ticks
==========
The x and y Axis on each Axes have default tick "locators" and "formatters"
diff --git a/galleries/users_explain/axes/colorbar_placement.py b/galleries/users_explain/axes/colorbar_placement.py
index 1e43d4940a98..8dbc2a356cb1 100644
--- a/galleries/users_explain/axes/colorbar_placement.py
+++ b/galleries/users_explain/axes/colorbar_placement.py
@@ -4,7 +4,7 @@
.. redirect-from:: /gallery/subplots_axes_and_figures/colorbar_placement
=================
-Placing Colorbars
+Placing colorbars
=================
Colorbars indicate the quantitative extent of image data. Placing in
diff --git a/galleries/users_explain/axes/constrainedlayout_guide.py b/galleries/users_explain/axes/constrainedlayout_guide.py
index 4581f5f67808..d96b829df372 100644
--- a/galleries/users_explain/axes/constrainedlayout_guide.py
+++ b/galleries/users_explain/axes/constrainedlayout_guide.py
@@ -5,7 +5,7 @@
.. _constrainedlayout_guide:
========================
-Constrained Layout Guide
+Constrained layout guide
========================
Use *constrained layout* to fit plots within your figure cleanly.
diff --git a/galleries/users_explain/axes/legend_guide.py b/galleries/users_explain/axes/legend_guide.py
index 3b138fe8ada3..1482cdbc4a81 100644
--- a/galleries/users_explain/axes/legend_guide.py
+++ b/galleries/users_explain/axes/legend_guide.py
@@ -213,7 +213,7 @@
plt.show()
# %%
-# Legend Handlers
+# Legend handlers
# ===============
#
# In order to create legend entries, handles are given as an argument to an
diff --git a/galleries/users_explain/axes/tight_layout_guide.py b/galleries/users_explain/axes/tight_layout_guide.py
index 8525b9773f91..9074641d39ab 100644
--- a/galleries/users_explain/axes/tight_layout_guide.py
+++ b/galleries/users_explain/axes/tight_layout_guide.py
@@ -4,7 +4,7 @@
.. _tight_layout_guide:
==================
-Tight Layout guide
+Tight layout guide
==================
How to use tight-layout to fit plots within your figure cleanly.
@@ -17,6 +17,7 @@
An alternative to *tight_layout* is :ref:`constrained_layout
`.
+
Simple example
==============
@@ -209,7 +210,7 @@ def example_plot(ax, fontsize=12):
# %%
-# Legends and Annotations
+# Legends and annotations
# =======================
#
# Pre Matplotlib 2.2, legends and annotations were excluded from the bounding
diff --git a/galleries/users_explain/colors/colorbar_only.py b/galleries/users_explain/colors/colorbar_only.py
index a47ced0a4ea6..4140ea454b99 100644
--- a/galleries/users_explain/colors/colorbar_only.py
+++ b/galleries/users_explain/colors/colorbar_only.py
@@ -1,9 +1,9 @@
"""
.. redirect-from:: /tutorials/colors/colorbar_only
-====================
-Standalone colorbars
-====================
+=============================
+Customized Colorbars Tutorial
+=============================
This tutorial shows how to build and customize standalone colorbars, i.e.
without an attached plot.
diff --git a/galleries/users_explain/colors/colormap-manipulation.py b/galleries/users_explain/colors/colormap-manipulation.py
index 87269b87befa..0cd488857257 100644
--- a/galleries/users_explain/colors/colormap-manipulation.py
+++ b/galleries/users_explain/colors/colormap-manipulation.py
@@ -3,9 +3,9 @@
.. _colormap-manipulation:
-******************
-Creating Colormaps
-******************
+********************************
+Creating Colormaps in Matplotlib
+********************************
Matplotlib has a number of built-in colormaps accessible via
`.matplotlib.colormaps`. There are also external libraries like
diff --git a/galleries/users_explain/colors/colormapnorms.py b/galleries/users_explain/colors/colormapnorms.py
index f375b3af805b..3aa0ab729371 100644
--- a/galleries/users_explain/colors/colormapnorms.py
+++ b/galleries/users_explain/colors/colormapnorms.py
@@ -4,7 +4,7 @@
.. _colormapnorms:
-Colormap Normalization
+Colormap normalization
======================
Objects that use colormaps by default linearly map the colors in the
diff --git a/galleries/users_explain/colors/colormaps.py b/galleries/users_explain/colors/colormaps.py
index b5db551cb5b5..92b56d298976 100644
--- a/galleries/users_explain/colors/colormaps.py
+++ b/galleries/users_explain/colors/colormaps.py
@@ -3,9 +3,9 @@
.. _colormaps:
-******************
-Choosing Colormaps
-******************
+********************************
+Choosing Colormaps in Matplotlib
+********************************
Matplotlib has a number of built-in colormaps accessible via
`.matplotlib.colormaps`. There are also external libraries that
diff --git a/galleries/users_explain/toolkits/axes_grid.rst b/galleries/users_explain/toolkits/axes_grid.rst
index ba37c4cf7d78..7ef8b1e582b6 100644
--- a/galleries/users_explain/toolkits/axes_grid.rst
+++ b/galleries/users_explain/toolkits/axes_grid.rst
@@ -60,7 +60,7 @@ The examples below show what you can do with ImageGrid.
:target: /gallery/axes_grid1/demo_axes_grid.html
:align: center
-AxesDivider Class
+AxesDivider class
-----------------
Behind the scenes, ImageGrid (and RGBAxes, described below) rely on
diff --git a/galleries/users_explain/toolkits/axisartist.rst b/galleries/users_explain/toolkits/axisartist.rst
index 9246fb27271b..ed1161fb92a7 100644
--- a/galleries/users_explain/toolkits/axisartist.rst
+++ b/galleries/users_explain/toolkits/axisartist.rst
@@ -99,7 +99,7 @@ Here is an example that uses ParasiteAxes.
:target: /gallery/axisartist/demo_parasite_axes2.html
:align: center
-Curvilinear Grid
+Curvilinear grid
----------------
The motivation behind the AxisArtist module is to support a curvilinear grid
@@ -298,7 +298,7 @@ HowTo
To change the pad between ticklabels and axis label,
axis.label.set_pad method.
-Rotation and Alignment of TickLabels
+Rotation and alignment of TickLabels
====================================
This is also quite different from standard Matplotlib and can be
@@ -547,7 +547,7 @@ way is to add it as an item of Axes's axis attribute.::
See the first example of this page.
-Current Limitations and TODO's
+Current limitations and TODO's
==============================
The code need more refinement. Here is a incomplete list of issues and TODO's
From 9697bbfe680e13423dcd1fba898b5cce6cbaf658 Mon Sep 17 00:00:00 2001
From: Jody Klymak
Date: Sat, 2 Dec 2023 14:36:16 -0800
Subject: [PATCH 33/87] Backport PR #27411: DOC: multilevel tick example
---
galleries/examples/ticks/multilevel_ticks.py | 99 ++++++++++++++++++++
1 file changed, 99 insertions(+)
create mode 100644 galleries/examples/ticks/multilevel_ticks.py
diff --git a/galleries/examples/ticks/multilevel_ticks.py b/galleries/examples/ticks/multilevel_ticks.py
new file mode 100644
index 000000000000..5b8d0ada5ae2
--- /dev/null
+++ b/galleries/examples/ticks/multilevel_ticks.py
@@ -0,0 +1,99 @@
+"""
+=========================
+Multilevel (nested) ticks
+=========================
+
+Sometimes we want another level of tick labels on an axis, perhaps to indicate
+a grouping of the ticks.
+
+Matplotlib does not provide an automated way to do this, but it is relatively
+straightforward to annotate below the main axis.
+
+These examples use `.Axes.secondary_xaxis`, which is one approach. It has the
+advantage that we can use Matplotlib Locators and Formatters on the axis that
+does the grouping if we want.
+
+This first example creates a secondary xaxis and manually adds the ticks and
+labels using `.Axes.set_xticks`. Note that the tick labels have a newline
+(e.g. ``"\nOughts"``) at the beginning of them to put the second-level tick
+labels below the main tick labels.
+"""
+
+import matplotlib.pyplot as plt
+import numpy as np
+
+import matplotlib.dates as mdates
+
+rng = np.random.default_rng(19680801)
+
+fig, ax = plt.subplots(layout='constrained', figsize=(4, 4))
+
+ax.plot(np.arange(30))
+
+sec = ax.secondary_xaxis(location=0)
+sec.set_xticks([5, 15, 25], labels=['\nOughts', '\nTeens', '\nTwenties'])
+
+# %%
+# This second example adds a second level of annotation to a categorical axis.
+# Here we need to note that each animal (category) is assigned an integer, so
+# ``cats`` is at x=0, ``dogs`` at x=1 etc. Then we place the ticks on the
+# second level on an x that is at the middle of the animal class we are trying
+# to delineate.
+#
+# This example also adds tick marks between the classes by adding a second
+# secondary xaxis, and placing long, wide ticks at the boundaries between the
+# animal classes.
+
+fig, ax = plt.subplots(layout='constrained', figsize=(7, 4))
+
+ax.plot(['cats', 'dogs', 'pigs', 'snakes', 'lizards', 'chickens',
+ 'eagles', 'herons', 'buzzards'],
+ rng.normal(size=9), 'o')
+
+# label the classes:
+sec = ax.secondary_xaxis(location=0)
+sec.set_xticks([1, 3.5, 6.5], labels=['\n\nMammals', '\n\nReptiles', '\n\nBirds'])
+sec.tick_params('x', length=0)
+
+# lines between the classes:
+sec2 = ax.secondary_xaxis(location=0)
+sec2.set_xticks([-0.5, 2.5, 4.5, 8.5], labels=[])
+sec2.tick_params('x', length=40, width=1.5)
+ax.set_xlim(-0.6, 8.6)
+
+# %%
+# Dates are another common place where we may want to have a second level of
+# tick labels. In this last example, we take advantage of the ability to add
+# an automatic locator and formatter to the secondary xaxis, which means we do
+# not need to set the ticks manually.
+#
+# This example also differs from the above, in that we placed it at a location
+# below the main axes ``location=-0.075`` and then we hide the spine by setting
+# the line width to zero. That means that our formatter no longer needs the
+# carriage returns of the previous two examples.
+
+fig, ax = plt.subplots(layout='constrained', figsize=(7, 4))
+
+time = np.arange(np.datetime64('2020-01-01'), np.datetime64('2020-03-31'),
+ np.timedelta64(1, 'D'))
+
+ax.plot(time, rng.random(size=len(time)))
+
+# just format the days:
+ax.xaxis.set_major_formatter(mdates.DateFormatter('%d'))
+
+# label the months:
+sec = ax.secondary_xaxis(location=-0.075)
+sec.xaxis.set_major_locator(mdates.MonthLocator(bymonthday=1))
+
+# note the extra spaces in the label to align the month label inside the month.
+# Note that this could have been done by changing ``bymonthday`` above as well:
+sec.xaxis.set_major_formatter(mdates.DateFormatter(' %b'))
+sec.tick_params('x', length=0)
+sec.spines['bottom'].set_linewidth(0)
+
+# label the xaxis, but note for this to look good, it needs to be on the
+# secondary xaxis.
+sec.set_xlabel('Dates (2020)')
+
+plt.show()
From c19ea29c4a07d4b187b86f3cf201f21af000fa61 Mon Sep 17 00:00:00 2001
From: Jody Klymak
Date: Sat, 2 Dec 2023 14:36:16 -0800
Subject: [PATCH 34/87] Backport PR #27411: DOC: multilevel tick example
---
galleries/examples/ticks/multilevel_ticks.py | 99 ++++++++++++++++++++
1 file changed, 99 insertions(+)
create mode 100644 galleries/examples/ticks/multilevel_ticks.py
diff --git a/galleries/examples/ticks/multilevel_ticks.py b/galleries/examples/ticks/multilevel_ticks.py
new file mode 100644
index 000000000000..5b8d0ada5ae2
--- /dev/null
+++ b/galleries/examples/ticks/multilevel_ticks.py
@@ -0,0 +1,99 @@
+"""
+=========================
+Multilevel (nested) ticks
+=========================
+
+Sometimes we want another level of tick labels on an axis, perhaps to indicate
+a grouping of the ticks.
+
+Matplotlib does not provide an automated way to do this, but it is relatively
+straightforward to annotate below the main axis.
+
+These examples use `.Axes.secondary_xaxis`, which is one approach. It has the
+advantage that we can use Matplotlib Locators and Formatters on the axis that
+does the grouping if we want.
+
+This first example creates a secondary xaxis and manually adds the ticks and
+labels using `.Axes.set_xticks`. Note that the tick labels have a newline
+(e.g. ``"\nOughts"``) at the beginning of them to put the second-level tick
+labels below the main tick labels.
+"""
+
+import matplotlib.pyplot as plt
+import numpy as np
+
+import matplotlib.dates as mdates
+
+rng = np.random.default_rng(19680801)
+
+fig, ax = plt.subplots(layout='constrained', figsize=(4, 4))
+
+ax.plot(np.arange(30))
+
+sec = ax.secondary_xaxis(location=0)
+sec.set_xticks([5, 15, 25], labels=['\nOughts', '\nTeens', '\nTwenties'])
+
+# %%
+# This second example adds a second level of annotation to a categorical axis.
+# Here we need to note that each animal (category) is assigned an integer, so
+# ``cats`` is at x=0, ``dogs`` at x=1 etc. Then we place the ticks on the
+# second level on an x that is at the middle of the animal class we are trying
+# to delineate.
+#
+# This example also adds tick marks between the classes by adding a second
+# secondary xaxis, and placing long, wide ticks at the boundaries between the
+# animal classes.
+
+fig, ax = plt.subplots(layout='constrained', figsize=(7, 4))
+
+ax.plot(['cats', 'dogs', 'pigs', 'snakes', 'lizards', 'chickens',
+ 'eagles', 'herons', 'buzzards'],
+ rng.normal(size=9), 'o')
+
+# label the classes:
+sec = ax.secondary_xaxis(location=0)
+sec.set_xticks([1, 3.5, 6.5], labels=['\n\nMammals', '\n\nReptiles', '\n\nBirds'])
+sec.tick_params('x', length=0)
+
+# lines between the classes:
+sec2 = ax.secondary_xaxis(location=0)
+sec2.set_xticks([-0.5, 2.5, 4.5, 8.5], labels=[])
+sec2.tick_params('x', length=40, width=1.5)
+ax.set_xlim(-0.6, 8.6)
+
+# %%
+# Dates are another common place where we may want to have a second level of
+# tick labels. In this last example, we take advantage of the ability to add
+# an automatic locator and formatter to the secondary xaxis, which means we do
+# not need to set the ticks manually.
+#
+# This example also differs from the above, in that we placed it at a location
+# below the main axes ``location=-0.075`` and then we hide the spine by setting
+# the line width to zero. That means that our formatter no longer needs the
+# carriage returns of the previous two examples.
+
+fig, ax = plt.subplots(layout='constrained', figsize=(7, 4))
+
+time = np.arange(np.datetime64('2020-01-01'), np.datetime64('2020-03-31'),
+ np.timedelta64(1, 'D'))
+
+ax.plot(time, rng.random(size=len(time)))
+
+# just format the days:
+ax.xaxis.set_major_formatter(mdates.DateFormatter('%d'))
+
+# label the months:
+sec = ax.secondary_xaxis(location=-0.075)
+sec.xaxis.set_major_locator(mdates.MonthLocator(bymonthday=1))
+
+# note the extra spaces in the label to align the month label inside the month.
+# Note that this could have been done by changing ``bymonthday`` above as well:
+sec.xaxis.set_major_formatter(mdates.DateFormatter(' %b'))
+sec.tick_params('x', length=0)
+sec.spines['bottom'].set_linewidth(0)
+
+# label the xaxis, but note for this to look good, it needs to be on the
+# secondary xaxis.
+sec.set_xlabel('Dates (2020)')
+
+plt.show()
From ab26f684a4517484db13cbc858bcde03ca1eb7dc Mon Sep 17 00:00:00 2001
From: Oscar Gustafsson
Date: Tue, 5 Dec 2023 12:29:57 +0100
Subject: [PATCH 35/87] Backport PR #27441: Fix some minor issues with hexbin
bins argument
---
galleries/examples/statistics/hexbin_demo.py | 2 +-
lib/matplotlib/axes/_axes.py | 4 ++--
lib/matplotlib/tests/test_axes.py | 5 +++--
3 files changed, 6 insertions(+), 5 deletions(-)
diff --git a/galleries/examples/statistics/hexbin_demo.py b/galleries/examples/statistics/hexbin_demo.py
index 4bd0e0401424..b9a6206a934f 100644
--- a/galleries/examples/statistics/hexbin_demo.py
+++ b/galleries/examples/statistics/hexbin_demo.py
@@ -29,7 +29,7 @@
hb = ax1.hexbin(x, y, gridsize=50, bins='log', cmap='inferno')
ax1.set(xlim=xlim, ylim=ylim)
ax1.set_title("With a log color scale")
-cb = fig.colorbar(hb, ax=ax1, label='log10(N)')
+cb = fig.colorbar(hb, ax=ax1, label='counts')
plt.show()
diff --git a/lib/matplotlib/axes/_axes.py b/lib/matplotlib/axes/_axes.py
index b4a41099beda..28a9a92550e8 100644
--- a/lib/matplotlib/axes/_axes.py
+++ b/lib/matplotlib/axes/_axes.py
@@ -5084,10 +5084,10 @@ def reduce_C_function(C: array) -> float
)
# Set normalizer if bins is 'log'
- if bins == 'log':
+ if cbook._str_equal(bins, 'log'):
if norm is not None:
_api.warn_external("Only one of 'bins' and 'norm' arguments "
- f"can be supplied, ignoring bins={bins}")
+ f"can be supplied, ignoring {bins=}")
else:
norm = mcolors.LogNorm(vmin=vmin, vmax=vmax)
vmin = vmax = None
diff --git a/lib/matplotlib/tests/test_axes.py b/lib/matplotlib/tests/test_axes.py
index edc040eff3dd..87d5e35013c0 100644
--- a/lib/matplotlib/tests/test_axes.py
+++ b/lib/matplotlib/tests/test_axes.py
@@ -956,17 +956,18 @@ def test_hexbin_extent():
ax.hexbin("x", "y", extent=[.1, .3, .6, .7], data=data)
-@image_comparison(['hexbin_empty.png', 'hexbin_empty.png'], remove_text=True)
+@image_comparison(['hexbin_empty.png'], remove_text=True)
def test_hexbin_empty():
# From #3886: creating hexbin from empty dataset raises ValueError
fig, ax = plt.subplots()
ax.hexbin([], [])
- fig, ax = plt.subplots()
# From #23922: creating hexbin with log scaling from empty
# dataset raises ValueError
ax.hexbin([], [], bins='log')
# From #27103: np.max errors when handed empty data
ax.hexbin([], [], C=[], reduce_C_function=np.max)
+ # No string-comparison warning from NumPy.
+ ax.hexbin([], [], bins=np.arange(10))
def test_hexbin_pickable():
From 842d05f8b59b9a80ca7491801c3c28d0bb67e1dd Mon Sep 17 00:00:00 2001
From: hannah
Date: Tue, 5 Dec 2023 15:39:10 -0500
Subject: [PATCH 36/87] Backport PR #27397: SpanSelector widget: Improve doc
for `extents`
---
lib/matplotlib/widgets.py | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/lib/matplotlib/widgets.py b/lib/matplotlib/widgets.py
index 0a31a9dd2529..3c6208e71029 100644
--- a/lib/matplotlib/widgets.py
+++ b/lib/matplotlib/widgets.py
@@ -2915,7 +2915,12 @@ def _snap(values, snap_values):
@property
def extents(self):
- """Return extents of the span selector."""
+ """
+ (float, float)
+ The values, in data coordinates, for the start and end points of the current
+ selection. If there is no selection then the start and end values will be
+ the same.
+ """
if self.direction == 'horizontal':
vmin = self._selection_artist.get_x()
vmax = vmin + self._selection_artist.get_width()
From d3fc627077833263082abc86d525f7b44e0dc2f4 Mon Sep 17 00:00:00 2001
From: hannah
Date: Wed, 6 Dec 2023 12:11:51 -0500
Subject: [PATCH 37/87] Backport PR #27434: FIX: Expand stairs plot-type entry
intro (reattempt)
---
galleries/plot_types/basic/stairs.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/galleries/plot_types/basic/stairs.py b/galleries/plot_types/basic/stairs.py
index 9bc5d025f1e1..de5761e3a7a5 100644
--- a/galleries/plot_types/basic/stairs.py
+++ b/galleries/plot_types/basic/stairs.py
@@ -3,7 +3,9 @@
stairs(values)
==============
-See `~matplotlib.axes.Axes.stairs`.
+See `~matplotlib.axes.Axes.stairs` when plotting :math:`y` between
+:math:`(x_i, x_{i+1})`. For plotting :math:`y` at :math:`x`, see
+`~matplotlib.axes.Axes.step`.
.. redirect-from:: /plot_types/basic/step
"""
From e86f487c2727040f4e67fd4b93b20f5b4f4fece5 Mon Sep 17 00:00:00 2001
From: hannah
Date: Wed, 6 Dec 2023 12:11:51 -0500
Subject: [PATCH 38/87] Backport PR #27434: FIX: Expand stairs plot-type entry
intro (reattempt)
---
galleries/plot_types/basic/stairs.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/galleries/plot_types/basic/stairs.py b/galleries/plot_types/basic/stairs.py
index 9bc5d025f1e1..de5761e3a7a5 100644
--- a/galleries/plot_types/basic/stairs.py
+++ b/galleries/plot_types/basic/stairs.py
@@ -3,7 +3,9 @@
stairs(values)
==============
-See `~matplotlib.axes.Axes.stairs`.
+See `~matplotlib.axes.Axes.stairs` when plotting :math:`y` between
+:math:`(x_i, x_{i+1})`. For plotting :math:`y` at :math:`x`, see
+`~matplotlib.axes.Axes.step`.
.. redirect-from:: /plot_types/basic/step
"""
From 53279ca3322074e33d479ba93a6de7c87cf3ed95 Mon Sep 17 00:00:00 2001
From: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com>
Date: Thu, 7 Dec 2023 21:12:50 +0100
Subject: [PATCH 39/87] Backport PR #27316: DOC: Synchronize LICENSE_STIX files
---
LICENSE/LICENSE_STIX | 193 +++++++++++++++++++++++++++----------------
1 file changed, 123 insertions(+), 70 deletions(-)
diff --git a/LICENSE/LICENSE_STIX b/LICENSE/LICENSE_STIX
index 2f7aeea331ce..6034d9474814 100644
--- a/LICENSE/LICENSE_STIX
+++ b/LICENSE/LICENSE_STIX
@@ -1,71 +1,124 @@
-TERMS AND CONDITIONS
-
- 1. Permission is hereby granted, free of charge, to any person
-obtaining a copy of the STIX Fonts-TM set accompanying this license
-(collectively, the "Fonts") and the associated documentation files
-(collectively with the Fonts, the "Font Software"), to reproduce and
-distribute the Font Software, including the rights to use, copy, merge
-and publish copies of the Font Software, and to permit persons to whom
-the Font Software is furnished to do so same, subject to the following
-terms and conditions (the "License").
-
- 2. The following copyright and trademark notice and these Terms and
-Conditions shall be included in all copies of one or more of the Font
-typefaces and any derivative work created as permitted under this
-License:
-
- Copyright (c) 2001-2005 by the STI Pub Companies, consisting of
-the American Institute of Physics, the American Chemical Society, the
-American Mathematical Society, the American Physical Society, Elsevier,
-Inc., and The Institute of Electrical and Electronic Engineers, Inc.
-Portions copyright (c) 1998-2003 by MicroPress, Inc. Portions copyright
-(c) 1990 by Elsevier, Inc. All rights reserved. STIX Fonts-TM is a
-trademark of The Institute of Electrical and Electronics Engineers, Inc.
-
- 3. You may (a) convert the Fonts from one format to another (e.g.,
-from TrueType to PostScript), in which case the normal and reasonable
-distortion that occurs during such conversion shall be permitted and (b)
-embed or include a subset of the Fonts in a document for the purposes of
-allowing users to read text in the document that utilizes the Fonts. In
-each case, you may use the STIX Fonts-TM mark to designate the resulting
-Fonts or subset of the Fonts.
-
- 4. You may also (a) add glyphs or characters to the Fonts, or modify
-the shape of existing glyphs, so long as the base set of glyphs is not
-removed and (b) delete glyphs or characters from the Fonts, provided
-that the resulting font set is distributed with the following
-disclaimer: "This [name] font does not include all the Unicode points
-covered in the STIX Fonts-TM set but may include others." In each case,
-the name used to denote the resulting font set shall not include the
-term "STIX" or any similar term.
-
- 5. You may charge a fee in connection with the distribution of the
-Font Software, provided that no copy of one or more of the individual
-Font typefaces that form the STIX Fonts-TM set may be sold by itself.
-
- 6. THE FONT SOFTWARE IS PROVIDED "AS IS," WITHOUT WARRANTY OF ANY
-KIND, EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTIES
-OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
-OF COPYRIGHT, PATENT, TRADEMARK OR OTHER RIGHT. IN NO EVENT SHALL
-MICROPRESS OR ANY OF THE STI PUB COMPANIES BE LIABLE FOR ANY CLAIM,
-DAMAGES OR OTHER LIABILITY, INCLUDING, BUT NOT LIMITED TO, ANY GENERAL,
-SPECIAL, INDIRECT, INCIDENTAL OR CONSEQUENTIAL DAMAGES, WHETHER IN AN
-ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM OR OUT OF THE USE OR
-INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT
-SOFTWARE.
-
- 7. Except as contained in the notice set forth in Section 2, the
-names MicroPress Inc. and STI Pub Companies, as well as the names of the
-companies/organizations that compose the STI Pub Companies, shall not be
-used in advertising or otherwise to promote the sale, use or other
-dealings in the Font Software without the prior written consent of the
-respective company or organization.
-
- 8. This License shall become null and void in the event of any
-material breach of the Terms and Conditions herein by licensee.
-
- 9. A substantial portion of the STIX Fonts set was developed by
-MicroPress Inc. for the STI Pub Companies. To obtain additional
-mathematical fonts, please contact MicroPress, Inc., 68-30 Harrow
-Street, Forest Hills, NY 11375, USA - Phone: (718) 575-1816.
+The STIX fonts distributed with matplotlib have been modified from
+their canonical form. They have been converted from OTF to TTF format
+using Fontforge and this script:
+ #!/usr/bin/env fontforge
+ i=1
+ while ( i<$argc )
+ Open($argv[i])
+ Generate($argv[i]:r + ".ttf")
+ i = i+1
+ endloop
+
+The original STIX Font License begins below.
+
+-----------------------------------------------------------
+
+STIX Font License
+
+24 May 2010
+
+Copyright (c) 2001-2010 by the STI Pub Companies, consisting of the American
+Institute of Physics, the American Chemical Society, the American Mathematical
+Society, the American Physical Society, Elsevier, Inc., and The Institute of
+Electrical and Electronic Engineers, Inc. (www.stixfonts.org), with Reserved
+Font Name STIX Fonts, STIX Fonts (TM) is a trademark of The Institute of
+Electrical and Electronics Engineers, Inc.
+
+Portions copyright (c) 1998-2003 by MicroPress, Inc. (www.micropress-inc.com),
+with Reserved Font Name TM Math. To obtain additional mathematical fonts, please
+contact MicroPress, Inc., 68-30 Harrow Street, Forest Hills, NY 11375, USA,
+Phone: (718) 575-1816.
+
+Portions copyright (c) 1990 by Elsevier, Inc.
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1.
+This license is copied below, and is also available with a FAQ at:
+https://scripts.sil.org/OFL
+
+-----------------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+-----------------------------------------------------------
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font creation
+efforts of academic and linguistic communities, and to provide a free and
+open framework in which fonts may be shared and improved in partnership
+with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded,
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply
+to any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software components as
+distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to, deleting,
+or substituting -- in part or in whole -- any of the components of the
+Original Version, by changing formats or by porting the Font Software to a
+new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed, modify,
+redistribute, and sell modified and unmodified copies of the Font
+Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components,
+in Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the corresponding
+Copyright Holder. This restriction only applies to the primary font name as
+presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created
+using the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
From 7dd778180dc806fbdf807d183a435bfacf4b790c Mon Sep 17 00:00:00 2001
From: Thomas A Caswell
Date: Thu, 7 Dec 2023 15:28:26 -0500
Subject: [PATCH 40/87] Merge pull request #27395 from
story645/dependencies-install
DOC: Moved dependencies under install because they're version dependent
(cherry picked from commit d267a1d353ba09300a16621364670ec7ebba0fb9)
---
doc/devel/development_setup.rst | 12 +++++-
doc/devel/index.rst | 6 ---
.../installing}/dependencies.rst | 4 +-
doc/users/installing/index.rst | 43 +++++++++++++------
4 files changed, 43 insertions(+), 22 deletions(-)
rename doc/{devel => users/installing}/dependencies.rst (99%)
diff --git a/doc/devel/development_setup.rst b/doc/devel/development_setup.rst
index d5f491a82563..5489a377586c 100644
--- a/doc/devel/development_setup.rst
+++ b/doc/devel/development_setup.rst
@@ -155,9 +155,16 @@ Remember to activate the environment whenever you start working on Matplotlib.
Install Dependencies
====================
+
Most Python dependencies will be installed when :ref:`setting up the environment `
but non-Python dependencies like C++ compilers, LaTeX, and other system applications
-must be installed separately. For a full list, see :ref:`dependencies`.
+must be installed separately.
+
+.. toctree::
+ :maxdepth: 2
+
+ ../users/installing/dependencies
+
Install Matplotlib in editable mode
===================================
@@ -178,7 +185,8 @@ also happen if you change branches) you will have to re-run
If the installation is not working, please consult the :ref:`troubleshooting guide `.
If the guide does not offer a solution, please reach out via `chat `_
-or :ref:`open an issue `.
+or :ref:`open an issue `. For a list of environment variables
+you can set before install, see :ref:`environment-variables`.
Verify the Installation
=======================
diff --git a/doc/devel/index.rst b/doc/devel/index.rst
index 47ea39d29c4b..04f83f22227f 100644
--- a/doc/devel/index.rst
+++ b/doc/devel/index.rst
@@ -97,12 +97,6 @@ Development environment
development_setup
- .. toctree::
- :maxdepth: 1
-
- dependencies
- ../users/installing/environment_variables_faq.rst
-
.. grid-item-card::
:shadow: none
diff --git a/doc/devel/dependencies.rst b/doc/users/installing/dependencies.rst
similarity index 99%
rename from doc/devel/dependencies.rst
rename to doc/users/installing/dependencies.rst
index 7c14d90180d6..d5145ea85b3a 100644
--- a/doc/devel/dependencies.rst
+++ b/doc/users/installing/dependencies.rst
@@ -1,3 +1,5 @@
+.. redirect-from: /devel/dependencies
+
.. _dependencies:
============
@@ -377,7 +379,7 @@ The additional Python packages required to build the
The content of :file:`doc-requirements.txt` is also shown below:
-.. include:: ../../requirements/doc/doc-requirements.txt
+.. include:: ../../../requirements/doc/doc-requirements.txt
:literal:
Additional external dependencies
diff --git a/doc/users/installing/index.rst b/doc/users/installing/index.rst
index 65fd8ee4182a..ba380a22e41f 100644
--- a/doc/users/installing/index.rst
+++ b/doc/users/installing/index.rst
@@ -1,8 +1,8 @@
.. redirect-from:: /users/installing
-============
+************
Installation
-============
+************
Install an official release
@@ -135,25 +135,42 @@ Configure build and behavior defaults
=====================================
Aspects of the build and install process and some behaviorial defaults of the
-library can be configured via :ref:`environment-variables`. Default plotting
-appearance and behavior can be configured via the
+library can be configured via:
+
+.. toctree::
+ :maxdepth: 2
+
+ environment_variables_faq.rst
+
+Default plotting appearance and behavior can be configured via the
:ref:`rcParams file `
+Dependencies
+============
+
+Mandatory dependencies should be installed automatically if you install Matplotlib using
+a package manager such as ``pip`` or ``conda``; therefore this list is primarily for
+reference and troubleshooting.
+
+.. toctree::
+ :maxdepth: 2
+
+ dependencies
+
.. _installing-faq:
-==========================
Frequently asked questions
-==========================
+===========================
Report a compilation problem
-============================
+----------------------------
See :ref:`reporting-problems`.
Matplotlib compiled fine, but nothing shows up when I use it
-============================================================
+------------------------------------------------------------
The first thing to try is a :ref:`clean install ` and see if
that helps. If not, the best way to test your install is by running a script,
@@ -175,7 +192,7 @@ If you are still having trouble, see :ref:`reporting-problems`.
.. _clean-install:
How to completely remove Matplotlib
-===================================
+-----------------------------------
Occasionally, problems with Matplotlib can be solved with a clean
installation of the package. In order to fully remove an installed Matplotlib:
@@ -187,12 +204,12 @@ installation of the package. In order to fully remove an installed Matplotlib:
directory `.
OSX Notes
-=========
+---------
.. _which-python-for-osx:
Which python for OSX?
----------------------
+^^^^^^^^^^^^^^^^^^^^^
Apple ships OSX with its own Python, in ``/usr/bin/python``, and its own copy
of Matplotlib. Unfortunately, the way Apple currently installs its own copies
@@ -222,7 +239,7 @@ or Python.org Python.
.. _install_osx_binaries:
Installing OSX binary wheels
-----------------------------
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
If you are using Python from https://www.python.org, Homebrew, or Macports,
then you can use the standard pip installer to install Matplotlib binaries in
@@ -242,7 +259,7 @@ You might also want to install IPython or the Jupyter notebook (``python3 -m pip
install ipython notebook``).
Checking your installation
---------------------------
+^^^^^^^^^^^^^^^^^^^^^^^^^^
The new version of Matplotlib should now be on your Python "path". Check this
at the Terminal.app command line::
From adcb7a124498fa3f6947ac83a8246e28e25024df Mon Sep 17 00:00:00 2001
From: Thomas A Caswell
Date: Thu, 7 Dec 2023 15:28:26 -0500
Subject: [PATCH 41/87] Merge pull request #27395 from
story645/dependencies-install
DOC: Moved dependencies under install because they're version dependent
(cherry picked from commit d267a1d353ba09300a16621364670ec7ebba0fb9)
---
doc/devel/development_setup.rst | 15 ++++++-
doc/devel/index.rst | 6 ---
.../installing}/dependencies.rst | 4 +-
doc/users/installing/index.rst | 43 +++++++++++++------
4 files changed, 46 insertions(+), 22 deletions(-)
rename doc/{devel => users/installing}/dependencies.rst (99%)
diff --git a/doc/devel/development_setup.rst b/doc/devel/development_setup.rst
index d5f491a82563..babb5829e5ea 100644
--- a/doc/devel/development_setup.rst
+++ b/doc/devel/development_setup.rst
@@ -155,9 +155,18 @@ Remember to activate the environment whenever you start working on Matplotlib.
Install Dependencies
====================
+
Most Python dependencies will be installed when :ref:`setting up the environment `
but non-Python dependencies like C++ compilers, LaTeX, and other system applications
-must be installed separately. For a full list, see :ref:`dependencies`.
+must be installed separately.
+
+.. toctree::
+ :maxdepth: 2
+
+ ../users/installing/dependencies
+
+
+.. _development-install:
Install Matplotlib in editable mode
===================================
@@ -178,7 +187,9 @@ also happen if you change branches) you will have to re-run
If the installation is not working, please consult the :ref:`troubleshooting guide `.
If the guide does not offer a solution, please reach out via `chat `_
-or :ref:`open an issue `.
+or :ref:`open an issue `. For a list of the environment
+variables you can set before install, see :ref:`environment-variables`.
+
Verify the Installation
=======================
diff --git a/doc/devel/index.rst b/doc/devel/index.rst
index 47ea39d29c4b..04f83f22227f 100644
--- a/doc/devel/index.rst
+++ b/doc/devel/index.rst
@@ -97,12 +97,6 @@ Development environment
development_setup
- .. toctree::
- :maxdepth: 1
-
- dependencies
- ../users/installing/environment_variables_faq.rst
-
.. grid-item-card::
:shadow: none
diff --git a/doc/devel/dependencies.rst b/doc/users/installing/dependencies.rst
similarity index 99%
rename from doc/devel/dependencies.rst
rename to doc/users/installing/dependencies.rst
index 7c14d90180d6..d5145ea85b3a 100644
--- a/doc/devel/dependencies.rst
+++ b/doc/users/installing/dependencies.rst
@@ -1,3 +1,5 @@
+.. redirect-from: /devel/dependencies
+
.. _dependencies:
============
@@ -377,7 +379,7 @@ The additional Python packages required to build the
The content of :file:`doc-requirements.txt` is also shown below:
-.. include:: ../../requirements/doc/doc-requirements.txt
+.. include:: ../../../requirements/doc/doc-requirements.txt
:literal:
Additional external dependencies
diff --git a/doc/users/installing/index.rst b/doc/users/installing/index.rst
index 65fd8ee4182a..ba380a22e41f 100644
--- a/doc/users/installing/index.rst
+++ b/doc/users/installing/index.rst
@@ -1,8 +1,8 @@
.. redirect-from:: /users/installing
-============
+************
Installation
-============
+************
Install an official release
@@ -135,25 +135,42 @@ Configure build and behavior defaults
=====================================
Aspects of the build and install process and some behaviorial defaults of the
-library can be configured via :ref:`environment-variables`. Default plotting
-appearance and behavior can be configured via the
+library can be configured via:
+
+.. toctree::
+ :maxdepth: 2
+
+ environment_variables_faq.rst
+
+Default plotting appearance and behavior can be configured via the
:ref:`rcParams file `
+Dependencies
+============
+
+Mandatory dependencies should be installed automatically if you install Matplotlib using
+a package manager such as ``pip`` or ``conda``; therefore this list is primarily for
+reference and troubleshooting.
+
+.. toctree::
+ :maxdepth: 2
+
+ dependencies
+
.. _installing-faq:
-==========================
Frequently asked questions
-==========================
+===========================
Report a compilation problem
-============================
+----------------------------
See :ref:`reporting-problems`.
Matplotlib compiled fine, but nothing shows up when I use it
-============================================================
+------------------------------------------------------------
The first thing to try is a :ref:`clean install ` and see if
that helps. If not, the best way to test your install is by running a script,
@@ -175,7 +192,7 @@ If you are still having trouble, see :ref:`reporting-problems`.
.. _clean-install:
How to completely remove Matplotlib
-===================================
+-----------------------------------
Occasionally, problems with Matplotlib can be solved with a clean
installation of the package. In order to fully remove an installed Matplotlib:
@@ -187,12 +204,12 @@ installation of the package. In order to fully remove an installed Matplotlib:
directory `.
OSX Notes
-=========
+---------
.. _which-python-for-osx:
Which python for OSX?
----------------------
+^^^^^^^^^^^^^^^^^^^^^
Apple ships OSX with its own Python, in ``/usr/bin/python``, and its own copy
of Matplotlib. Unfortunately, the way Apple currently installs its own copies
@@ -222,7 +239,7 @@ or Python.org Python.
.. _install_osx_binaries:
Installing OSX binary wheels
-----------------------------
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
If you are using Python from https://www.python.org, Homebrew, or Macports,
then you can use the standard pip installer to install Matplotlib binaries in
@@ -242,7 +259,7 @@ You might also want to install IPython or the Jupyter notebook (``python3 -m pip
install ipython notebook``).
Checking your installation
---------------------------
+^^^^^^^^^^^^^^^^^^^^^^^^^^
The new version of Matplotlib should now be on your Python "path". Check this
at the Terminal.app command line::
From f9bcd6b827b00b2b24a6cfb8934f147770ab4ce5 Mon Sep 17 00:00:00 2001
From: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com>
Date: Sat, 9 Dec 2023 13:27:08 +0100
Subject: [PATCH 42/87] Backport PR #27481: Fixing Pylab documentation in API
interface overview
---
galleries/users_explain/figure/api_interfaces.rst | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/galleries/users_explain/figure/api_interfaces.rst b/galleries/users_explain/figure/api_interfaces.rst
index 6947817e6781..5279fe24634a 100644
--- a/galleries/users_explain/figure/api_interfaces.rst
+++ b/galleries/users_explain/figure/api_interfaces.rst
@@ -285,6 +285,11 @@ Appendix: "pylab" interface
---------------------------
There is one further interface that is highly discouraged, and that is to
-basically do ``from matplotlib.pyplot import *``. This allows users to simply
-call ``plot(x, y)``. While convenient, this can lead to obvious problems if the
-user unwittingly names a variable the same name as a pyplot method.
+basically do ``from matplotlib.pylab import *``. This imports all the
+functions from ``matplotlib.pyplot``, ``numpy``, ``numpy.fft``, ``numpy.linalg``, and
+``numpy.random``, and some additional functions into the global namespace.
+
+Such a pattern is considered bad practice in modern python, as it clutters
+the global namespace. Even more severely, in the case of ``pylab``, this will
+overwrite some builtin functions (e.g. the builtin ``sum`` will be replaced by
+``numpy.sum``), which can lead to unexpected behavior.
From 0229df5e716421eb53e834dfd1dbcc03a43275f2 Mon Sep 17 00:00:00 2001
From: Elliott Sales de Andrade
Date: Mon, 11 Dec 2023 21:57:39 -0500
Subject: [PATCH 43/87] Backport PR #27496: Bump actions/setup-python from 4 to
5
---
.github/workflows/cibuildwheel.yml | 2 +-
.github/workflows/codeql-analysis.yml | 2 +-
.github/workflows/mypy-stubtest.yml | 2 +-
.github/workflows/reviewdog.yml | 4 ++--
.github/workflows/tests.yml | 2 +-
5 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/.github/workflows/cibuildwheel.yml b/.github/workflows/cibuildwheel.yml
index 217c5d88f16e..c31842a4ce1f 100644
--- a/.github/workflows/cibuildwheel.yml
+++ b/.github/workflows/cibuildwheel.yml
@@ -43,7 +43,7 @@ jobs:
with:
fetch-depth: 0
- - uses: actions/setup-python@v4
+ - uses: actions/setup-python@v5
name: Install Python
with:
python-version: 3.9
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
index d31973e954d5..f0041ece02ee 100644
--- a/.github/workflows/codeql-analysis.yml
+++ b/.github/workflows/codeql-analysis.yml
@@ -29,7 +29,7 @@ jobs:
uses: actions/checkout@v4
- name: Set up Python
- uses: actions/setup-python@v4
+ uses: actions/setup-python@v5
if: matrix.language != 'javascript'
with:
python-version: '3.x'
diff --git a/.github/workflows/mypy-stubtest.yml b/.github/workflows/mypy-stubtest.yml
index 6da6f607642c..efd37a38b15b 100644
--- a/.github/workflows/mypy-stubtest.yml
+++ b/.github/workflows/mypy-stubtest.yml
@@ -14,7 +14,7 @@ jobs:
- uses: actions/checkout@v4
- name: Set up Python 3
- uses: actions/setup-python@v4
+ uses: actions/setup-python@v5
with:
python-version: 3.9
diff --git a/.github/workflows/reviewdog.yml b/.github/workflows/reviewdog.yml
index f9c1121581c0..f4495eda8b84 100644
--- a/.github/workflows/reviewdog.yml
+++ b/.github/workflows/reviewdog.yml
@@ -15,7 +15,7 @@ jobs:
- uses: actions/checkout@v4
- name: Set up Python 3
- uses: actions/setup-python@v4
+ uses: actions/setup-python@v5
with:
python-version: 3.9
@@ -45,7 +45,7 @@ jobs:
- uses: actions/checkout@v4
- name: Set up Python 3
- uses: actions/setup-python@v4
+ uses: actions/setup-python@v5
with:
python-version: 3.9
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 4f0a1c0196de..76290bfcc0d1 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -98,7 +98,7 @@ jobs:
fetch-depth: 0
- name: Set up Python ${{ matrix.python-version }}
- uses: actions/setup-python@v4
+ uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
From 8b40424ea4020bea189124024ad360e10b01aa61 Mon Sep 17 00:00:00 2001
From: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com>
Date: Tue, 12 Dec 2023 15:19:07 +0100
Subject: [PATCH 44/87] Backport PR #27504: DOC: correct return type for axline
---
lib/matplotlib/axes/_axes.py | 2 +-
lib/matplotlib/axes/_axes.pyi | 4 ++--
lib/matplotlib/pyplot.py | 4 ++--
3 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/lib/matplotlib/axes/_axes.py b/lib/matplotlib/axes/_axes.py
index 28a9a92550e8..a54150f6f3c2 100644
--- a/lib/matplotlib/axes/_axes.py
+++ b/lib/matplotlib/axes/_axes.py
@@ -893,7 +893,7 @@ def axline(self, xy1, xy2=None, *, slope=None, **kwargs):
Returns
-------
- `.Line2D`
+ `.AxLine`
Other Parameters
----------------
diff --git a/lib/matplotlib/axes/_axes.pyi b/lib/matplotlib/axes/_axes.pyi
index 9602db3b950c..1bfca8fc333d 100644
--- a/lib/matplotlib/axes/_axes.pyi
+++ b/lib/matplotlib/axes/_axes.pyi
@@ -18,7 +18,7 @@ from matplotlib.contour import ContourSet, QuadContourSet
from matplotlib.image import AxesImage, PcolorImage
from matplotlib.legend import Legend
from matplotlib.legend_handler import HandlerBase
-from matplotlib.lines import Line2D
+from matplotlib.lines import Line2D, AxLine
from matplotlib.mlab import GaussianKDE
from matplotlib.patches import Rectangle, FancyArrow, Polygon, StepPatch, Wedge
from matplotlib.quiver import Quiver, QuiverKey, Barbs
@@ -151,7 +151,7 @@ class Axes(_AxesBase):
*,
slope: float | None = ...,
**kwargs
- ) -> Line2D: ...
+ ) -> AxLine: ...
def axhspan(
self, ymin: float, ymax: float, xmin: float = ..., xmax: float = ..., **kwargs
) -> Polygon: ...
diff --git a/lib/matplotlib/pyplot.py b/lib/matplotlib/pyplot.py
index 42c177490cbb..fb925f1df62b 100644
--- a/lib/matplotlib/pyplot.py
+++ b/lib/matplotlib/pyplot.py
@@ -130,7 +130,7 @@
# We may not need the following imports here:
from matplotlib.colors import Normalize
-from matplotlib.lines import Line2D
+from matplotlib.lines import Line2D, AxLine
from matplotlib.text import Text, Annotation
from matplotlib.patches import Polygon, Rectangle, Circle, Arrow
from matplotlib.widgets import Button, Slider, Widget
@@ -2721,7 +2721,7 @@ def axline(
*,
slope: float | None = None,
**kwargs,
-) -> Line2D:
+) -> AxLine:
return gca().axline(xy1, xy2=xy2, slope=slope, **kwargs)
From bce5d1a599f6f1ebfc78fee63e9294aebb81b055 Mon Sep 17 00:00:00 2001
From: James Salsman
Date: Wed, 13 Dec 2023 03:09:26 -0800
Subject: [PATCH 45/87] Backport PR #27346: DOC: Show and correct default
alignment parameters in text.py
---
.../examples/text_labels_and_annotations/text_alignment.py | 3 ++-
lib/matplotlib/axes/_axes.py | 5 ++++-
lib/matplotlib/text.py | 4 ++--
3 files changed, 8 insertions(+), 4 deletions(-)
diff --git a/galleries/examples/text_labels_and_annotations/text_alignment.py b/galleries/examples/text_labels_and_annotations/text_alignment.py
index 7ad0d07c6572..4c0351e0bbc5 100644
--- a/galleries/examples/text_labels_and_annotations/text_alignment.py
+++ b/galleries/examples/text_labels_and_annotations/text_alignment.py
@@ -4,7 +4,8 @@
==============
Texts are aligned relative to their anchor point depending on the properties
-``horizontalalignment`` and ``verticalalignment``.
+``horizontalalignment`` (default: ``left``) and ``verticalalignment``
+(default: ``baseline``.)
.. redirect-from:: /gallery/pyplots/text_layout
diff --git a/lib/matplotlib/axes/_axes.py b/lib/matplotlib/axes/_axes.py
index a54150f6f3c2..793ff56cfcf9 100644
--- a/lib/matplotlib/axes/_axes.py
+++ b/lib/matplotlib/axes/_axes.py
@@ -632,7 +632,10 @@ def text(self, x, y, s, fontdict=None, **kwargs):
"""
Add text to the Axes.
- Add the text *s* to the Axes at location *x*, *y* in data coordinates.
+ Add the text *s* to the Axes at location *x*, *y* in data coordinates,
+ with a default ``horizontalalignment`` on the ``left`` and
+ ``verticalalignment`` at the ``baseline``. See
+ :doc:`/gallery/text_labels_and_annotations/text_alignment`.
Parameters
----------
diff --git a/lib/matplotlib/text.py b/lib/matplotlib/text.py
index 7a58ce717200..7e7b84a3f9c3 100644
--- a/lib/matplotlib/text.py
+++ b/lib/matplotlib/text.py
@@ -123,7 +123,7 @@ def __init__(self,
The text is aligned relative to the anchor point (*x*, *y*) according
to ``horizontalalignment`` (default: 'left') and ``verticalalignment``
- (default: 'bottom'). See also
+ (default: 'baseline'). See also
:doc:`/gallery/text_labels_and_annotations/text_alignment`.
While Text accepts the 'label' keyword argument, by default it is not
@@ -1251,7 +1251,7 @@ def set_verticalalignment(self, align):
Parameters
----------
- align : {'bottom', 'baseline', 'center', 'center_baseline', 'top'}
+ align : {'baseline', 'bottom', 'center', 'center_baseline', 'top'}
"""
_api.check_in_list(
['top', 'bottom', 'center', 'baseline', 'center_baseline'],
From ca293a2e63083ad73b2ddbed87d86cade7015f1f Mon Sep 17 00:00:00 2001
From: Jody Klymak
Date: Fri, 15 Dec 2023 22:18:57 -0800
Subject: [PATCH 46/87] Backport PR #27528: FIX: Remove runloop execution while
waiting for stdin
---
src/_macosx.m | 3 ---
1 file changed, 3 deletions(-)
diff --git a/src/_macosx.m b/src/_macosx.m
index a580362f676f..d39f37063c9e 100755
--- a/src/_macosx.m
+++ b/src/_macosx.m
@@ -89,9 +89,6 @@ static int wait_for_stdin() {
if (!event) { break; }
[NSApp sendEvent: event];
}
- // We need to run the run loop for a short time to allow the
- // events to be processed and keep flushing them while we wait for stdin
- [[NSRunLoop currentRunLoop] runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 0.01]];
}
// Remove the input handler as an observer
[[NSNotificationCenter defaultCenter] removeObserver: stdinHandle];
From 4a7efefa7dd8d55764eb5b5373e96dfba8f9b9c8 Mon Sep 17 00:00:00 2001
From: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com>
Date: Sun, 17 Dec 2023 20:59:31 +0100
Subject: [PATCH 47/87] Backport PR #27534: Clarify AxLine Params
---
lib/matplotlib/lines.py | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/lib/matplotlib/lines.py b/lib/matplotlib/lines.py
index 92d55a3fe6ae..9bc058f92132 100644
--- a/lib/matplotlib/lines.py
+++ b/lib/matplotlib/lines.py
@@ -1478,9 +1478,10 @@ def __init__(self, xy1, xy2, slope, **kwargs):
The first set of (x, y) coordinates for the line to pass through.
xy2 : (float, float) or None
The second set of (x, y) coordinates for the line to pass through.
- Either *xy2* or *slope* has to be given.
+ Both *xy2* and *slope* must be passed, but one of them must be None.
slope : float or None
- The slope of the line. Either *xy2* or *slope* has to be given.
+ The slope of the line. Both *xy2* and *slope* must be passed, but one of
+ them must be None.
"""
super().__init__([0, 1], [0, 1], **kwargs)
From 428cf414e2210edfcc574ffbcd9407c4124e2dcc Mon Sep 17 00:00:00 2001
From: Oscar Gustafsson
Date: Mon, 18 Dec 2023 12:14:35 +0100
Subject: [PATCH 48/87] Backport PR #27535: Update ax.legend input types
---
lib/matplotlib/axes/_axes.py | 2 +-
lib/matplotlib/axes/_axes.pyi | 8 ++++----
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/lib/matplotlib/axes/_axes.py b/lib/matplotlib/axes/_axes.py
index 793ff56cfcf9..499c221bb5c9 100644
--- a/lib/matplotlib/axes/_axes.py
+++ b/lib/matplotlib/axes/_axes.py
@@ -280,7 +280,7 @@ def legend(self, *args, **kwargs):
Parameters
----------
- handles : sequence of (`.Artist` or tuple of `.Artist`), optional
+ handles : list of (`.Artist` or tuple of `.Artist`), optional
A list of Artists (lines, patches) to be added to the legend.
Use this together with *labels*, if you need full control on what
is shown in the legend and the automatic mechanism described above
diff --git a/lib/matplotlib/axes/_axes.pyi b/lib/matplotlib/axes/_axes.pyi
index 1bfca8fc333d..0a70e575dfc4 100644
--- a/lib/matplotlib/axes/_axes.pyi
+++ b/lib/matplotlib/axes/_axes.pyi
@@ -31,7 +31,7 @@ import matplotlib.streamplot as mstream
import datetime
import PIL.Image
-from collections.abc import Callable, Sequence
+from collections.abc import Callable, Iterable, Sequence
from typing import Any, Literal, overload
import numpy as np
from numpy.typing import ArrayLike
@@ -57,11 +57,11 @@ class Axes(_AxesBase):
@overload
def legend(self) -> Legend: ...
@overload
- def legend(self, handles: Sequence[Artist | tuple[Artist, ...]], labels: Sequence[str], **kwargs) -> Legend: ...
+ def legend(self, handles: Iterable[Artist | tuple[Artist, ...]], labels: Iterable[str], **kwargs) -> Legend: ...
@overload
- def legend(self, *, handles: Sequence[Artist | tuple[Artist, ...]], **kwargs) -> Legend: ...
+ def legend(self, *, handles: Iterable[Artist | tuple[Artist, ...]], **kwargs) -> Legend: ...
@overload
- def legend(self, labels: Sequence[str], **kwargs) -> Legend: ...
+ def legend(self, labels: Iterable[str], **kwargs) -> Legend: ...
@overload
def legend(self, **kwargs) -> Legend: ...
From 33bbb0520650a03309a218e28fcc87b0be401f0f Mon Sep 17 00:00:00 2001
From: Kyle Sunden
Date: Mon, 18 Dec 2023 18:37:06 -0600
Subject: [PATCH 49/87] Backport PR #27527: FIX: Add macos timers to the main
thread
---
src/_macosx.m | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/src/_macosx.m b/src/_macosx.m
index d39f37063c9e..6be86cfe7367 100755
--- a/src/_macosx.m
+++ b/src/_macosx.m
@@ -1723,11 +1723,15 @@ - (void)flagsChanged:(NSEvent *)event
}
// hold a reference to the timer so we can invalidate/stop it later
- self->timer = [NSTimer scheduledTimerWithTimeInterval: interval
- repeats: !single
- block: ^(NSTimer *timer) {
+ self->timer = [NSTimer timerWithTimeInterval: interval
+ repeats: !single
+ block: ^(NSTimer *timer) {
gil_call_method((PyObject*)self, "_on_timer");
}];
+ // Schedule the timer on the main run loop which is needed
+ // when updating the UI from a background thread
+ [[NSRunLoop mainRunLoop] addTimer: self->timer forMode: NSRunLoopCommonModes];
+
exit:
Py_XDECREF(py_interval);
Py_XDECREF(py_single);
From 2e01b0c6b281794be8784c16d4c346cec3b39da9 Mon Sep 17 00:00:00 2001
From: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com>
Date: Fri, 29 Dec 2023 23:43:34 +0100
Subject: [PATCH 50/87] Backport PR #27578: Fix polar labels with negative
theta limit
---
lib/matplotlib/projections/polar.py | 2 +-
lib/matplotlib/tests/test_polar.py | 8 ++++++++
2 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/lib/matplotlib/projections/polar.py b/lib/matplotlib/projections/polar.py
index 0bff320e5728..33063674c415 100644
--- a/lib/matplotlib/projections/polar.py
+++ b/lib/matplotlib/projections/polar.py
@@ -298,7 +298,7 @@ def set_axis(self, axis):
def __call__(self):
lim = self.axis.get_view_interval()
if _is_full_circle_deg(lim[0], lim[1]):
- return np.arange(8) * 2 * np.pi / 8
+ return np.deg2rad(min(lim)) + np.arange(8) * 2 * np.pi / 8
else:
return np.deg2rad(self.base())
diff --git a/lib/matplotlib/tests/test_polar.py b/lib/matplotlib/tests/test_polar.py
index 9d6e78da2cbc..9a1c6be6fcff 100644
--- a/lib/matplotlib/tests/test_polar.py
+++ b/lib/matplotlib/tests/test_polar.py
@@ -446,3 +446,11 @@ def test_polar_log():
n = 100
ax.plot(np.linspace(0, 2 * np.pi, n), np.logspace(0, 2, n))
+
+
+def test_polar_neg_theta_lims():
+ fig = plt.figure()
+ ax = fig.add_subplot(projection='polar')
+ ax.set_thetalim(-np.pi, np.pi)
+ labels = [l.get_text() for l in ax.xaxis.get_ticklabels()]
+ assert labels == ['-180°', '-135°', '-90°', '-45°', '0°', '45°', '90°', '135°']
From 88d3600a0431fcc9ab8785e434ce47569d4be086 Mon Sep 17 00:00:00 2001
From: Elliott Sales de Andrade
Date: Thu, 4 Jan 2024 02:34:10 -0500
Subject: [PATCH 51/87] Backport PR #27595: Fix is_sorted_and_has_non_nan for
byteswapped inputs.
---
lib/matplotlib/tests/test_lines.py | 2 ++
src/_path_wrapper.cpp | 4 ++--
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/lib/matplotlib/tests/test_lines.py b/lib/matplotlib/tests/test_lines.py
index 4f23e6969b0b..6ad8c640384e 100644
--- a/lib/matplotlib/tests/test_lines.py
+++ b/lib/matplotlib/tests/test_lines.py
@@ -249,6 +249,8 @@ def test_is_sorted_and_has_non_nan():
assert _path.is_sorted_and_has_non_nan(np.array([1, 2, 3]))
assert _path.is_sorted_and_has_non_nan(np.array([1, np.nan, 3]))
assert not _path.is_sorted_and_has_non_nan([3, 5] + [np.nan] * 100 + [0, 2])
+ # [2, 256] byteswapped:
+ assert not _path.is_sorted_and_has_non_nan(np.array([33554432, 65536], ">i4"))
n = 2 * mlines.Line2D._subslice_optim_min_size
plt.plot([np.nan] * n, range(n))
diff --git a/src/_path_wrapper.cpp b/src/_path_wrapper.cpp
index 369d9e030880..15a30e298dfd 100644
--- a/src/_path_wrapper.cpp
+++ b/src/_path_wrapper.cpp
@@ -699,8 +699,8 @@ static PyObject *Py_is_sorted_and_has_non_nan(PyObject *self, PyObject *obj)
{
bool result;
- PyArrayObject *array = (PyArrayObject *)PyArray_FromAny(
- obj, NULL, 1, 1, 0, NULL);
+ PyArrayObject *array = (PyArrayObject *)PyArray_CheckFromAny(
+ obj, NULL, 1, 1, NPY_ARRAY_NOTSWAPPED, NULL);
if (array == NULL) {
return NULL;
From 2445d11fedb0586e00b10022f497ceea59e70351 Mon Sep 17 00:00:00 2001
From: Oscar Gustafsson
Date: Thu, 4 Jan 2024 10:15:31 +0100
Subject: [PATCH 52/87] Backport PR #27594: Cleanup viewlims example.
---
galleries/examples/event_handling/viewlims.py | 79 +++++++++----------
1 file changed, 39 insertions(+), 40 deletions(-)
diff --git a/galleries/examples/event_handling/viewlims.py b/galleries/examples/event_handling/viewlims.py
index b47e3b5b0801..ebc3e6de5fb8 100644
--- a/galleries/examples/event_handling/viewlims.py
+++ b/galleries/examples/event_handling/viewlims.py
@@ -14,21 +14,15 @@
You can copy and paste individual parts, or download the entire example
using the link at the bottom of the page.
"""
+
+import functools
+
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.patches import Rectangle
-# We just subclass Rectangle so that it can be called with an Axes
-# instance, causing the rectangle to update its shape to match the
-# bounds of the Axes
-class UpdatingRect(Rectangle):
- def __call__(self, ax):
- self.set_bounds(*ax.viewLim.bounds)
- ax.figure.canvas.draw_idle()
-
-
# A class that will regenerate a fractal set as we zoom in, so that you
# can actually see the increasing detail. A box in the left panel will show
# the area to which we are zoomed.
@@ -40,9 +34,9 @@ def __init__(self, h=500, w=500, niter=50, radius=2., power=2):
self.radius = radius
self.power = power
- def compute_image(self, xstart, xend, ystart, yend):
- self.x = np.linspace(xstart, xend, self.width)
- self.y = np.linspace(ystart, yend, self.height).reshape(-1, 1)
+ def compute_image(self, xlim, ylim):
+ self.x = np.linspace(*xlim, self.width)
+ self.y = np.linspace(*ylim, self.height).reshape(-1, 1)
c = self.x + 1.0j * self.y
threshold_time = np.zeros((self.height, self.width))
z = np.zeros(threshold_time.shape, dtype=complex)
@@ -56,38 +50,43 @@ def compute_image(self, xstart, xend, ystart, yend):
def ax_update(self, ax):
ax.set_autoscale_on(False) # Otherwise, infinite loop
# Get the number of points from the number of pixels in the window
- self.width, self.height = \
- np.round(ax.patch.get_window_extent().size).astype(int)
- # Get the range for the new area
- vl = ax.viewLim
- extent = vl.x0, vl.x1, vl.y0, vl.y1
+ self.width, self.height = ax.patch.get_window_extent().size.round().astype(int)
# Update the image object with our new data and extent
- im = ax.images[-1]
- im.set_data(self.compute_image(*extent))
- im.set_extent(extent)
+ ax.images[-1].set(data=self.compute_image(ax.get_xlim(), ax.get_ylim()),
+ extent=(*ax.get_xlim(), *ax.get_ylim()))
ax.figure.canvas.draw_idle()
md = MandelbrotDisplay()
-Z = md.compute_image(-2., 0.5, -1.25, 1.25)
-
-fig1, (ax1, ax2) = plt.subplots(1, 2)
-ax1.imshow(Z, origin='lower',
- extent=(md.x.min(), md.x.max(), md.y.min(), md.y.max()))
-ax2.imshow(Z, origin='lower',
- extent=(md.x.min(), md.x.max(), md.y.min(), md.y.max()))
-
-rect = UpdatingRect(
- [0, 0], 0, 0, facecolor='none', edgecolor='black', linewidth=1.0)
-rect.set_bounds(*ax2.viewLim.bounds)
-ax1.add_patch(rect)
-
-# Connect for changing the view limits
-ax2.callbacks.connect('xlim_changed', rect)
-ax2.callbacks.connect('ylim_changed', rect)
-
-ax2.callbacks.connect('xlim_changed', md.ax_update)
-ax2.callbacks.connect('ylim_changed', md.ax_update)
-ax2.set_title("Zoom here")
+
+fig1, (ax_full, ax_zoom) = plt.subplots(1, 2)
+ax_zoom.imshow([[0]], origin="lower") # Empty initial image.
+ax_zoom.set_title("Zoom here")
+
+rect = Rectangle(
+ [0, 0], 0, 0, facecolor="none", edgecolor="black", linewidth=1.0)
+ax_full.add_patch(rect)
+
+
+def update_rect(rect, ax): # Let the rectangle track the bounds of the zoom axes.
+ xlo, xhi = ax.get_xlim()
+ ylo, yhi = ax.get_ylim()
+ rect.set_bounds((xlo, ylo, xhi - xlo, yhi - ylo))
+ ax.figure.canvas.draw_idle()
+
+
+# Connect for changing the view limits.
+ax_zoom.callbacks.connect("xlim_changed", functools.partial(update_rect, rect))
+ax_zoom.callbacks.connect("ylim_changed", functools.partial(update_rect, rect))
+
+ax_zoom.callbacks.connect("xlim_changed", md.ax_update)
+ax_zoom.callbacks.connect("ylim_changed", md.ax_update)
+
+# Initialize: trigger image computation by setting view limits; set colormap limits;
+# copy image to full view.
+ax_zoom.set(xlim=(-2, .5), ylim=(-1.25, 1.25))
+im = ax_zoom.images[0]
+ax_zoom.images[0].set(clim=(im.get_array().min(), im.get_array().max()))
+ax_full.imshow(im.get_array(), extent=im.get_extent(), origin="lower")
plt.show()
From 14aa4e0a24558124fbd4a322c9c143287eab56b3 Mon Sep 17 00:00:00 2001
From: Oscar Gustafsson
Date: Thu, 4 Jan 2024 10:15:31 +0100
Subject: [PATCH 53/87] Backport PR #27594: Cleanup viewlims example.
---
galleries/examples/event_handling/viewlims.py | 79 +++++++++----------
1 file changed, 39 insertions(+), 40 deletions(-)
diff --git a/galleries/examples/event_handling/viewlims.py b/galleries/examples/event_handling/viewlims.py
index b47e3b5b0801..ebc3e6de5fb8 100644
--- a/galleries/examples/event_handling/viewlims.py
+++ b/galleries/examples/event_handling/viewlims.py
@@ -14,21 +14,15 @@
You can copy and paste individual parts, or download the entire example
using the link at the bottom of the page.
"""
+
+import functools
+
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.patches import Rectangle
-# We just subclass Rectangle so that it can be called with an Axes
-# instance, causing the rectangle to update its shape to match the
-# bounds of the Axes
-class UpdatingRect(Rectangle):
- def __call__(self, ax):
- self.set_bounds(*ax.viewLim.bounds)
- ax.figure.canvas.draw_idle()
-
-
# A class that will regenerate a fractal set as we zoom in, so that you
# can actually see the increasing detail. A box in the left panel will show
# the area to which we are zoomed.
@@ -40,9 +34,9 @@ def __init__(self, h=500, w=500, niter=50, radius=2., power=2):
self.radius = radius
self.power = power
- def compute_image(self, xstart, xend, ystart, yend):
- self.x = np.linspace(xstart, xend, self.width)
- self.y = np.linspace(ystart, yend, self.height).reshape(-1, 1)
+ def compute_image(self, xlim, ylim):
+ self.x = np.linspace(*xlim, self.width)
+ self.y = np.linspace(*ylim, self.height).reshape(-1, 1)
c = self.x + 1.0j * self.y
threshold_time = np.zeros((self.height, self.width))
z = np.zeros(threshold_time.shape, dtype=complex)
@@ -56,38 +50,43 @@ def compute_image(self, xstart, xend, ystart, yend):
def ax_update(self, ax):
ax.set_autoscale_on(False) # Otherwise, infinite loop
# Get the number of points from the number of pixels in the window
- self.width, self.height = \
- np.round(ax.patch.get_window_extent().size).astype(int)
- # Get the range for the new area
- vl = ax.viewLim
- extent = vl.x0, vl.x1, vl.y0, vl.y1
+ self.width, self.height = ax.patch.get_window_extent().size.round().astype(int)
# Update the image object with our new data and extent
- im = ax.images[-1]
- im.set_data(self.compute_image(*extent))
- im.set_extent(extent)
+ ax.images[-1].set(data=self.compute_image(ax.get_xlim(), ax.get_ylim()),
+ extent=(*ax.get_xlim(), *ax.get_ylim()))
ax.figure.canvas.draw_idle()
md = MandelbrotDisplay()
-Z = md.compute_image(-2., 0.5, -1.25, 1.25)
-
-fig1, (ax1, ax2) = plt.subplots(1, 2)
-ax1.imshow(Z, origin='lower',
- extent=(md.x.min(), md.x.max(), md.y.min(), md.y.max()))
-ax2.imshow(Z, origin='lower',
- extent=(md.x.min(), md.x.max(), md.y.min(), md.y.max()))
-
-rect = UpdatingRect(
- [0, 0], 0, 0, facecolor='none', edgecolor='black', linewidth=1.0)
-rect.set_bounds(*ax2.viewLim.bounds)
-ax1.add_patch(rect)
-
-# Connect for changing the view limits
-ax2.callbacks.connect('xlim_changed', rect)
-ax2.callbacks.connect('ylim_changed', rect)
-
-ax2.callbacks.connect('xlim_changed', md.ax_update)
-ax2.callbacks.connect('ylim_changed', md.ax_update)
-ax2.set_title("Zoom here")
+
+fig1, (ax_full, ax_zoom) = plt.subplots(1, 2)
+ax_zoom.imshow([[0]], origin="lower") # Empty initial image.
+ax_zoom.set_title("Zoom here")
+
+rect = Rectangle(
+ [0, 0], 0, 0, facecolor="none", edgecolor="black", linewidth=1.0)
+ax_full.add_patch(rect)
+
+
+def update_rect(rect, ax): # Let the rectangle track the bounds of the zoom axes.
+ xlo, xhi = ax.get_xlim()
+ ylo, yhi = ax.get_ylim()
+ rect.set_bounds((xlo, ylo, xhi - xlo, yhi - ylo))
+ ax.figure.canvas.draw_idle()
+
+
+# Connect for changing the view limits.
+ax_zoom.callbacks.connect("xlim_changed", functools.partial(update_rect, rect))
+ax_zoom.callbacks.connect("ylim_changed", functools.partial(update_rect, rect))
+
+ax_zoom.callbacks.connect("xlim_changed", md.ax_update)
+ax_zoom.callbacks.connect("ylim_changed", md.ax_update)
+
+# Initialize: trigger image computation by setting view limits; set colormap limits;
+# copy image to full view.
+ax_zoom.set(xlim=(-2, .5), ylim=(-1.25, 1.25))
+im = ax_zoom.images[0]
+ax_zoom.images[0].set(clim=(im.get_array().min(), im.get_array().max()))
+ax_full.imshow(im.get_array(), extent=im.get_extent(), origin="lower")
plt.show()
From a179ea8be9ec250fb04b7b8551e3da3f14775550 Mon Sep 17 00:00:00 2001
From: Thomas A Caswell
Date: Mon, 8 Jan 2024 09:21:09 -0500
Subject: [PATCH 54/87] Backport PR #27606: Pin black version
---
environment.yml | 2 +-
requirements/testing/all.txt | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/environment.yml b/environment.yml
index 7b13735bb172..15cba9a01c32 100644
--- a/environment.yml
+++ b/environment.yml
@@ -62,4 +62,4 @@ dependencies:
- pytest-xdist
- tornado
- pytz
- - black
+ - black<24
diff --git a/requirements/testing/all.txt b/requirements/testing/all.txt
index 173c5a4a9909..4ca786fcf73e 100644
--- a/requirements/testing/all.txt
+++ b/requirements/testing/all.txt
@@ -1,6 +1,6 @@
# pip requirements for all the CI builds
-black
+black<24
certifi
coverage!=6.3
psutil
From fabbaabedb9e1e2c5ee50ea092131a06756c1848 Mon Sep 17 00:00:00 2001
From: hannah
Date: Tue, 9 Jan 2024 17:15:05 -0500
Subject: [PATCH 55/87] Backport PR #27620: DOC: simplify histogram animation
example
---
.../examples/animation/animated_histogram.py | 43 +++++++++----------
1 file changed, 21 insertions(+), 22 deletions(-)
diff --git a/galleries/examples/animation/animated_histogram.py b/galleries/examples/animation/animated_histogram.py
index d23d174ad2ca..03fb04d8acda 100644
--- a/galleries/examples/animation/animated_histogram.py
+++ b/galleries/examples/animation/animated_histogram.py
@@ -7,43 +7,42 @@
histogram.
"""
+import functools
+
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.animation as animation
-# Fixing random state for reproducibility
-np.random.seed(19680801)
-# Fixing bin edges
+# Setting up a random number generator with a fixed state for reproducibility.
+rng = np.random.default_rng(seed=19680801)
+# Fixing bin edges.
HIST_BINS = np.linspace(-4, 4, 100)
-# histogram our data with numpy
-data = np.random.randn(1000)
+# Histogram our data with numpy.
+data = rng.standard_normal(1000)
n, _ = np.histogram(data, HIST_BINS)
# %%
# To animate the histogram, we need an ``animate`` function, which generates
-# a random set of numbers and updates the heights of rectangles. We utilize a
-# python closure to track an instance of `.BarContainer` whose `.Rectangle`
-# patches we shall update.
+# a random set of numbers and updates the heights of rectangles. The ``animate``
+# function updates the `.Rectangle` patches on an instance of `.BarContainer`.
-def prepare_animation(bar_container):
+def animate(frame_number, bar_container):
+ # Simulate new data coming in.
+ data = rng.standard_normal(1000)
+ n, _ = np.histogram(data, HIST_BINS)
+ for count, rect in zip(n, bar_container.patches):
+ rect.set_height(count)
- def animate(frame_number):
- # simulate new data coming in
- data = np.random.randn(1000)
- n, _ = np.histogram(data, HIST_BINS)
- for count, rect in zip(n, bar_container.patches):
- rect.set_height(count)
- return bar_container.patches
- return animate
+ return bar_container.patches
# %%
# Using :func:`~matplotlib.pyplot.hist` allows us to get an instance of
-# `.BarContainer`, which is a collection of `.Rectangle` instances. Calling
-# ``prepare_animation`` will define ``animate`` function working with supplied
-# `.BarContainer`, all this is used to setup `.FuncAnimation`.
+# `.BarContainer`, which is a collection of `.Rectangle` instances. Since
+# `.FuncAnimation` will only pass the frame number parameter to the animation
+# function, we use `functools.partial` to fix the ``bar_container`` parameter.
# Output generated via `matplotlib.animation.Animation.to_jshtml`.
@@ -52,6 +51,6 @@ def animate(frame_number):
ec="yellow", fc="green", alpha=0.5)
ax.set_ylim(top=55) # set safe limit to ensure that all data is visible.
-ani = animation.FuncAnimation(fig, prepare_animation(bar_container), 50,
- repeat=False, blit=True)
+anim = functools.partial(animate, bar_container=bar_container)
+ani = animation.FuncAnimation(fig, anim, 50, repeat=False, blit=True)
plt.show()
From fbb5aa5bdbf4e9d0e24f0655a0cbf896344359e7 Mon Sep 17 00:00:00 2001
From: hannah
Date: Tue, 9 Jan 2024 17:15:05 -0500
Subject: [PATCH 56/87] Backport PR #27620: DOC: simplify histogram animation
example
---
.../examples/animation/animated_histogram.py | 43 +++++++++----------
1 file changed, 21 insertions(+), 22 deletions(-)
diff --git a/galleries/examples/animation/animated_histogram.py b/galleries/examples/animation/animated_histogram.py
index d23d174ad2ca..03fb04d8acda 100644
--- a/galleries/examples/animation/animated_histogram.py
+++ b/galleries/examples/animation/animated_histogram.py
@@ -7,43 +7,42 @@
histogram.
"""
+import functools
+
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.animation as animation
-# Fixing random state for reproducibility
-np.random.seed(19680801)
-# Fixing bin edges
+# Setting up a random number generator with a fixed state for reproducibility.
+rng = np.random.default_rng(seed=19680801)
+# Fixing bin edges.
HIST_BINS = np.linspace(-4, 4, 100)
-# histogram our data with numpy
-data = np.random.randn(1000)
+# Histogram our data with numpy.
+data = rng.standard_normal(1000)
n, _ = np.histogram(data, HIST_BINS)
# %%
# To animate the histogram, we need an ``animate`` function, which generates
-# a random set of numbers and updates the heights of rectangles. We utilize a
-# python closure to track an instance of `.BarContainer` whose `.Rectangle`
-# patches we shall update.
+# a random set of numbers and updates the heights of rectangles. The ``animate``
+# function updates the `.Rectangle` patches on an instance of `.BarContainer`.
-def prepare_animation(bar_container):
+def animate(frame_number, bar_container):
+ # Simulate new data coming in.
+ data = rng.standard_normal(1000)
+ n, _ = np.histogram(data, HIST_BINS)
+ for count, rect in zip(n, bar_container.patches):
+ rect.set_height(count)
- def animate(frame_number):
- # simulate new data coming in
- data = np.random.randn(1000)
- n, _ = np.histogram(data, HIST_BINS)
- for count, rect in zip(n, bar_container.patches):
- rect.set_height(count)
- return bar_container.patches
- return animate
+ return bar_container.patches
# %%
# Using :func:`~matplotlib.pyplot.hist` allows us to get an instance of
-# `.BarContainer`, which is a collection of `.Rectangle` instances. Calling
-# ``prepare_animation`` will define ``animate`` function working with supplied
-# `.BarContainer`, all this is used to setup `.FuncAnimation`.
+# `.BarContainer`, which is a collection of `.Rectangle` instances. Since
+# `.FuncAnimation` will only pass the frame number parameter to the animation
+# function, we use `functools.partial` to fix the ``bar_container`` parameter.
# Output generated via `matplotlib.animation.Animation.to_jshtml`.
@@ -52,6 +51,6 @@ def animate(frame_number):
ec="yellow", fc="green", alpha=0.5)
ax.set_ylim(top=55) # set safe limit to ensure that all data is visible.
-ani = animation.FuncAnimation(fig, prepare_animation(bar_container), 50,
- repeat=False, blit=True)
+anim = functools.partial(animate, bar_container=bar_container)
+ani = animation.FuncAnimation(fig, anim, 50, repeat=False, blit=True)
plt.show()
From f189a342176838df9564537b38326882a14c1ded Mon Sep 17 00:00:00 2001
From: Thomas A Caswell
Date: Thu, 11 Jan 2024 11:22:43 -0500
Subject: [PATCH 57/87] Backport PR #27634: circle: Make deploy stage into a
normal step
---
.circleci/config.yml | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/.circleci/config.yml b/.circleci/config.yml
index 0668f436ddac..e120f95f5ee8 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -1,6 +1,6 @@
# Circle CI configuration file
# https://circleci.com/docs/
-
+---
version: 2.1
@@ -197,6 +197,12 @@ commands:
- store_artifacts:
path: doc/build/sphinx-gallery-files.tar.gz
+ deploy-docs:
+ steps:
+ - run:
+ name: "Deploy new docs"
+ command: ./.circleci/deploy-docs.sh
+
##########################################
# Here is where the real jobs are defined.
@@ -234,9 +240,7 @@ jobs:
fingerprints:
- "be:c3:c1:d8:fb:a1:0e:37:71:72:d7:a3:40:13:8f:14"
- - deploy:
- name: "Deploy new docs"
- command: ./.circleci/deploy-docs.sh
+ - deploy-docs
#########################################
# Defining workflows gets us parallelism.
From f7f0937d5572c6e6b8c94ff1dc225fe11ce92634 Mon Sep 17 00:00:00 2001
From: Thomas A Caswell
Date: Thu, 11 Jan 2024 11:22:43 -0500
Subject: [PATCH 58/87] Backport PR #27634: circle: Make deploy stage into a
normal step
---
.circleci/config.yml | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/.circleci/config.yml b/.circleci/config.yml
index 0668f436ddac..e120f95f5ee8 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -1,6 +1,6 @@
# Circle CI configuration file
# https://circleci.com/docs/
-
+---
version: 2.1
@@ -197,6 +197,12 @@ commands:
- store_artifacts:
path: doc/build/sphinx-gallery-files.tar.gz
+ deploy-docs:
+ steps:
+ - run:
+ name: "Deploy new docs"
+ command: ./.circleci/deploy-docs.sh
+
##########################################
# Here is where the real jobs are defined.
@@ -234,9 +240,7 @@ jobs:
fingerprints:
- "be:c3:c1:d8:fb:a1:0e:37:71:72:d7:a3:40:13:8f:14"
- - deploy:
- name: "Deploy new docs"
- command: ./.circleci/deploy-docs.sh
+ - deploy-docs
#########################################
# Defining workflows gets us parallelism.
From 2d566207f511cc02522753d0793a207971026cc1 Mon Sep 17 00:00:00 2001
From: Elliott Sales de Andrade
Date: Tue, 16 Jan 2024 19:53:52 -0500
Subject: [PATCH 59/87] Backport PR #27624: Prepare for Pytest v8
---
lib/matplotlib/backends/backend_pdf.py | 2 +-
lib/matplotlib/tests/test_colors.py | 11 ++++++++---
lib/matplotlib/tests/test_rcparams.py | 6 ++----
lib/matplotlib/tests/test_ticker.py | 16 ++++++++++++----
4 files changed, 23 insertions(+), 12 deletions(-)
diff --git a/lib/matplotlib/backends/backend_pdf.py b/lib/matplotlib/backends/backend_pdf.py
index aa4883135d92..facb8efec819 100644
--- a/lib/matplotlib/backends/backend_pdf.py
+++ b/lib/matplotlib/backends/backend_pdf.py
@@ -2732,7 +2732,7 @@ def close(self):
_api.warn_deprecated("3.8", message=(
"Keeping empty pdf files is deprecated since %(since)s and support "
"will be removed %(removal)s."))
- PdfFile(self._filename, metadata=self._metadata) # touch the file.
+ PdfFile(self._filename, metadata=self._metadata).close() # touch the file.
def infodict(self):
"""
diff --git a/lib/matplotlib/tests/test_colors.py b/lib/matplotlib/tests/test_colors.py
index 139efbe17407..35030b6bea7a 100644
--- a/lib/matplotlib/tests/test_colors.py
+++ b/lib/matplotlib/tests/test_colors.py
@@ -1,6 +1,7 @@
import copy
import itertools
import unittest.mock
+from packaging.version import parse as parse_version
from io import BytesIO
import numpy as np
@@ -147,9 +148,13 @@ def test_double_register_builtin_cmap():
with pytest.raises(ValueError, match='A colormap named "viridis"'):
with pytest.warns(mpl.MatplotlibDeprecationWarning):
cm.register_cmap(name, mpl.colormaps[name])
- with pytest.warns(UserWarning):
- # TODO is warning more than once!
- cm.register_cmap(name, mpl.colormaps[name], override_builtin=True)
+
+ if parse_version(pytest.__version__).major < 8:
+ with pytest.warns(UserWarning):
+ cm.register_cmap(name, mpl.colormaps[name], override_builtin=True)
+ else:
+ with pytest.warns(UserWarning), pytest.warns(mpl.MatplotlibDeprecationWarning):
+ cm.register_cmap(name, mpl.colormaps[name], override_builtin=True)
def test_unregister_builtin_cmap():
diff --git a/lib/matplotlib/tests/test_rcparams.py b/lib/matplotlib/tests/test_rcparams.py
index 515068c462d4..610b6056f20f 100644
--- a/lib/matplotlib/tests/test_rcparams.py
+++ b/lib/matplotlib/tests/test_rcparams.py
@@ -106,14 +106,12 @@ def test_rcparams_update():
rc = mpl.RcParams({'figure.figsize': (3.5, 42)})
bad_dict = {'figure.figsize': (3.5, 42, 1)}
# make sure validation happens on input
- with pytest.raises(ValueError), \
- pytest.warns(UserWarning, match="validate"):
+ with pytest.raises(ValueError):
rc.update(bad_dict)
def test_rcparams_init():
- with pytest.raises(ValueError), \
- pytest.warns(UserWarning, match="validate"):
+ with pytest.raises(ValueError):
mpl.RcParams({'figure.figsize': (3.5, 42, 1)})
diff --git a/lib/matplotlib/tests/test_ticker.py b/lib/matplotlib/tests/test_ticker.py
index 961daaa1d167..ff9a519ee185 100644
--- a/lib/matplotlib/tests/test_ticker.py
+++ b/lib/matplotlib/tests/test_ticker.py
@@ -3,6 +3,7 @@
import locale
import logging
import re
+from packaging.version import parse as parse_version
import numpy as np
from numpy.testing import assert_almost_equal, assert_array_equal
@@ -914,10 +915,17 @@ def test_mathtext_ticks(self):
'axes.formatter.use_mathtext': False
})
- with pytest.warns(UserWarning, match='cmr10 font should ideally'):
- fig, ax = plt.subplots()
- ax.set_xticks([-1, 0, 1])
- fig.canvas.draw()
+ if parse_version(pytest.__version__).major < 8:
+ with pytest.warns(UserWarning, match='cmr10 font should ideally'):
+ fig, ax = plt.subplots()
+ ax.set_xticks([-1, 0, 1])
+ fig.canvas.draw()
+ else:
+ with (pytest.warns(UserWarning, match="Glyph 8722"),
+ pytest.warns(UserWarning, match='cmr10 font should ideally')):
+ fig, ax = plt.subplots()
+ ax.set_xticks([-1, 0, 1])
+ fig.canvas.draw()
def test_cmr10_substitutions(self, caplog):
mpl.rcParams.update({
From 697c7cb6dfac027727f3c99a9abe9d4d07089b2f Mon Sep 17 00:00:00 2001
From: David Stansby
Date: Wed, 17 Jan 2024 11:57:43 +0000
Subject: [PATCH 60/87] Merge pull request #27647 from saranti/minorticks
Fix error that occurs when minorticks are on multi-Axes Figure with more than one boxplot
(cherry picked from commit b03407b375d8a4b5101f40178f9d19b84bfce822)
---
lib/matplotlib/tests/test_ticker.py | 21 +++++++++++++++++++++
lib/matplotlib/ticker.py | 2 +-
2 files changed, 22 insertions(+), 1 deletion(-)
diff --git a/lib/matplotlib/tests/test_ticker.py b/lib/matplotlib/tests/test_ticker.py
index ff9a519ee185..202465847b5b 100644
--- a/lib/matplotlib/tests/test_ticker.py
+++ b/lib/matplotlib/tests/test_ticker.py
@@ -1797,3 +1797,24 @@ def test_set_offset_string(formatter):
assert formatter.get_offset() == ''
formatter.set_offset_string('mpl')
assert formatter.get_offset() == 'mpl'
+
+
+def test_minorticks_on_multi_fig():
+ """
+ Turning on minor gridlines in a multi-Axes Figure
+ that contains more than one boxplot and shares the x-axis
+ should not raise an exception.
+ """
+ fig, ax = plt.subplots()
+
+ ax.boxplot(np.arange(10), positions=[0])
+ ax.boxplot(np.arange(10), positions=[0])
+ ax.boxplot(np.arange(10), positions=[1])
+
+ ax.grid(which="major")
+ ax.grid(which="minor")
+ ax.minorticks_on()
+ fig.draw_without_rendering()
+
+ assert ax.get_xgridlines()
+ assert isinstance(ax.xaxis.get_minor_locator(), mpl.ticker.AutoMinorLocator)
diff --git a/lib/matplotlib/ticker.py b/lib/matplotlib/ticker.py
index 5b1b7e11408c..47a06f3eec3a 100644
--- a/lib/matplotlib/ticker.py
+++ b/lib/matplotlib/ticker.py
@@ -2895,7 +2895,7 @@ def __call__(self):
'logarithmic scale')
return []
- majorlocs = self.axis.get_majorticklocs()
+ majorlocs = np.unique(self.axis.get_majorticklocs())
try:
majorstep = majorlocs[1] - majorlocs[0]
except IndexError:
From 72403c7c63c2f2f957182d0ed0501adde385f2c1 Mon Sep 17 00:00:00 2001
From: David Stansby
Date: Wed, 17 Jan 2024 12:03:53 +0000
Subject: [PATCH 61/87] Backport PR #27657: Fix Numpy 2.0 related test failures
---
lib/matplotlib/pylab.py | 2 ++
lib/matplotlib/tests/test_axes.py | 23 ++++++++++++++---------
lib/matplotlib/tests/test_colors.py | 16 ++++++++--------
3 files changed, 24 insertions(+), 17 deletions(-)
diff --git a/lib/matplotlib/pylab.py b/lib/matplotlib/pylab.py
index 77eb6506d87f..a50779cf6d26 100644
--- a/lib/matplotlib/pylab.py
+++ b/lib/matplotlib/pylab.py
@@ -60,6 +60,8 @@
bytes = __import__("builtins").bytes
# We also don't want the numpy version of these functions
abs = __import__("builtins").abs
+bool = __import__("builtins").bool
max = __import__("builtins").max
min = __import__("builtins").min
+pow = __import__("builtins").pow
round = __import__("builtins").round
diff --git a/lib/matplotlib/tests/test_axes.py b/lib/matplotlib/tests/test_axes.py
index 87d5e35013c0..3fa7cbe0e34d 100644
--- a/lib/matplotlib/tests/test_axes.py
+++ b/lib/matplotlib/tests/test_axes.py
@@ -5735,7 +5735,12 @@ def test_text_labelsize():
ax.tick_params(direction='out')
-@image_comparison(['pie_default.png'])
+# Note: The `pie` image tests were affected by Numpy 2.0 changing promotions
+# (NEP 50). While the changes were only marginal, tolerances were introduced.
+# These tolerances could likely go away when numpy 2.0 is the minimum supported
+# numpy and the images are regenerated.
+
+@image_comparison(['pie_default.png'], tol=0.01)
def test_pie_default():
# The slices will be ordered and plotted counter-clockwise.
labels = 'Frogs', 'Hogs', 'Dogs', 'Logs'
@@ -5748,7 +5753,7 @@ def test_pie_default():
@image_comparison(['pie_linewidth_0', 'pie_linewidth_0', 'pie_linewidth_0'],
- extensions=['png'], style='mpl20')
+ extensions=['png'], style='mpl20', tol=0.01)
def test_pie_linewidth_0():
# The slices will be ordered and plotted counter-clockwise.
labels = 'Frogs', 'Hogs', 'Dogs', 'Logs'
@@ -5780,7 +5785,7 @@ def test_pie_linewidth_0():
plt.axis('equal')
-@image_comparison(['pie_center_radius.png'], style='mpl20')
+@image_comparison(['pie_center_radius.png'], style='mpl20', tol=0.005)
def test_pie_center_radius():
# The slices will be ordered and plotted counter-clockwise.
labels = 'Frogs', 'Hogs', 'Dogs', 'Logs'
@@ -5800,7 +5805,7 @@ def test_pie_center_radius():
plt.axis('equal')
-@image_comparison(['pie_linewidth_2.png'], style='mpl20')
+@image_comparison(['pie_linewidth_2.png'], style='mpl20', tol=0.01)
def test_pie_linewidth_2():
# The slices will be ordered and plotted counter-clockwise.
labels = 'Frogs', 'Hogs', 'Dogs', 'Logs'
@@ -5815,7 +5820,7 @@ def test_pie_linewidth_2():
plt.axis('equal')
-@image_comparison(['pie_ccw_true.png'], style='mpl20')
+@image_comparison(['pie_ccw_true.png'], style='mpl20', tol=0.01)
def test_pie_ccw_true():
# The slices will be ordered and plotted counter-clockwise.
labels = 'Frogs', 'Hogs', 'Dogs', 'Logs'
@@ -5830,7 +5835,7 @@ def test_pie_ccw_true():
plt.axis('equal')
-@image_comparison(['pie_frame_grid.png'], style='mpl20')
+@image_comparison(['pie_frame_grid.png'], style='mpl20', tol=0.002)
def test_pie_frame_grid():
# The slices will be ordered and plotted counter-clockwise.
labels = 'Frogs', 'Hogs', 'Dogs', 'Logs'
@@ -5857,7 +5862,7 @@ def test_pie_frame_grid():
plt.axis('equal')
-@image_comparison(['pie_rotatelabels_true.png'], style='mpl20')
+@image_comparison(['pie_rotatelabels_true.png'], style='mpl20', tol=0.009)
def test_pie_rotatelabels_true():
# The slices will be ordered and plotted counter-clockwise.
labels = 'Hogwarts', 'Frogs', 'Dogs', 'Logs'
@@ -5872,7 +5877,7 @@ def test_pie_rotatelabels_true():
plt.axis('equal')
-@image_comparison(['pie_no_label.png'])
+@image_comparison(['pie_no_label.png'], tol=0.01)
def test_pie_nolabel_but_legend():
labels = 'Frogs', 'Hogs', 'Dogs', 'Logs'
sizes = [15, 30, 45, 10]
@@ -5886,7 +5891,7 @@ def test_pie_nolabel_but_legend():
plt.legend()
-@image_comparison(['pie_shadow.png'], style='mpl20')
+@image_comparison(['pie_shadow.png'], style='mpl20', tol=0.002)
def test_pie_shadow():
# Also acts as a test for the shade argument of Shadow
sizes = [15, 30, 45, 10]
diff --git a/lib/matplotlib/tests/test_colors.py b/lib/matplotlib/tests/test_colors.py
index 35030b6bea7a..49761ba20307 100644
--- a/lib/matplotlib/tests/test_colors.py
+++ b/lib/matplotlib/tests/test_colors.py
@@ -1371,38 +1371,38 @@ def test_scalarmappable_to_rgba(bytes):
# uint8 RGBA
x = np.ones((2, 3, 4), dtype=np.uint8)
expected = x.copy() if bytes else x.astype(np.float32)/255
- np.testing.assert_array_equal(sm.to_rgba(x, bytes=bytes), expected)
+ np.testing.assert_almost_equal(sm.to_rgba(x, bytes=bytes), expected)
# uint8 RGB
expected[..., 3] = alpha_1
- np.testing.assert_array_equal(sm.to_rgba(x[..., :3], bytes=bytes), expected)
+ np.testing.assert_almost_equal(sm.to_rgba(x[..., :3], bytes=bytes), expected)
# uint8 masked RGBA
xm = np.ma.masked_array(x, mask=np.zeros_like(x))
xm.mask[0, 0, 0] = True
expected = x.copy() if bytes else x.astype(np.float32)/255
expected[0, 0, 3] = 0
- np.testing.assert_array_equal(sm.to_rgba(xm, bytes=bytes), expected)
+ np.testing.assert_almost_equal(sm.to_rgba(xm, bytes=bytes), expected)
# uint8 masked RGB
expected[..., 3] = alpha_1
expected[0, 0, 3] = 0
- np.testing.assert_array_equal(sm.to_rgba(xm[..., :3], bytes=bytes), expected)
+ np.testing.assert_almost_equal(sm.to_rgba(xm[..., :3], bytes=bytes), expected)
# float RGBA
x = np.ones((2, 3, 4), dtype=float) * 0.5
expected = (x * 255).astype(np.uint8) if bytes else x.copy()
- np.testing.assert_array_equal(sm.to_rgba(x, bytes=bytes), expected)
+ np.testing.assert_almost_equal(sm.to_rgba(x, bytes=bytes), expected)
# float RGB
expected[..., 3] = alpha_1
- np.testing.assert_array_equal(sm.to_rgba(x[..., :3], bytes=bytes), expected)
+ np.testing.assert_almost_equal(sm.to_rgba(x[..., :3], bytes=bytes), expected)
# float masked RGBA
xm = np.ma.masked_array(x, mask=np.zeros_like(x))
xm.mask[0, 0, 0] = True
expected = (x * 255).astype(np.uint8) if bytes else x.copy()
expected[0, 0, 3] = 0
- np.testing.assert_array_equal(sm.to_rgba(xm, bytes=bytes), expected)
+ np.testing.assert_almost_equal(sm.to_rgba(xm, bytes=bytes), expected)
# float masked RGB
expected[..., 3] = alpha_1
expected[0, 0, 3] = 0
- np.testing.assert_array_equal(sm.to_rgba(xm[..., :3], bytes=bytes), expected)
+ np.testing.assert_almost_equal(sm.to_rgba(xm[..., :3], bytes=bytes), expected)
def test_failed_conversions():
From 0e42de70641413d2aa4140601a70d438032dc0cf Mon Sep 17 00:00:00 2001
From: David Stansby
Date: Fri, 29 Dec 2023 10:35:34 +0000
Subject: [PATCH 62/87] Backport PR #27581: CI: install German lanugage packs
an ubuntu test runners
Merge pull request #27581 from tacaswell/ci/de_locale
CI: install German lanugage packs an ubuntu test runners
(cherry picked from commit 4df729a4755a4de6af706f069e23b1b3cdeab839)
---
.github/workflows/tests.yml | 1 +
azure-pipelines.yml | 1 +
2 files changed, 2 insertions(+)
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 76290bfcc0d1..a9724425b60d 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -118,6 +118,7 @@ jobs:
gir1.2-gtk-3.0 \
graphviz \
inkscape \
+ language-pack-de \
lcov \
libcairo2 \
libcairo2-dev \
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index bb38804ae121..4e01d67f7385 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -101,6 +101,7 @@ stages:
gir1.2-gtk-3.0 \
graphviz \
inkscape \
+ language-pack-de \
libcairo2 \
libgirepository-1.0-1 \
lmodern \
From cf8735a91baed6fea30cc914d43d918a647aca1e Mon Sep 17 00:00:00 2001
From: Ruth Comer <10599679+rcomer@users.noreply.github.com>
Date: Sun, 21 Jan 2024 10:53:28 +0000
Subject: [PATCH 63/87] Backport PR #27678: DOC: selecting individual colors
from a colormap
---
.flake8 | 1 +
.../color/individual_colors_from_cmap.py | 61 +++++++++++++++++++
2 files changed, 62 insertions(+)
create mode 100644 galleries/examples/color/individual_colors_from_cmap.py
diff --git a/.flake8 b/.flake8
index ee739cdf4231..f6d6b8d8c6df 100644
--- a/.flake8
+++ b/.flake8
@@ -73,6 +73,7 @@ per-file-ignores =
galleries/users_explain/text/text_props.py: E501
galleries/examples/animation/frame_grabbing_sgskip.py: E402
+ galleries/examples/color/individual_colors_from_cmap.py: E402
galleries/examples/images_contours_and_fields/tricontour_demo.py: E201
galleries/examples/images_contours_and_fields/tripcolor_demo.py: E201
galleries/examples/images_contours_and_fields/triplot_demo.py: E201
diff --git a/galleries/examples/color/individual_colors_from_cmap.py b/galleries/examples/color/individual_colors_from_cmap.py
new file mode 100644
index 000000000000..572fb33e6f11
--- /dev/null
+++ b/galleries/examples/color/individual_colors_from_cmap.py
@@ -0,0 +1,61 @@
+"""
+===========================================
+Selecting individual colors from a colormap
+===========================================
+
+Sometimes we want to use more colors or a different set of colors than the default color
+cycle provides. Selecting individual colors from one of the provided colormaps can be a
+convenient way to do this.
+
+Once we have hold of a `.Colormap` instance, the individual colors can be accessed
+by passing it an index. If we want a specific number of colors taken at regular
+intervals from a continuous colormap, we can create a new colormap using the
+`~.Colormap.resampled` method.
+
+For more details about manipulating colormaps, see :ref:`colormap-manipulation`.
+"""
+
+import matplotlib.pyplot as plt
+
+import matplotlib as mpl
+
+n_lines = 21
+
+cmap = mpl.colormaps.get_cmap('plasma').resampled(n_lines)
+
+fig, ax = plt.subplots(layout='constrained')
+
+for i in range(n_lines):
+ ax.plot([0, i], color=cmap(i))
+
+plt.show()
+
+# %%
+# Instead of passing colors one by one to `~.Axes.plot`, we can replace the default
+# color cycle with a different set of colors. Specifying a `~cycler.cycler` instance
+# within `.rcParams` achieves that. See :ref:`color_cycle` for details.
+
+
+from cycler import cycler
+
+cmap = mpl.colormaps.get_cmap('Dark2')
+colors = cmap(range(cmap.N)) # cmap.N is number of unique colors in the colormap
+
+with mpl.rc_context({'axes.prop_cycle': cycler(color=colors)}):
+
+ fig, ax = plt.subplots(layout='constrained')
+
+ for i in range(n_lines):
+ ax.plot([0, i])
+
+plt.show()
+
+# %%
+#
+# .. admonition:: References
+#
+# The use of the following functions, methods, classes and modules is shown
+# in this example:
+#
+# - `matplotlib.colors.Colormap`
+# - `matplotlib.colors.Colormap.resampled`
From 47b5ba315f359c0e94665e43514ec65171f87bbd Mon Sep 17 00:00:00 2001
From: Ruth Comer <10599679+rcomer@users.noreply.github.com>
Date: Sun, 21 Jan 2024 10:53:28 +0000
Subject: [PATCH 64/87] Backport PR #27678: DOC: selecting individual colors
from a colormap
---
.flake8 | 1 +
.../color/individual_colors_from_cmap.py | 61 +++++++++++++++++++
2 files changed, 62 insertions(+)
create mode 100644 galleries/examples/color/individual_colors_from_cmap.py
diff --git a/.flake8 b/.flake8
index ee739cdf4231..f6d6b8d8c6df 100644
--- a/.flake8
+++ b/.flake8
@@ -73,6 +73,7 @@ per-file-ignores =
galleries/users_explain/text/text_props.py: E501
galleries/examples/animation/frame_grabbing_sgskip.py: E402
+ galleries/examples/color/individual_colors_from_cmap.py: E402
galleries/examples/images_contours_and_fields/tricontour_demo.py: E201
galleries/examples/images_contours_and_fields/tripcolor_demo.py: E201
galleries/examples/images_contours_and_fields/triplot_demo.py: E201
diff --git a/galleries/examples/color/individual_colors_from_cmap.py b/galleries/examples/color/individual_colors_from_cmap.py
new file mode 100644
index 000000000000..572fb33e6f11
--- /dev/null
+++ b/galleries/examples/color/individual_colors_from_cmap.py
@@ -0,0 +1,61 @@
+"""
+===========================================
+Selecting individual colors from a colormap
+===========================================
+
+Sometimes we want to use more colors or a different set of colors than the default color
+cycle provides. Selecting individual colors from one of the provided colormaps can be a
+convenient way to do this.
+
+Once we have hold of a `.Colormap` instance, the individual colors can be accessed
+by passing it an index. If we want a specific number of colors taken at regular
+intervals from a continuous colormap, we can create a new colormap using the
+`~.Colormap.resampled` method.
+
+For more details about manipulating colormaps, see :ref:`colormap-manipulation`.
+"""
+
+import matplotlib.pyplot as plt
+
+import matplotlib as mpl
+
+n_lines = 21
+
+cmap = mpl.colormaps.get_cmap('plasma').resampled(n_lines)
+
+fig, ax = plt.subplots(layout='constrained')
+
+for i in range(n_lines):
+ ax.plot([0, i], color=cmap(i))
+
+plt.show()
+
+# %%
+# Instead of passing colors one by one to `~.Axes.plot`, we can replace the default
+# color cycle with a different set of colors. Specifying a `~cycler.cycler` instance
+# within `.rcParams` achieves that. See :ref:`color_cycle` for details.
+
+
+from cycler import cycler
+
+cmap = mpl.colormaps.get_cmap('Dark2')
+colors = cmap(range(cmap.N)) # cmap.N is number of unique colors in the colormap
+
+with mpl.rc_context({'axes.prop_cycle': cycler(color=colors)}):
+
+ fig, ax = plt.subplots(layout='constrained')
+
+ for i in range(n_lines):
+ ax.plot([0, i])
+
+plt.show()
+
+# %%
+#
+# .. admonition:: References
+#
+# The use of the following functions, methods, classes and modules is shown
+# in this example:
+#
+# - `matplotlib.colors.Colormap`
+# - `matplotlib.colors.Colormap.resampled`
From a9ff1e78242674326064b73e13e68337631e1a30 Mon Sep 17 00:00:00 2001
From: Thomas A Caswell
Date: Mon, 22 Jan 2024 12:21:14 -0500
Subject: [PATCH 65/87] Backport PR #27670: Implement macos AppDelegate
---
src/_macosx.m | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/src/_macosx.m b/src/_macosx.m
index 6be86cfe7367..47df6c37da93 100755
--- a/src/_macosx.m
+++ b/src/_macosx.m
@@ -100,6 +100,9 @@ static int wait_for_stdin() {
}
/* ---------------------------- Cocoa classes ---------------------------- */
+@interface MatplotlibAppDelegate : NSObject
+- (BOOL)applicationSupportsSecureRestorableState:(NSApplication *)app;
+@end
@interface Window : NSWindow
{ PyObject* manager;
@@ -195,6 +198,7 @@ static void lazy_init(void) {
NSApp = [NSApplication sharedApplication];
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
+ [NSApp setDelegate: [[[MatplotlibAppDelegate alloc] init] autorelease]];
// Run our own event loop while waiting for stdin on the Python side
// this is needed to keep the application responsive while waiting for input
@@ -779,6 +783,12 @@ int mpl_check_modifier(
},
};
+@implementation MatplotlibAppDelegate
+- (BOOL)applicationSupportsSecureRestorableState:(NSApplication *)app {
+ return YES;
+}
+@end
+
@interface NavigationToolbar2Handler : NSObject
{ PyObject* toolbar;
NSButton* panbutton;
From c6a86a51ee44938b44f17e37be2d0aa1f482792e Mon Sep 17 00:00:00 2001
From: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com>
Date: Wed, 24 Jan 2024 00:11:49 +0100
Subject: [PATCH 66/87] Backport PR #27681: doc: fix Patch.contains_point
docstring example
---
lib/matplotlib/patches.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/lib/matplotlib/patches.py b/lib/matplotlib/patches.py
index f80df92c62fc..ce012b0faf98 100644
--- a/lib/matplotlib/patches.py
+++ b/lib/matplotlib/patches.py
@@ -190,10 +190,10 @@ def contains_point(self, point, radius=None):
transform them first:
>>> center = 0, 0
- >>> c = Circle(center, radius=1)
+ >>> c = Circle(center, radius=3)
>>> plt.gca().add_patch(c)
- >>> transformed_center = c.get_transform().transform(center)
- >>> c.contains_point(transformed_center)
+ >>> transformed_interior_point = c.get_data_transform().transform((0, 2))
+ >>> c.contains_point(transformed_interior_point)
True
"""
From b0e7df368248c37bc67adab2efcbf5b27f8fabfb Mon Sep 17 00:00:00 2001
From: Kyle Sunden
Date: Wed, 24 Jan 2024 17:57:45 -0600
Subject: [PATCH 67/87] Backport PR #27044: Fix quiver key plot when
angles='xy' and/or scale_units='xy'
---
lib/matplotlib/quiver.py | 30 ++++++----
.../test_quiver/quiver_key_xy.png | Bin 20249 -> 20122 bytes
lib/matplotlib/tests/test_quiver.py | 56 ++++++++++++++++++
3 files changed, 73 insertions(+), 13 deletions(-)
diff --git a/lib/matplotlib/quiver.py b/lib/matplotlib/quiver.py
index c8f8ba566106..5dbf7970f933 100644
--- a/lib/matplotlib/quiver.py
+++ b/lib/matplotlib/quiver.py
@@ -263,7 +263,7 @@ def __init__(self, Q, X, Y, U, label,
The key label (e.g., length and units of the key).
angle : float, default: 0
The angle of the key arrow, in degrees anti-clockwise from the
- x-axis.
+ horizontal axis.
coordinates : {'axes', 'figure', 'data', 'inches'}, default: 'axes'
Coordinate system and units for *X*, *Y*: 'axes' and 'figure' are
normalized coordinate systems with (0, 0) in the lower left and
@@ -327,10 +327,8 @@ def _init(self):
Umask=ma.nomask):
u = self.U * np.cos(np.radians(self.angle))
v = self.U * np.sin(np.radians(self.angle))
- angle = (self.Q.angles if isinstance(self.Q.angles, str)
- else 'uv')
- self.verts = self.Q._make_verts(
- np.array([u]), np.array([v]), angle)
+ self.verts = self.Q._make_verts([[0., 0.]],
+ np.array([u]), np.array([v]), 'uv')
kwargs = self.Q.polykw
kwargs.update(self.kw)
self.vector = mcollections.PolyCollection(
@@ -521,7 +519,7 @@ def _init(self):
# _make_verts sets self.scale if not already specified
if (self._dpi_at_last_init != self.axes.figure.dpi
and self.scale is None):
- self._make_verts(self.U, self.V, self.angles)
+ self._make_verts(self.XY, self.U, self.V, self.angles)
self._dpi_at_last_init = self.axes.figure.dpi
@@ -537,7 +535,7 @@ def get_datalim(self, transData):
@martist.allow_rasterization
def draw(self, renderer):
self._init()
- verts = self._make_verts(self.U, self.V, self.angles)
+ verts = self._make_verts(self.XY, self.U, self.V, self.angles)
self.set_verts(verts, closed=False)
super().draw(renderer)
self.stale = False
@@ -594,33 +592,38 @@ def _set_transform(self):
self.set_transform(trans)
return trans
- def _angles_lengths(self, U, V, eps=1):
- xy = self.axes.transData.transform(self.XY)
+ # Calculate angles and lengths for segment between (x, y), (x+u, y+v)
+ def _angles_lengths(self, XY, U, V, eps=1):
+ xy = self.axes.transData.transform(XY)
uv = np.column_stack((U, V))
- xyp = self.axes.transData.transform(self.XY + eps * uv)
+ xyp = self.axes.transData.transform(XY + eps * uv)
dxy = xyp - xy
angles = np.arctan2(dxy[:, 1], dxy[:, 0])
lengths = np.hypot(*dxy.T) / eps
return angles, lengths
- def _make_verts(self, U, V, angles):
+ # XY is stacked [X, Y].
+ # See quiver() doc for meaning of X, Y, U, V, angles.
+ def _make_verts(self, XY, U, V, angles):
uv = (U + V * 1j)
str_angles = angles if isinstance(angles, str) else ''
if str_angles == 'xy' and self.scale_units == 'xy':
# Here eps is 1 so that if we get U, V by diffing
# the X, Y arrays, the vectors will connect the
# points, regardless of the axis scaling (including log).
- angles, lengths = self._angles_lengths(U, V, eps=1)
+ angles, lengths = self._angles_lengths(XY, U, V, eps=1)
elif str_angles == 'xy' or self.scale_units == 'xy':
# Calculate eps based on the extents of the plot
# so that we don't end up with roundoff error from
# adding a small number to a large.
eps = np.abs(self.axes.dataLim.extents).max() * 0.001
- angles, lengths = self._angles_lengths(U, V, eps=eps)
+ angles, lengths = self._angles_lengths(XY, U, V, eps=eps)
+
if str_angles and self.scale_units == 'xy':
a = lengths
else:
a = np.abs(uv)
+
if self.scale is None:
sn = max(10, math.sqrt(self.N))
if self.Umask is not ma.nomask:
@@ -630,6 +633,7 @@ def _make_verts(self, U, V, angles):
# crude auto-scaling
# scale is typical arrow length as a multiple of the arrow width
scale = 1.8 * amean * sn / self.span
+
if self.scale_units is None:
if self.scale is None:
self.scale = scale
diff --git a/lib/matplotlib/tests/baseline_images/test_quiver/quiver_key_xy.png b/lib/matplotlib/tests/baseline_images/test_quiver/quiver_key_xy.png
index 8475b027093083cf82d7d59ee6f62d3fa2717b86..f4b2b83d08e2b46844a64755c82588a38cc7442e 100644
GIT binary patch
literal 20122
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