You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.
Dismiss alert
<liclass="toctree-l1 current active has-children"><aclass="current reference internal" href="#">Coding guidelines</a><detailsopen="open"><summary><spanclass="toctree-toggle" role="presentation"><iclass="fa-solid fa-chevron-down"></i></span></summary><ul>
<liclass="toctree-l2"><aclass="reference internal" href="license.html">Licenses for contributed code</a></li>
<liclass="toctree-l2"><aclass="reference internal" href="MEP/MEP12.html">MEP12: Improve Gallery and Examples</a></li>
<liclass="toctree-l2"><aclass="reference internal" href="MEP/MEP13.html">MEP13: Use properties for Artists</a></li>
<liclass="toctree-l2"><aclass="reference internal" href="MEP/MEP14.html">MEP14: Text handling</a></li>
<liclass="toctree-l2"><aclass="reference internal" href="MEP/MEP15.html">MEP15: Fix axis autoscaling when limits are specified for one axis only</a></li>
<spanid="id1"></span><h1>Coding guidelines<aclass="headerlink" href="#coding-guidelines" title="Link to this heading">#</a></h1>
<p>We appreciate these guidelines being followed because it improves the readability,
consistency, and maintainability of the code base.</p>
<divclass="seealso admonition">
<pclass="admonition-title">API guidelines</p>
<p>If adding new features, changing behavior or function signatures, or removing
public interfaces, please consult the <aclass="reference internal" href="api_changes.html#api-changes"><spanclass="std std-ref">API guidelines</span></a>.</p>
</div>
<sectionid="pep8-as-enforced-by-ruff">
<spanid="code-style"></span><h2>PEP8, as enforced by ruff<aclass="headerlink" href="#pep8-as-enforced-by-ruff" title="Link to this heading">#</a></h2>
<p>Formatting should follow the recommendations of <aclass="reference external" href="https://www.python.org/dev/peps/pep-0008/">PEP8</a>, as enforced by <aclass="reference external" href="https://docs.astral.sh/ruff/">ruff</a>.
Matplotlib modifies PEP8 to extend the maximum line length to 88
characters. You can check PEP8 compliance from the command line with</p>
<p>Matplotlib intentionally does not use the <aclass="reference external" href="https://black.readthedocs.io/">black</a> auto-formatter (<aclass="reference external" href="https://github.com/matplotlib/matplotlib/issues/18796">1</a>),
in particular due to its inability to understand the semantics of
<p>In general, Matplotlib modules should <strong>not</strong> import <aclass="reference internal" href="../api/matplotlib_configuration_api.html#matplotlib.rcParams" title="matplotlib.rcParams"><codeclass="xref py py-obj docutils literal notranslate"><spanclass="pre">rcParams</span></code></a> using <codeclass="docutils literal notranslate"><spanclass="pre">from</span>
<spanclass="pre">matplotlib</span><spanclass="pre">import</span><spanclass="pre">rcParams</span></code>, but rather access it as <codeclass="docutils literal notranslate"><spanclass="pre">mpl.rcParams</span></code>. This
is because some modules are imported very early, before the <aclass="reference internal" href="../api/matplotlib_configuration_api.html#matplotlib.rcParams" title="matplotlib.rcParams"><codeclass="xref py py-obj docutils literal notranslate"><spanclass="pre">rcParams</span></code></a>
singleton is constructed.</p>
</section>
<sectionid="variable-names">
<h2>Variable names<aclass="headerlink" href="#variable-names" title="Link to this heading">#</a></h2>
<p>When feasible, please use our internal variable naming convention for objects
of a given class and objects of any child class:</p>
<p><codeclass="docutils literal notranslate"><spanclass="pre">trans_<source></span></code> when target is screen</p>
</td>
</tr>
<trclass="row-odd"></tr>
</tbody>
</table>
</div>
<p>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.</p>
</section>
<sectionid="type-hints">
<spanid="id5"></span><h2>Type hints<aclass="headerlink" href="#type-hints" title="Link to this heading">#</a></h2>
<p>If you add new public API or change public API, update or add the
corresponding <aclass="reference external" href="https://mypy.readthedocs.io/en/latest/">mypy</a> type hints.
We generally use <aclass="reference external" href="https://typing.readthedocs.io/en/latest/source/stubs.html#type-stubs">stub files</a>
(<codeclass="docutils literal notranslate"><spanclass="pre">*.pyi</span></code>) to store the type information; for example <codeclass="docutils literal notranslate"><spanclass="pre">colors.pyi</span></code> contains
the type information for <codeclass="docutils literal notranslate"><spanclass="pre">colors.py</span></code>. A notable exception is <codeclass="docutils literal notranslate"><spanclass="pre">pyplot.py</span></code>,
which is type hinted inline.</p>
<p>Type hints can be validated by the <aclass="reference external" href="https://mypy.readthedocs.io/en/stable/stubtest.html">stubtest</a> tool, which can be run
locally using <codeclass="docutils literal notranslate"><spanclass="pre">tox</span><spanclass="pre">-e</span><spanclass="pre">stubtest</span></code> and is a part of the <aclass="reference internal" href="development_workflow.html#automated-tests"><spanclass="std std-ref">Automated tests</span></a>
suite. Type hints for existing functions are also checked by the mypy
<h2>New modules and files: installation<aclass="headerlink" href="#new-modules-and-files-installation" title="Link to this heading">#</a></h2>
<ulclass="simple">
<li><p>If you have added new files or directories, or reorganized existing ones, make sure the
new files are included in the <codeclass="file docutils literal notranslate"><spanclass="pre">meson.build</span></code> in the corresponding directories.</p></li>
<li><p>New modules <em>may</em> be typed inline or using parallel stub file like existing modules.</p></li>
</ul>
</section>
<sectionid="c-c-extensions">
<h2>C/C++ extensions<aclass="headerlink" href="#c-c-extensions" title="Link to this heading">#</a></h2>
<ulclass="simple">
<li><p>Extensions may be written in C or C++.</p></li>
<li><p>Code style should conform to PEP7 (understanding that PEP7 doesn't
address C++, but most of its admonitions still apply).</p></li>
<li><p>Python/C interface code should be kept separate from the core C/C++
code. The interface code should be named <codeclass="file docutils literal notranslate"><spanclass="pre">FOO_wrap.cpp</span></code> or
<li><p>Header file documentation (aka docstrings) should be in Numpydoc
format. We don't plan on using automated tools for these
docstrings, and the Numpydoc format is well understood in the
scientific Python community.</p></li>
<li><p>C/C++ code in the <codeclass="file docutils literal notranslate"><spanclass="pre">extern/</span></code> directory is vendored, and should be kept
close to upstream whenever possible. It can be modified to fix bugs or
implement new features only if the required changes cannot be made elsewhere
in the codebase. In particular, avoid making style fixes to it.</p></li>
</ul>
<sectionid="static-analysis-with-clang-tidy">
<spanid="clang-tidy"></span><h3>Static analysis with clang-tidy<aclass="headerlink" href="#static-analysis-with-clang-tidy" title="Link to this heading">#</a></h3>
<p>Matplotlib's C/C++ sources in <codeclass="file docutils literal notranslate"><spanclass="pre">src/</span></code> are checked with
<aclass="reference external" href="https://clang.llvm.org/extra/clang-tidy/">clang-tidy</a> in CI (see
<codeclass="file docutils literal notranslate"><spanclass="pre">.github/workflows/linting.yml</span></code>). The check
configuration lives in <codeclass="file docutils literal notranslate"><spanclass="pre">.clang-tidy</span></code>.</p>
<p>The logic lives in <codeclass="file docutils literal notranslate"><spanclass="pre">tools/run_clang_tidy.py</span></code>. It requires
<codeclass="docutils literal notranslate"><spanclass="pre">clang-tidy</span></code> on <codeclass="docutils literal notranslate"><spanclass="pre">PATH</span></code> and <codeclass="docutils literal notranslate"><spanclass="pre">meson</span></code> and <codeclass="docutils literal notranslate"><spanclass="pre">pybind11</span></code> installed:</p>
<p>On macOS, <codeclass="docutils literal notranslate"><spanclass="pre">clang-tidy</span></code> is not on <codeclass="docutils literal notranslate"><spanclass="pre">PATH</span></code> after a Homebrew install:</p>
<p><aclass="reference internal" href="../api/_as_gen/matplotlib.axes.Axes.text.html#matplotlib.axes.Axes.text" title="matplotlib.axes.Axes.text"><codeclass="xref py py-obj docutils literal notranslate"><spanclass="pre">matplotlib.axes.Axes.text</span></code></a> (simplified for illustration) just
passes all <codeclass="docutils literal notranslate"><spanclass="pre">args</span></code> and <codeclass="docutils literal notranslate"><spanclass="pre">kwargs</span></code> on to <codeclass="docutils literal notranslate"><spanclass="pre">matplotlib.text.Text.__init__</span></code>:</p>
<divclass="highlight-default notranslate"><divclass="highlight"><pre><span></span><spanclass="c1"># in axes/_axes.py</span>
just passes them on to the <aclass="reference internal" href="../api/_as_gen/matplotlib.artist.Artist.update.html#matplotlib.artist.Artist.update" title="matplotlib.artist.Artist.update"><codeclass="xref py py-obj docutils literal notranslate"><spanclass="pre">matplotlib.artist.Artist.update</span></code></a> method:</p>
<divclass="highlight-default notranslate"><divclass="highlight"><pre><span></span><spanclass="c1"># in text.py</span>
<p><codeclass="docutils literal notranslate"><spanclass="pre">update</span></code> does the work looking for methods named like
<codeclass="docutils literal notranslate"><spanclass="pre">set_property</span></code> if <codeclass="docutils literal notranslate"><spanclass="pre">property</span></code> is a keyword argument. i.e., no one
looks at the keywords, they just get passed through the API to the
artist constructor which looks for suitably named methods and calls
them with the value.</p>
<p>As a general rule, the use of <codeclass="docutils literal notranslate"><spanclass="pre">**kwargs</span></code> should be reserved for
pass-through keyword arguments, as in the example above. If all the
keyword args are to be used in the function, and not passed
on, use the key/value keyword args in the function definition rather
than the <codeclass="docutils literal notranslate"><spanclass="pre">**kwargs</span></code> idiom.</p>
<p>In some cases, you may want to consume some keys in the local
function, and let others pass through. Instead of popping arguments to
use off <codeclass="docutils literal notranslate"><spanclass="pre">**kwargs</span></code>, specify them as keyword-only arguments to the local
function. This makes it obvious at a glance which arguments will be
consumed in the function. For example, in
<aclass="reference internal" href="../api/_as_gen/matplotlib.axes.Axes.plot.html#matplotlib.axes.Axes.plot" title="matplotlib.axes.Axes.plot"><codeclass="xref py py-meth docutils literal notranslate"><spanclass="pre">plot()</span></code></a>, <codeclass="docutils literal notranslate"><spanclass="pre">scalex</span></code> and <codeclass="docutils literal notranslate"><spanclass="pre">scaley</span></code> are
<spanid="using-logging"></span><h2>Using logging for debug messages<aclass="headerlink" href="#using-logging-for-debug-messages" title="Link to this heading">#</a></h2>
<p>Matplotlib uses the standard Python <aclass="reference external" href="https://docs.python.org/3/library/logging.html#module-logging" title="(in Python v3.14)"><codeclass="xref py py-obj docutils literal notranslate"><spanclass="pre">logging</span></code></a> library to write verbose
warnings, information, and debug messages. Please use it! In all those places
you write <aclass="reference external" href="https://docs.python.org/3/library/functions.html#print" title="(in Python v3.14)"><codeclass="xref py py-obj docutils literal notranslate"><spanclass="pre">print</span></code></a> calls to do your debugging, try using <aclass="reference external" href="https://docs.python.org/3/library/logging.html#logging.debug" title="(in Python v3.14)"><codeclass="xref py py-obj docutils literal notranslate"><spanclass="pre">logging.debug</span></code></a>
instead!</p>
<p>To include <aclass="reference external" href="https://docs.python.org/3/library/logging.html#module-logging" title="(in Python v3.14)"><codeclass="xref py py-obj docutils literal notranslate"><spanclass="pre">logging</span></code></a> in your module, at the top of the module, you need to
<codeclass="docutils literal notranslate"><spanclass="pre">import</span><spanclass="pre">logging</span></code>. Then calls in your code like:</p>
<divclass="highlight-default notranslate"><divclass="highlight"><pre><span></span><spanclass="n">_log</span><spanclass="o">=</span><spanclass="n">logging</span><spanclass="o">.</span><spanclass="n">getLogger</span><spanclass="p">(</span><spanclass="vm">__name__</span><spanclass="p">)</span><spanclass="c1"># right after the imports</span>
<spanclass="c1"># code</span>
<spanclass="c1"># more code</span>
<spanclass="n">_log</span><spanclass="o">.</span><spanclass="n">info</span><spanclass="p">(</span><spanclass="s1">'Here is some information'</span><spanclass="p">)</span>
<spanclass="n">_log</span><spanclass="o">.</span><spanclass="n">debug</span><spanclass="p">(</span><spanclass="s1">'Here is some more detailed information'</span><spanclass="p">)</span>
</pre></div>
</div>
<p>will log to a logger named <codeclass="docutils literal notranslate"><spanclass="pre">matplotlib.yourmodulename</span></code>.</p>
<p>If an end-user of Matplotlib sets up <aclass="reference external" href="https://docs.python.org/3/library/logging.html#module-logging" title="(in Python v3.14)"><codeclass="xref py py-obj docutils literal notranslate"><spanclass="pre">logging</span></code></a> to display at levels more
verbose than <codeclass="docutils literal notranslate"><spanclass="pre">logging.WARNING</span></code> in their code with the Matplotlib-provided
<divclass="highlight-none notranslate"><divclass="highlight"><pre><span></span>DEBUG:matplotlib.backends:backend MacOSX version unknown
DEBUG:matplotlib.yourmodulename:Here is some information
DEBUG:matplotlib.yourmodulename:Here is some more detailed information
</pre></div>
</div>
<p>Avoid using pre-computed strings (<codeclass="docutils literal notranslate"><spanclass="pre">f-strings</span></code>, <codeclass="docutils literal notranslate"><spanclass="pre">str.format</span></code>,etc.) for logging because
of security and performance issues, and because they interfere with style handlers. For
example, use <codeclass="docutils literal notranslate"><spanclass="pre">_log.error('hello</span><spanclass="pre">%s',</span><spanclass="pre">'world')</span></code> rather than <codeclass="docutils literal notranslate"><spanclass="pre">_log.error('hello</span>
<spanclass="pre">{}'.format('world'))</span></code> or <codeclass="docutils literal notranslate"><spanclass="pre">_log.error(f'hello</span><spanclass="pre">{s}')</span></code>.</p>
<sectionid="which-logging-level-to-use">
<h3>Which logging level to use?<aclass="headerlink" href="#which-logging-level-to-use" title="Link to this heading">#</a></h3>
<p>There are five levels at which you can emit messages.</p>
<ulclass="simple">
<li><p><aclass="reference external" href="https://docs.python.org/3/library/logging.html#logging.critical" title="(in Python v3.14)"><codeclass="xref py py-obj docutils literal notranslate"><spanclass="pre">logging.critical</span></code></a> and <aclass="reference external" href="https://docs.python.org/3/library/logging.html#logging.error" title="(in Python v3.14)"><codeclass="xref py py-obj docutils literal notranslate"><spanclass="pre">logging.error</span></code></a> are really only there for errors that
will end the use of the library but not kill the interpreter.</p></li>
<li><p><aclass="reference external" href="https://docs.python.org/3/library/logging.html#logging.warning" title="(in Python v3.14)"><codeclass="xref py py-obj docutils literal notranslate"><spanclass="pre">logging.warning</span></code></a> and <aclass="reference internal" href="../api/_api_api.html#matplotlib._api.warn_external" title="matplotlib._api.warn_external"><codeclass="xref py py-obj docutils literal notranslate"><spanclass="pre">_api.warn_external</span></code></a> are used to warn the user,
see below.</p></li>
<li><p><aclass="reference external" href="https://docs.python.org/3/library/logging.html#logging.info" title="(in Python v3.14)"><codeclass="xref py py-obj docutils literal notranslate"><spanclass="pre">logging.info</span></code></a> is for information that the user may want to know if the
program behaves oddly. They are not displayed by default. For instance, if
an object isn't drawn because its position is <codeclass="docutils literal notranslate"><spanclass="pre">NaN</span></code>, that can usually
be ignored, but a mystified user could call
<codeclass="docutils literal notranslate"><spanclass="pre">logging.basicConfig(level=logging.INFO)</span></code> and get an error message that
says why.</p></li>
<li><p><aclass="reference external" href="https://docs.python.org/3/library/logging.html#logging.debug" title="(in Python v3.14)"><codeclass="xref py py-obj docutils literal notranslate"><spanclass="pre">logging.debug</span></code></a> is the least likely to be displayed, and hence can be the
most verbose. "Expected" code paths (e.g., reporting normal intermediate
steps of layouting or rendering) should only log at this level.</p></li>
</ul>
<p>By default, <aclass="reference external" href="https://docs.python.org/3/library/logging.html#module-logging" title="(in Python v3.14)"><codeclass="xref py py-obj docutils literal notranslate"><spanclass="pre">logging</span></code></a> displays all log messages at levels higher than
<p>The <aclass="reference external" href="https://docs.python.org/3/howto/logging.html#logging-basic-tutorial">logging tutorial</a> suggests that the difference between <aclass="reference external" href="https://docs.python.org/3/library/logging.html#logging.warning" title="(in Python v3.14)"><codeclass="xref py py-obj docutils literal notranslate"><spanclass="pre">logging.warning</span></code></a>
and <aclass="reference internal" href="../api/_api_api.html#matplotlib._api.warn_external" title="matplotlib._api.warn_external"><codeclass="xref py py-obj docutils literal notranslate"><spanclass="pre">_api.warn_external</span></code></a> (which uses <aclass="reference external" href="https://docs.python.org/3/library/warnings.html#warnings.warn" title="(in Python v3.14)"><codeclass="xref py py-obj docutils literal notranslate"><spanclass="pre">warnings.warn</span></code></a>) is that
<aclass="reference internal" href="../api/_api_api.html#matplotlib._api.warn_external" title="matplotlib._api.warn_external"><codeclass="xref py py-obj docutils literal notranslate"><spanclass="pre">_api.warn_external</span></code></a> should be used for things the user must change to stop
the warning (typically in the source), whereas <aclass="reference external" href="https://docs.python.org/3/library/logging.html#logging.warning" title="(in Python v3.14)"><codeclass="xref py py-obj docutils literal notranslate"><spanclass="pre">logging.warning</span></code></a> can be more
persistent. Moreover, note that <aclass="reference internal" href="../api/_api_api.html#matplotlib._api.warn_external" title="matplotlib._api.warn_external"><codeclass="xref py py-obj docutils literal notranslate"><spanclass="pre">_api.warn_external</span></code></a> will by default only
emit a given warning <em>once</em> for each line of user code, whereas
<aclass="reference external" href="https://docs.python.org/3/library/logging.html#logging.warning" title="(in Python v3.14)"><codeclass="xref py py-obj docutils literal notranslate"><spanclass="pre">logging.warning</span></code></a> will display the message every time it is called.</p>
<p>By default, <aclass="reference external" href="https://docs.python.org/3/library/warnings.html#warnings.warn" title="(in Python v3.14)"><codeclass="xref py py-obj docutils literal notranslate"><spanclass="pre">warnings.warn</span></code></a> displays the line of code that has the <codeclass="docutils literal notranslate"><spanclass="pre">warn</span></code>
call. This usually isn't more informative than the warning message itself.
<spanclass="n">warnings</span><spanclass="o">.</span><spanclass="n">warn</span><spanclass="p">(</span><spanclass="s1">'Attempting to set identical bottom==top'</span><spanclass="p">)</span>
<spanclass="n">my_matplotlib_module</span><spanclass="o">.</span><spanclass="n">set_range</span><spanclass="p">(</span><spanclass="mi">0</span><spanclass="p">,</span><spanclass="mi">0</span><spanclass="p">)</span><spanclass="c1"># set range</span>
</pre></div>
</div>
<p>will display</p>
<divclass="highlight-none notranslate"><divclass="highlight"><pre><span></span>UserWarning: Attempting to set identical bottom==top
warnings.warn('Attempting to set identical bottom==top')
</pre></div>
</div>
<p>Modifying the module to use <aclass="reference internal" href="../api/_api_api.html#matplotlib._api.warn_external" title="matplotlib._api.warn_external"><codeclass="xref py py-obj docutils literal notranslate"><spanclass="pre">_api.warn_external</span></code></a>:</p>
<spanclass="n">_api</span><spanclass="o">.</span><spanclass="n">warn_external</span><spanclass="p">(</span><spanclass="s1">'Attempting to set identical bottom==top'</span><spanclass="p">)</span>
</pre></div>
</div>
<p>and running the same script will display</p>
<divclass="highlight-none notranslate"><divclass="highlight"><pre><span></span>UserWarning: Attempting to set identical bottom==top
my_matplotlib_module.set_range(0, 0) # set range
</pre></div>
</div>
</section>
</section>
<sectionid="licenses-for-contributed-code">
<spanid="licence-coding-guide"></span><h2>Licenses for contributed code<aclass="headerlink" href="#licenses-for-contributed-code" title="Link to this heading">#</a></h2>
<p>Matplotlib only uses BSD compatible code. If you bring in code from
another project make sure it has a PSF, BSD, MIT or compatible license
(see the Open Source Initiative <aclass="reference external" href="https://opensource.org/licenses">licenses page</a> for details on individual
licenses). If it doesn't, you may consider contacting the author and
asking them to relicense it. GPL and LGPL code are not acceptable in
the main code base, though we are considering an alternative way of
distributing L/GPL code through a separate channel, possibly a
toolkit. If you include code, make sure you include a copy of that
code's license in the license directory if the code's license requires
you to distribute the license with it. Non-BSD compatible licenses
are acceptable in Matplotlib toolkits (e.g., basemap), but make sure you
clearly state the licenses you are using.</p>
<sectionid="why-bsd-compatible">
<h3>Why BSD compatible?<aclass="headerlink" href="#why-bsd-compatible" title="Link to this heading">#</a></h3>
<p>The two dominant license variants in the wild are GPL-style and
BSD-style. There are countless other licenses that place specific
restrictions on code reuse, but there is an important difference to be
considered in the GPL and BSD variants. The best known and perhaps
most widely used license is the GPL, which in addition to granting you
full rights to the source code including redistribution, carries with
it an extra obligation. If you use GPL code in your own code, or link
with it, your product must be released under a GPL compatible
license. i.e., you are required to give the source code to other
people and give them the right to redistribute it as well. Many of the
most famous and widely used open source projects are released under
the GPL, including linux, gcc, emacs and sage.</p>
<p>The second major class are the BSD-style licenses (which includes MIT
and the python PSF license). These basically allow you to do whatever
you want with the code: ignore it, include it in your own open source
project, include it in your proprietary product, sell it,
whatever. python itself is released under a BSD compatible license, in
the sense that, quoting from the PSF license page:</p>
<p>Famous projects released under a BSD-style license in the permissive
sense of the last paragraph are the BSD operating system, python and
TeX.</p>
<p>There are several reasons why early Matplotlib developers selected a
BSD compatible license. Matplotlib is a python extension, and we
choose a license that was based on the python license (BSD
compatible). Also, we wanted to attract as many users and developers
as possible, and many software companies will not use GPL code in
software they plan to distribute, even those that are highly committed
to open source development, such as <aclass="reference external" href="https://www.enthought.com">enthought</a>, out of legitimate concern that use of the
GPL will "infect" their code base by its viral nature. In effect, they
want to retain the right to release some proprietary code. Companies
and institutions who use Matplotlib often make significant
contributions, because they have the resources to get a job done, even
a boring one. Two of the Matplotlib backends (FLTK and WX) were
contributed by private companies. The final reason behind the
licensing choice is compatibility with the other python extensions for
scientific computing: ipython, numpy, scipy, the enthought tool suite
and python itself are all distributed under BSD compatible licenses.</p>