{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "\n# Coding shortcuts\n\nMatplotlib's primary and universal API is the `Axes interface `.\nWhile it is clearly structured and powerful, it can sometimes feel overly verbose and\nthus cumbersome to write. This page collects patterns for condensing the code\nof the Axes-based API and achieving the same results with less typing for many simpler\nplots.\n\n

Note

The `pyplot interface ` is an alternative more compact\n interface, and was historically modeled to be similar to MATLAB. It remains a\n valid approach for those who want to use it. However, it has the disadvantage that\n it achieves its brevity through implicit assumptions that you have to understand.\n\n Since it follows a different paradigm, switching between the Axes interface and\n the pyplot interface requires a shift of the mental model, and some code rewrite,\n if the code develops to a point at which pyplot no longer provides enough\n flexibility.

\n\nThis tutorial goes the other way round, starting from the standard verbose Axes\ninterface and using its capabilities for shortcuts when you don't need all the\ngenerality.\n\nLet's assume we want to make a plot of the number of daylight hours per day over the\nyear in London.\n\nThe standard approach with the Axes interface looks like this.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "import matplotlib.pyplot as plt\nimport numpy as np\n\nday = np.arange(365)\nhours = 4.276 * np.sin(2 * np.pi * (day - 80)/365) + 12.203\n\nfig, ax = plt.subplots()\nax.plot(day, hours, color=\"orange\")\nax.set_xlabel(\"day\")\nax.set_ylabel(\"daylight hours\")\nax.set_title(\"London\")\nplt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that we've included ``plt.show()`` here. This is needed to show the plot window\nwhen running from a command line or in a Python script. If you run a Jupyter notebook,\nthis command is automatically executed at the end of each cell.\n\nFor the rest of the tutorial, we'll assume that we are in a notebook and leave this\nout for brevity. Depending on your context you may still need it.\n\nIf you instead want to save to a file, use ``fig.savefig(\"daylight.png\")``.\n\n\n## Collect Axes properties into a single ``set()`` call\n\nThe properties of Matplotlib Artists can be modified through their respective\n``set_*()`` methods. Artists additionally have a generic ``set()`` method, that takes\nkeyword arguments and is equivalent to calling all the respective ``set_*()`` methods.\n::\n\n ax.set_xlabel(\"day\")\n ax.set_ylabel(\"daylight hours\")\n\ncan also be written as ::\n\n ax.set(xlabel=\"day\", ylabel=\"daylight hours\")\n\nThis is the most simple and effective reduction you can do. With that we can shorten\nthe above plot to\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "fig, ax = plt.subplots()\nax.plot(day, hours, color=\"orange\")\nax.set(xlabel=\"day\", ylabel=\"daylight hours\", title=\"London\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This works as long as you only need to pass one parameter to the ``set_*()`` function.\nThe individual functions are still necessary if you want more control, e.g.\n``set_title(\"London\", fontsize=16)``.\n\n\n## Not storing a reference to the figure\nAnother nuisance of ``fig, ax = plt.subplots()`` is that you always create a ``fig``\nvariable, even if you don't use it. A slightly shorter version would be using the\nstandard variable for unused value in Python (``_``): ``_, ax = plt.subplots()``.\nHowever, that's only marginally better.\n\nYou can work around this by separating figure and Axes creation and chaining them ::\n\n ax = plt.figure().add_subplot()\n\nThis is a bit cleaner logically and has the slight advantage that you could set\nfigure properties inline as well; e.g. ``plt.figure(facecolor=\"lightgoldenrod\")``.\nBut it has the disadvantage that it's longer than ``fig, ax = plt.subplots()``.\n\nYou can still obtain the figure from the Axes if needed, e.g. ::\n\n ax.figure.savefig(\"daylight_hours.png\")\n\nThe example code now looks like this:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "ax = plt.figure().add_subplot()\nax.plot(day, hours, color=\"orange\")\nax.set(xlabel=\"day\", ylabel=\"daylight hours\", title=\"London\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Define Axes properties during axes creation\nThe ``set_*`` methods as well as ``set`` modify existing objects. You can\nalternatively define them right at creation. Since you typically don't instantiate\nclasses yourself in Matplotlib, but rather call some factory function that creates\nthe object and wires it up correctly with the plot, this may seem less obvious. But\nin fact you just pass the desired properties to the factory functions. You are likely\ndoing this already in some places without realizing. Consider the function to create\na line ::\n\n ax.plot(x, y, color=\"orange\")\n\nThis is equivalent to ::\n\n line, = ax.plot(x, y)\n line.set_color(\"orange\")\n\nThe same can be done with functions that create Axes.\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "ax = plt.figure().add_subplot(xlabel=\"day\", ylabel=\"daylight hours\", title=\"London\")\nax.plot(day, hours, color=\"orange\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ ".. important::\n The Axes properties are only accepted as keyword arguments by\n `.Figure.add_subplot`, which creates a single Axes.\n\n For `.Figure.subplots` and `.pyplot.subplots`, you'd have to pass the properties\n as a dict via the keyword argument ``subplot_kw``. The limitation here is that\n such parameters are given to all Axes. For example, if you need two subplots\n (``fig, (ax1, ax2) = plt.subplots(1, 2)``) with different labels, you have to\n set them individually.\n\nDefining Axes properties during creation is best used for single subplots or when\nall subplots share the same properties.\n\n\n## Using implicit figure creation\nYou can go even further by tapping into the pyplot logic and use `.pyplot.axes` to\ncreate the axes:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "ax = plt.axes(xlabel=\"day\", ylabel=\"daylight hours\", title=\"London\")\nax.plot(day, hours, color=\"orange\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Warning

When using this, you have to be aware of the implicit figure semantics of pyplot.\n ``plt.axes()`` will only create a new figure if no figure exists. Otherwise, it\n will add the Axes to the current existing figure, which is likely not what you\n want.

\n\n## Not storing a reference to the Axes\nIf you only need to visualize one dataset, you can append the plot command\ndirectly to the Axes creation. This may be useful e.g. in notebooks,\nwhere you want to create a plot with some configuration, but as little distracting\ncode as possible:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "plt.axes(xlabel=\"day\", ylabel=\"daylight hours\").plot(day, hours, color=\"orange\")" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.13.5" } }, "nbformat": 4, "nbformat_minor": 0 }