{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Getting Started With Matplotlib\n", "\n", "[back to overview page](index.ipynb)\n", "\n", "This page is about the general mechanics of plotting with [Matplotlib](http://matplotlib.org/), not so much about the plots themselves.\n", "For more information about those, have a look at the [overview page](index.ipynb) and especially at the [external links section](index.ipynb#External-Links)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Outdated Information\n", "\n", "Matplotlib has been very actively developed in the last few years.\n", "Many improvements have been made and the API as well as the recommended usage patterns have changed quite a bit.\n", "\n", "Sadly, this also means that a lot of documentation out there is outdated and may actually, although well intended, be bad advice.\n", "In fact, this very page may be outdated at the time you are reading it!\n", "Have a look at this date:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "!date +%F" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This is the date of the last change to this page.\n", "If it's older then half a year or a year, it is very likely to be outdated, so don't read it!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Initial Setup\n", "\n", "You should create a file named `matplotlibrc`\n", "in the same directory as your notebook file(s),\n", "containing this line:\n", "\n", " figure.dpi: 96\n", "\n", "For more details, see [Default Values for Matplotlib's \"inline\" backend](matplotlib-inline-defaults.ipynb)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Plotting Step by Step\n", "\n", "There are several different ways of using Matplotlib, here we provide mainly slow-paced step-by-step instructions that show explicitly what has to be done in order to create a plot.\n", "\n", "These instructions should help you to create your own individualized plotting functions (see below).\n", "\n", "You can also use Matplotlib in a much less explicit and quicker-to-type way called \"pylab\" (see further below)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Importing Matplotlib\n", "\n", "There are several ways to do that, some of which are *not recommended* anymore (especially `from pylab import *`).\n", "\n", "As far as I know, this is the canonical and recommended way to import Matplotlib for most use cases:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import matplotlib.pyplot as plt" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For some specialized cases, you can also import specific classes from certain `matplotlib` sub-modules, e.g.\n", "\n", " from matplotlib.patches import Polygon, Ellipse\n", " from matplotlib.colors import LinearSegmentedColormap\n", "\n", "There are lots of code examples out there that still use them, but the following imports are [not recommended anymore](https://matplotlib.org/3.6.0/api/index.html#module-pylab) and you should **never use any of these**:\n", "\n", "
\n",
"from pylab import *\n",
"from matplotlib.pyplot import *\n",
""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### A Quick Plot\n",
"\n",
"If you are in a hurry and just need to plot a few values ..."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"data = 4, 8, 15, 16, 23, 42"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"... you can do it like this:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"plt.plot(data);"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This does multiple steps at once, which is convenient for quick plots.\n",
"For more complicated plotting needs, it is better to have more explicit control about figures, axes and so on.\n",
"The following sections go into more detail about the different steps that are necessary to produce a plot."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Creating a `Figure` and One or More `Axes` Objects\n",
"\n",
"Before plotting anything, a [Figure object](http://matplotlib.org/api/figure_api.html)\n",
"has to be created.\n",
"Some commands handle figure creation and selection automatically (like the example above),\n",
"but it normally makes your code easier to read if you create figures explicitly.\n",
"\n",
"A figure typically contains one or more\n",
"[Axes objects](http://matplotlib.org/api/axes_api.html).\n",
"Most plotting commands work on those.\n",
"\n",
"You can create a figure and a single axes object with a single command like this:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"fig, ax = plt.subplots()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"There are many options you can pass to\n",
"[plt.subplots()](http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.subplots)\n",
"in order to customize things, have a look at the documentation of\n",
"[plt.figure()](http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.figure),\n",
"[add_subplot()](https://matplotlib.org/api/_as_gen/matplotlib.figure.Figure.html#matplotlib.figure.Figure.add_subplot)\n",
"and [GridSpec](http://matplotlib.org/api/gridspec_api.html#matplotlib.gridspec.GridSpec).\n",
"\n",
"If you want more than one `Axes` object, you can specify rows and columns of subplots:\n",
"\n",
" fig, (ax1, ax2) = plt.subplots(1, 2)\n",
"\n",
"If you want, you can also use\n",
"[plt.figure()](http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.figure)\n",
"to create a figure object first, and then use\n",
"[add_axes()](https://matplotlib.org/api/_as_gen/matplotlib.figure.Figure.html#matplotlib.figure.Figure.add_axes)\n",
"and/or\n",
"[add_subplot()](https://matplotlib.org/api/_as_gen/matplotlib.figure.Figure.html#matplotlib.figure.Figure.add_subplot)\n",
"to add axes objects.\n",
"\n",
"If you want to continue plotting on the previously used `Axes` object, you can use [plt.gca()](http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.gca) (= *get current axes*).\n",
"If no axes object exists, this command creates one for you (it also creates a figure object, if needed).\n",
"\n",
"Each figure has a (possibly empty) list of references to all its `Axes` objects ..."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"fig.axes"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Obviously, our example figure has one `Axes` object (the one we got from `plt.subplots()` above)."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"fig.axes[0] is ax"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Each `Axes` object has a reference to its (exactly one) parent figure:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"ax.figure"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"So don't worry if you misplace your figure reference, you can always get it from any contained `Axes` object."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"ax.figure is fig"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Plotting Data\n",
"\n",
"Once we have an `Axes` object, we can plot data onto it.\n",
"There are many types of plots\n",
"(have a look at the [`Axes` documentation](http://matplotlib.org/api/axes_api.html)),\n",
"here we'll just create a very simple plot consisting of two lines.\n",
"Note that when plotting a two-dimensional array of data,\n",
"each column is used to create a separate line in the plot."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"ax.plot([[42, 40],\n",
" [22, 20],\n",
" [32, 30]])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"As you can see, this returns a list of objects (in our case it's two lines).\n",
"You can use those objects for fine-tuning the plot and you can also get a reference to the `Axes` object they belong to:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"_[0].axes is ax"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"> In case you didn't know: The underscore \"`_`\" is a special variable name that is set by the interactive Python interpreter to the result of the last expression of the previously executed code cell.\n",
"\n",
"If you don't need the returned list, you can hide it by appending a semicolon (this is only necessary in the last line of a code cell).\n",
"Let's plot again into the same axes (keeping the previous plot):"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"ax.plot(data);"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Note that mentioning the figure object a few cells above led to the plot being displayed in the cell output.\n",
"The `plot()` command in the previous cell, however, didn't show the plot.\n",
"\n",
"Normally, you would create a figure and produce one or more plots in the same code cell.\n",
"But if you want to show the same figure again in a later cell, just mention the figure object again:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"fig"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Alternatively, you can use IPython's built-in `display()` function:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"display(fig)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Plotting to a File\n",
"\n",
"Analyzing your data in the notebook is nice,\n",
"but you probably also want to save the plot in a separate image file.\n",
"It's very easy to\n",
"[save a figure to a file](https://matplotlib.org/api/_as_gen/matplotlib.figure.Figure.html#matplotlib.figure.Figure.savefig),\n",
"e.g. a PNG file:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"fig.savefig('my_plot.png')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This creates a file named [my_plot.png](my_plot.png) in the current directory.\n",
"You can choose the file type by means of the file extension:\n",
"\n",
" fig.savefig('my_plot.svg')\n",
" fig.savefig('my_plot.pdf')\n",
" fig.savefig('my_plot.eps')\n",
"\n",
"You can [save multiple figures to one PDF file with `PdfPages`](http://matplotlib.org/faq/howto_faq.html#save-multiple-plots-to-one-pdf-file).\n",
"\n",
"It is also possible to [create PGF files for use in LaTeX documents](http://matplotlib.org/users/pgf.html):\n",
"\n",
" fig.savefig('my_plot.pgf')\n",
"\n",
"The available image formats depend on the backend, you can get a list for the currently selected backend:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"fig.canvas.get_supported_filetypes_grouped()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Different Backends\n",
"\n",
"Speaking of which, Matplotlib supports different backends.\n",
"In the examples above, we were using the \"inline\" backend, which is the default (since `ipykernel` version 4.4, see [PR #159](https://github.com/ipython/ipykernel/pull/159)).\n",
"This shows the plots in the notebook itself, right after the code cells that produce the plots."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"If you prefer a separate window for the plots,\n",
"you can use this\n",
"[\"magic\" command](http://ipython.org/ipython-doc/stable/interactive/magics.html#magic-matplotlib):"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"%matplotlib"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"fig, ax = plt.subplots()\n",
"ax.plot(data);"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"After executing the above cell, the plot window should open immediately.\n",
"Note that if you are using Matplotlib in a plain Python script,\n",
"you'll have to call\n",
"[plt.show()](http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.show)\n",
"in order to actually open the plot window, see also http://matplotlib.org/faq/howto_faq.html#use-show.\n",
"\n",
"The effects of the `Axes`'s methods are immediately visible in the plot window, e.g.:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"ax.plot(data[::-1]);"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"ax.grid()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"If you are using Matplotlib (non-interactively) from a plain Python script,\n",
"you'll have to use `fig.canvas.draw()` (or `plt.draw()`) to update the current figure.\n",
"\n",
"If you want to open a new window, just create a new figure object:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"fig2, ax2 = plt.subplots()\n",
"ax2.plot(data + data[::-1]);"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"If you keep references to the figure/axes objects, you can update previous plots\n",
"(as long as you don't close their window)."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"ax.grid()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"There are many plotting backends,\n",
"some Jupyter extensions even provide their own backend.\n",
"You can list all available backends like this:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"%matplotlib -l"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Switching backends might require restarting the kernel in some cases, but switching back and forth between one external backend and the \"inline\" backend should work immediately.\n",
"\n",
"To switch back to the \"inline\" backend, just use:\n",
"\n",
" %matplotlib inline"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Closing a Plot\n",
"\n",
"Matplotlib keeps references to all figures and even if you close all plot windows and delete all your own references, the figures are still kept in memory.\n",
"\n",
"To release all resources for the current figure, use:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"plt.close()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"To close all figures, use:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"plt.close('all')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Note that [plt.clf()](http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.clf)\n",
"and [plt.cla()](http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.cla)\n",
"clear the current figure and axes, respectively,\n",
"but they don't reset the parameters (e.g. figure size)\n",
"and they don't free all resources.\n",
"\n",
"Let's switch back to the \"inline\" backend now:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"%matplotlib inline"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Advice: Write Your Own Plotting Function!\n",
"\n",
"You will most likely not just plot once and then move on.\n",
"More realistically, you'll plot many times while exploring your data and changing some parameters in your calculations.\n",
"\n",
"Depending on the task at hand, you'll have certain requirements regarding axis scaling, tick marks, labels etc.\n",
"\n",
"Instead of repeating the same commands again and again,\n",
"you should write an individualized plotting function (or more likely: several plotting functions).\n",
"Here's an example:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import matplotlib.pyplot as plt\n",
"import numpy as np\n",
"\n",
"\n",
"def myplot(data, ax=None):\n",
" \"\"\"A special plotting function for my special needs.\"\"\"\n",
" if ax is None:\n",
" ax = plt.gca()\n",
" x = np.arange(len(data)) * 1000 # my special x-axis needs\n",
" lines = ax.plot(x, data)\n",
" ax.set_xlabel(\"my independent variable / millisomethings\")\n",
" ax.set_ylabel(\"very interesting unitless values\")\n",
" ax.grid(True)\n",
" return lines"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Note that this function accepts an optional `ax` argument\n",
"(as recommended by the [official FAQ](http://matplotlib.org/faq/usage_faq.html#coding-styles)),\n",
"where an existing `Axes` object can be passed to be drawn on.\n",
"By default, the current `Axes` object is used.\n",
"If none exists, a new figure with a new `Axes` object is created automatically.\n",
"All this is done by [plt.gca()](http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.gca)\n",
"(= *get current axes*).\n",
"\n",
"You should think about what is most useful to be returned from this function,\n",
"in this example it just passes through the list of lines returned by\n",
"[plot()](https://matplotlib.org/api/_as_gen/matplotlib.axes.Axes.plot.html#matplotlib.axes.Axes.plot).\n",
"\n",
"Note that `show()` is not used within the function, as this might not be desired,\n",
"e.g. if we only want to plot to a file and we don't want to show the plot window.\n",
"If we use \"interactive\" mode (which is enabled by default in a Jupyter notebook),\n",
"it isn't necessary anyway.\n",
"\n",
"The custom plotting function can be used like this:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"myplot([3, 2, 4, 1]);"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"By means of the optional `ax` argument it can also be used in more complicated settings, e.g.:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"fig, (ax1, ax2) = plt.subplots(1, 2, sharey=True)\n",
"fig.set_figwidth(fig.get_figwidth() * 1.5)\n",
"fig.subplots_adjust(wspace=0.06)\n",
"myplot([3, 2, 4, 1], ax=ax1)\n",
"myplot([2, 3, 1, 5, 4, 0], ax=ax2)\n",
"ax2.set_ylabel('');"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Of course it's also possible to fine-tune the plotting style in every detail,\n",
"but this is beyond the scope of this little notebook.\n",
"See https://matplotlib.org/tutorials/introductory/customizing.html for more information."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Finally: The Quick and Dirty Way\n",
"\n",
"The above examples are quite explicit (which is good) and a bit verbose (which might be tedious).\n",
"\n",
"If you just want to quickly fire up an IPython console and make some spontaneous throw-away plots, you can use the so-called \"pylab\" mode using [the \"magic\" command](http://ipython.org/ipython-doc/stable/interactive/magics.html#magic-pylab)\n",
"\n",
" %pylab\n",
"\n",
"or\n",
"\n",
" %pylab inline\n",
" \n",
"This injects a whole lot of convenience functions into the current namespace.\n",
"That means you don't need to write any `import` statements and you can use the functions without the `plt.` and `np.` prefixes, e.g.:\n",
"\n",
" plot(arange(100)**2);\n",
"\n",
"This should significantly reduce the number of characters you have to type (at least on the short term).\n",
"However, this is not recommended if you want to keep your code, because the resulting code is hard to read for others (and for future you) and [it may cause some subtle errors](http://nbviewer.ipython.org/github/Carreau/posts/blob/master/10-No-PyLab-Thanks.ipynb)."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
" \n",
"
\n",
" \n",
"
\n",
" To the extent possible under law,\n",
" the person who associated CC0\n",
" with this work has waived all copyright and related or neighboring\n",
" rights to this work.\n",
"