A plethora of libraries exist for plotting figures with Python.
Matplotlib is one of the most well-known libraries and a particular good choice for publication-quality figures. In this weekly coding hour we will cover how to get started with matplotlib and learn a few tips and tricks.
Python and its package manager Pip should be installed on your system and be accessible from the command line.
You can check that Python and Pip are available with the following commands
python --version
python -m pip --version
On some machines you will have to replace python and pip with python3 and pip3, respectively. The output of the two commands will tell you if Python and Pip are installed and in which version. If they are not installed go to python.org and install the latest stable release for your platform.
Next, Matplotlib has to be installed. This can be done easily via the command line with the following command
pip install matplotlib
Furthermore, we will use numpy in this tutorial, therefore also install numpy via
pip install numpy
We will use Jupyter Notebooks in this tutorial to keep everything structured and in one place. However, this is just a choice of personal preference and you can also run the python code as a file. To install jupyter notebooks run
pip install jupyter
The following minimal example from matplotlibs website shows how to plot a simple figure.
In the first two rows matplotlibs pyplot interface and numpy are imported. With the as keyword both of them are given a shorthand alias (plt and np, respectively).
In the next two lines the x- and y-axis data are prepared. Numpy is used to create 200 equidistant points from 0 to 2 for the x values. Then the y values are calculated as the sine of these values.
In the last block of code, the figure and axis of the plot are initialized, the data is plotted and the figure is shown.
# Bonus tip: To make your plots interactive in the jupyter notebook
# run the following line anywhere in your notebook (after installing the required dependencies: ipympl, ...)
%matplotlib widget
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 2 * np.pi, 200)
y = np.sin(x)
fig, ax = plt.subplots()
ax.plot(x, y)
plt.show()
Often you can see the implicit version of the above example which is shown in the following cell. Here no handles are kept to the created objects. We are always acting on the last called object. This can quickly get confusing and especially for more complicated figures can lead to unexpected behavior.
A quick argument conveying you to use the explicit interface might be, that the minimal example will just add a cosine function to the previous plot instead of creating a new figure - highlighting that the implicit interface will force you to be especially careful with opening and closing figures.
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 2 * np.pi, 200)
y = np.cos(x)
plt.plot(x, y)
Interactive figures can be saved from their graphical user interface. However, the provided options for styling the plot vary depending on the specific platform and the implementation thereon.
A more convenient way is to programatically save the figures. To do this call the savefig method of your created figure.
fig.savefig("minimal_example.png")
Matplotlib allows for to customize almost every part of the plot. Here we will only cover the most important parts, see the documentation for more information.
This figure shows the internal structure of each figure and can point you to the right part of the documentation.
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
plt.style.use('default')
matplotlib.rcParams.update({'font.size': 16})
xs = np.linspace(0, 2 * np.pi, 200)
ys = -np.cos(xs)
ys_exp = ys + np.random.normal(0, 0.2, len(ys))
fig, ax = plt.subplots(figsize=(10, 6))
ax.plot(xs, ys, linewidth=2, color="#FF0266", linestyle="dashed", label="Fit")
ax.plot(xs, ys_exp, linewidth=2, color="#36A5FF", label="Experimental Data")
ax.legend(loc="lower center")
ax.margins(x=0, y=0.1)
ax.set_yticks((-1, 0, 1))
ax.set_yticklabels(("$-A_0$", "0", "$A_0$"))
ax.set_xticks((1, 3, 5))
ax.xaxis.set_major_locator(matplotlib.ticker.MaxNLocator(4))
ax.xaxis.set_minor_locator(matplotlib.ticker.MultipleLocator(0.1))
ax.yaxis.set_minor_locator(matplotlib.ticker.MultipleLocator(0.1))
ax.set_xlabel("x-Axis description [units]")
ax.set_ylabel("y-Axis description [units]")
ax.grid(visible=True, which='major', axis='both')
ax.set_title("Example Figure")
style_list = ['default', 'classic'] + sorted(
style for style in plt.style.available
if style != 'classic' and not style.startswith('_'))
fig = plt.figure(figsize=(8, 3 * len(style_list)))
gs = matplotlib.gridspec.GridSpec(len(style_list), 1)
for i, style in enumerate(style_list):
with plt.style.context(style):
tmp_ax = fig.add_subplot(gs[i])
tmp_ax.plot(xs, ys, linewidth=2, color="#FF0266", linestyle="dashed", label="Fit")
tmp_ax.plot(xs, ys_exp, linewidth=2, color="#36A5FF", label="Experimental Data")
tmp_ax.legend(loc="lower center")
tmp_ax.margins(x=0, y=0.1)
tmp_ax.set_yticks((-1, 0, 1))
tmp_ax.set_yticklabels(("$-A_0$", "0", "$A_0$"))
tmp_ax.set_xticks((1, 3, 5))
tmp_ax.xaxis.set_major_locator(matplotlib.ticker.MaxNLocator(4))
tmp_ax.xaxis.set_minor_locator(matplotlib.ticker.MultipleLocator(0.1))
tmp_ax.yaxis.set_minor_locator(matplotlib.ticker.MultipleLocator(0.1))
tmp_ax.set_xlabel("x-Axis description [units]")
tmp_ax.set_ylabel("y-Axis description [units]")
tmp_ax.grid(visible=True, which='major', axis='both')
tmp_ax.set_title(style)
plt.tight_layout()
So far we only plotted data as lines. However, matplotlib offers convenient methods to plot a wide variety of plots. Two good resources to choose the fitting type of plot are Python Graph Gallery and Data To Viz. The first offers a wide variety of examples and the ladder provides a flow chart to find the correct type of plot.
Often you will have to import data from some kind of character-separated values file. This can be done quite easily with numpy.
For a simple tab separated file with an x and y column the following will do the trick
xs, ys = np.genfromtxt('yourfilename.csv', delimter='\t', unpack=True)
When embedding figures into LaTeX documents it is generally advantageous to use a vector graphic format (e.g. SVG or PDF). This will prevent problems with low-resolution graphics. However, raster graphic formats can be advantageous if your figure consists of a very high number of elements which will make rendering the PDF slow.
To make embedded figures consistent with the layout of the containing document we can specify the figures size and dpi when creating the figure (via the figsize argument). The size is expected to be in inches. Then the font sizes can be chosen according to the remaining document and result in a nice consistent layout.
The previous point expects you to know the linewidth or columnwidth (for full-width or half-width figures) of your LaTeX document. You can quickly check these values by adding \the\linewidth somewhere to your LaTeX document. In the rendered version this will be replaced by the according width in points. One point corresponds to 1/72 of an inch (1 inch = 2.54 cm).
When positioning texts, or other artists in an axis you can choose which coordinate system to specify the position in. The options include inter alia the data coordinate system, and the figure or axis coordinates in percent. See the documentation for the full list.
Often Matplotlib will label your axis in scientific notation by default. However, this is often hard to read and can be surpressed by using ax.ticklabel_format(style='plain', useOffset=False).
To create figures with multiple axes in a grid arrangement, specify the number of columns and rows when calling plt.subplots(nrows, ncols). See the example below this cell.
If you want to produce figures with more complicated layouts or just have finer control, you can use GridSpec and control the exact positioning of your axes.
Often the figure will have a quite luxurious margin around the figure. This can be changed either by calling fig.tight_layout() just before saving or by adjusting the margins individually via fig.subplots_adjust().
In some cases it can be very useful to select the file to plot at the beginning of the script. TKinter provides a quick solution to do this via the following code
import tkinter as tk
from tkinter import filedialog
root = tk.Tk()
root.withdraw()
filenames = filedialog.askopenfilename(multiple=True)
root.destroy()
This will save a list of filenames to the filename variable. To select only a sinlge file set multiple to False which will return only a single filename as a string.
import tkinter as tk
from tkinter import filedialog
root = tk.Tk()
root.withdraw()
filename = filedialog.asksaveasfilename()
root.destroy()
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 2 * np.pi, 200)
y = np.sin(x)
x += 1221212
fig, ax = plt.subplots()
ax.ticklabel_format(style='plain', useOffset=False)
ax.plot(x, y)
ax.xaxis.set_major_locator(matplotlib.ticker.MaxNLocator(4))
plt.show()