API guidelines#

API consistency and stability are of great value; Therefore, API changes(e.g. signature changes, behavior changes, removals) will only be conductedif the added benefit is worth the effort of adapting existing code.

Because we are a visualization library, our primary output is the finalvisualization the user sees; therefore, the appearance of the figure is part ofthe API and any changes, either semantic or aesthetic, are backwards-incompatibleAPI changes.

Add new API#

Every new function, parameter and attribute that is not explicitly marked asprivate (i.e., starts with an underscore) becomes part of Matplotlib's publicAPI. As discussed above, changing the existing API is cumbersome. Therefore,take particular care when adding new API:

  • Mark helper functions and internal attributes as private by prefixing themwith an underscore.

  • Carefully think about good names for your functions and variables.

  • Try to adopt patterns and naming conventions from existing parts of theMatplotlib API.

  • Consider making as many arguments keyword-only as possible. See alsoAPI Evolution the Right Way -- Add Parameters Compatibly.

Add or change colormaps, color sequences, and styles#

Visual changes are considered an API break. Therefore, we generally do not modifyexisting colormaps, color sequences, or styles.

We put a high bar on adding new colormaps and styles to prevent excessively growingthem. While the decision is case-by-case, evaluation criteria include:

  • novelty: Does it support a new use case? e.g. slight variations of existing maps,sequences and styles are likely not accepted.

  • usability and accessibility: Are colors of sequences sufficiently distinct? Hascolorblindness been considered?

  • evidence of wide spread usage: for example academic papers, industry blogs andwhitepapers, or inclusion in other visualization libraries or domain specific tools

  • open license: colormaps, sequences, and styles must have a BSD compatible license(seeLicenses for contributed code)

Deprecate API#

When deciding to deprecate API we carefully consider the balance between the advantages(clearer interfaces, better usability, less maintenance) and the disadvantages (usershave to learn new API and have to modify existing code).

Tip

A rough estimate on the current usage of an API can be obtained by a GitHub codesearch. A good search pattern is typically[expression]language:PythonNOTis:fork.[expression] may be a simplestring, but often regular expressions are helpful to exclude incorrect matches.You can start simple and look at the search results, if there are too manyincorrect matches, gradually refine your search criteria.

It can also be helpful to addNOTpath:**/matplotlib/**NOTpath:**/site-packages/**to exclude matches where the matplotlib codebase is checked into another repo,either as direct sources or as part of an environment.

Example: Calls of the methodFigure.draw() could be matched using/\bfig(ure)?\.draw\(/. This expression employs a number of patterns:

  • Add the opening bracket( after the method name to only find method calls.

  • Include a common object name if there are otherwise too many false positives.There are manydraw() functions out there, but the ones we are looking forare likely called viafig.draw() orfigure.draw().

  • Use the word boundary marker\b to make sure your expression is not amatching as part of a longer word.

Link to the resulting GitHub search

API changes in Matplotlib have to be performed following the deprecation processbelow, except in very rare circumstances as deemed necessary by the developmentteam. Generally API deprecation happens in two stages:

  • introduce: warn users that the APIwill change

  • expire: APIis changed as described in the introduction period

This ensures that users are notified before the change will take effect and thusprevents unexpected breaking of code. Occasionally deprecations are marked aspending, which means that the deprecation will be introduced in a future release.

Rules#

  • Deprecations are targeted at the nextmeso release (e.g. 3.Y)

  • Deprecated API is generally removed (expired) two point-releases after introductionof the deprecation. Longer deprecations can be imposed by core developers ona case-by-case basis to give more time for the transition

  • The old API must remain fully functional during the deprecation period

  • If alternatives to the deprecated API exist, they should be availableduring the deprecation period

  • If in doubt, decisions about API changes are finally made by theAPI consistency lead developer.

Introduce deprecation#

Deprecations are introduced to warn users that the API will change. The deprecationnotice describes how the API will change. When alternatives to the deprecated API exist,they are also listed in the notice and decorators.

  1. Create adeprecation notice

  2. If possible, issue aMatplotlibDeprecationWarning when thedeprecated API is used. There are a number of helper tools for this:

    • Use_api.warn_deprecated() for general deprecation warnings

    • Use the decorator@_api.deprecated to deprecate classes, functions,methods, or properties

    • Use@_api.deprecate_privatize_attribute to annotate deprecation ofattributes while keeping the internal private version.

    • To warn on changes of the function signature, use the decorators@_api.delete_parameter,@_api.rename_parameter, and@_api.make_keyword_only

    All these helpers take a first parametersince, which should be set tothe next point release, e.g. "3.x".

    You can use standard rst cross references inalternative.

  3. Make appropriate changes to the type hints in the associated.pyi file.The general guideline is to match runtime reported behavior.

    • Items marked with@_api.deprecated or@_api.deprecate_privatize_attributeare generally kept during the expiry period, and thus no changes are needed onintroduction.

    • Items decorated with@_api.rename_parameter or@_api.make_keyword_onlyreport thenew (post deprecation) signature at runtime, and thusshould beupdated on introduction.

    • Items decorated with@_api.delete_parameter should include a default value hintfor the deleted parameter, even if it did not previously have one (e.g.param:<type>=...).

Expire deprecation#

The API changes described in the introduction notice are only implemented after theintroduction period has expired.

  1. Create adeprecation announcement. For the content,you can usually copy the deprecation notice and adapt it slightly.

  2. Change the code functionality and remove any related deprecation warnings.

  3. Make appropriate changes to the type hints in the associated.pyi file.

    • Items marked with@_api.deprecated or@_api.deprecate_privatize_attributeare to be removed on expiry.

    • Items decorated with@_api.rename_parameter or@_api.make_keyword_onlywill have been updated at introduction, and require no change now.

    • Items decorated with@_api.delete_parameter will need to be updated to thefinal signature, in the same way as the.py file signature is updated.

    • Any entries inci/mypy-stubtest-allowlist.txt which indicate a deprecationversion should be double checked. In most cases this is not needed, though someitems were never type hinted in the first place and were added to this fileinstead. For removed items that were not in the stub file, only deleting from theallowlist is required.

Pending deprecation#

A pending deprecation is an announcement that a deprecation will be introduced in thefuture. By default, pending deprecations do not raise a warning to the user; however,pending deprecations are rendered in the documentation and listed in the release notes.Pending notices are primarily intended to give downstream library and tool developerstime to adapt their code so that it does not raise a deprecationwarning. This is because their users cannot act on warnings triggered by how the toolsand libraries use Matplotlib. It's also possible to run Python in dev mode to raisePendingDeprecationWarning.

To mark a deprecation as pending, set the following parameters on the appropriatedeprecation decorator:* thepending parameter is set toTrue* theremoval parameter is left blank

When converting a pending deprecation to an introduced deprecation, update thedecorator such that:*pending is set toFalse*since is set to the next meso release (3.Y+1)*removal is set to at least 2 meso releases after (3.Y+3) introduction.

Pending deprecations are documented in theAPI change notes inthe same manner as introduced and expired deprecations. The notice should includepending deprecation in the title.

Announce new and deprecated API#

When adding or changing the API in a backward in-compatible way, please add theappropriateversioning directive and document itin therelease notes by adding an entry to the appropriatefolder:

versioning directive

announcement folder

new feature

..versionadded::3.N

doc/users/next_whats_new/

API change

..versionchanged::3.N

doc/api/next_api_changes/[kind]

When deprecating API, please add a notice as described in thedeprecation guidelines and summarized here:

stage

announcement folder

introduce deprecation

doc/api/next_api_changes/deprecation

expire deprecation

doc/api/next_api_changes/[kind]

Generally the introduction notices can be repurposed for the expiration notice as theyare expected to be describing the same API changes and removals.

Versioning directives#

When making a backward incompatible change, please add a versioning directive inthe docstring. The directives should be placed at the end of a description block.For example:

classFoo:"""    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    """defset_b(b):"""        Set b.        .. versionadded:: 3.6        Parameters        ----------        b: bool

For classes and functions, the directive should be placed before theParameters section. For parameters, the directive should be placed at theend of the parameter description. The micro release version is omitted andthe directive should not be added to entire modules.

Release notes#

For both change notes and what's new, please avoid using cross-references in sectiontitles as it causes links to be confusing in the table of contents. Instead, ensure thata cross-reference is included in the descriptive text.

API change notes#

API change notes for future releases are collected indoc/api/next_api_changes/.They are divided into four subdirectories:

  • Deprecations: Announcements of future changes. Typically, these willraise a deprecation warning and users of this API should change their codeto stay compatible with future releases of Matplotlib. If possible, statewhat should be used instead.

  • Removals: Parts of the API that got removed. If possible, state whatshould be used instead.

  • Behaviour changes: API that stays valid but will yield a differentresult.

  • Development changes: Changes to the build process, dependencies, etc.

Please place new entries in these directories with a new file named99999-ABC.rst, where99999 would be the PR number, andABC theauthor's initials. Typically, each change will get its own file, but you mayalso amend existing files when suitable. The overall goal is a comprehensibledocumentation of the changes.

A typical entry could look like this:

Locators~~~~~~~~The unused `Locator.autoscale()` method is deprecated (pass the axislimits to `Locator.view_limits()` instead).

Please avoid using references in section titles, as it causes links to beconfusing in the table of contents. Instead, ensure that a reference isincluded in the descriptive text. Use inline literals (double backticks)to denote code objects in the title.

What's new notes#

Each new feature (e.g. function, parameter, config value, behavior, ...) mustbe described through a "What's new" entry.

Each entry is written into a separate file in thedoc/users/next_whats_new/ directory. They are sorted and merged intowhats_new.rst during the release process.

When adding an entry please look at the currently existing files tosee if you can extend any of them. If you create a file, name itsomething likecool_new_feature.rst if you have added a brand newfeature or something likeupdated_feature.rst for extensions ofexisting features.

Include contents of the form:

Sectiontitleforfeature-------------------------Adescriptionofthefeaturefromtheuserperspective.Thisshouldincludewhatthefeatureallowsuserstodoandhowthefeatureisused.Technicaldetailsshouldbeleftoutwhentheydonotimpactusage,forexampleimplementationdetails.Thedescriptionmayincludeaashortinstructiveexample,ifithelpstounderstandthefeature.

Please avoid using references in section titles, as it causes links to beconfusing in the table of contents. Instead, ensure that a reference isincluded in the descriptive text. Use inline literals (double backticks)to denote code objects in the title.

Discourage API#

We have API that we do not recommend anymore for new code, but that cannot bedeprecated because its removal would be breaking backward-compatibility and toodisruptive. In such a case we can formally discourage API. This can coverspecific parameters, call patterns, whole methods etc.

To do so, add a note to the docstring

..admonition::Discouraged[descriptionandsuggestedalternative]

You find several examples for good descriptions if you search the codebase for..admonition::Discouraged.

Additionally, if a whole function is discouraged, prefix the summary line with[*Discouraged*] so that it renders in the API overview like this

[Discouraged] Return the XAxis instance.