Matplotlib was created to replicate MatLab’s (another programming language) plotting capabilities in Python.
It is an excellent 2D and 3D graphics library for generating scientific figures.
Some of the major Pros of Matplotlib are:
The official Matplotlib web page: http://matplotlib.org/
The main idea in using the more formal Object Oriented method is to create figure objects and then just call methods or attributes off of that object. This approach is nicer when dealing with a canvas that has multiple plots on it.
To begin we create a figure instance. Then we can add axes to that figure:
> # Create Figure (empty canvas)
+ fig = plt.figure()
+
+ # Add set of axes to figure
+ axes = fig.add_axes([0.1, 0.1, 0.8, 0.8])
+ # left, bottom, width, height (range 0 to 1)
+ # 10% from left, 10% from bottom
+ # takes up 80% of height, 80% of width
+
+ # Plot on that set of axes
+ axes.plot(x, y, 'b')
+
+ # Notice the use of set_ to begin methods
+ axes.set_xlabel('Set X Label')
+ axes.set_ylabel('Set y Label')
+ axes.set_title('Set Title')The code is a little more complicated, but the advantage is that we now have full control of where the plot axes are placed, and we can easily add more than one axis to the figure:
> # Creates blank canvas
+ fig = plt.figure()
+
+ axes1 = fig.add_axes([0.1, 0.1, 0.8, 0.8]) # main axes
+ axes2 = fig.add_axes([0.4, 0.2, 0.4, 0.3]) # inset axes
+ plt.show()> fig = plt.figure()
+
+ axes1 = fig.add_axes([0.1, 0.1, 0.8, 0.8]) # main axes
+ axes2 = fig.add_axes([0.2, 0.5, 0.4, 0.3]) # inset axes
+
+ # Larger Figure Axes 1
+ axes1.plot(x, y, 'b')
+ axes1.set_xlabel('X_label_axes2')
+ axes1.set_ylabel('Y_label_axes2')
+ axes1.set_title('Axes 2 Title')
+
+ # Insert Figure Axes 2
+ axes2.plot(y, x, 'r')
+ axes2.set_xlabel('X_label_axes2')
+ axes2.set_ylabel('Y_label_axes2')
+ axes2.set_title('Axes 2 Title')The plt.subplots() object will act as a more automatic axis manager.
> # Use similar to plt.figure() except use
+ # tuple unpacking to grab fig and axes
+ fig, axes = plt.subplots()
+
+ # Now use the axes object to add stuff to plot
+ axes.plot(x, y, 'r')
+ axes.set_xlabel('x')
+ axes.set_ylabel('y')
+ axes.set_title('title')Then you can specify the number of rows and columns when creating the subplots() object:
Axes is an array of axes to plot on
array([<matplotlib.axes._subplots.AxesSubplot object at 0x0000000033C4A0C8>,
<matplotlib.axes._subplots.AxesSubplot object at 0x0000000034085648>],
dtype=object)
We can iterate through this array:
> fig, axes = plt.subplots(nrows=1, ncols=2)
+ for ax in axes:
+ ax.plot(x, y, 'b')
+ ax.set_xlabel('x')
+ ax.set_ylabel('y')
+ ax.set_title('title')Or we can plot by the index:
> fig, axes = plt.subplots(nrows=1, ncols=2)
+
+ axes[0].plot(x,y)
+ axes[0].set_title('First Plot')
+
+ axes[1].plot(y,x)
+ axes[1].set_title('Second Plot')A common issue with matplolib is overlapping subplots or figures. You can use fig.tight_layout() or plt.tight_layout() method, which automatically adjusts the positions of the axes on the figure canvas so that there is no overlapping content:
> fig, axes = plt.subplots(nrows=1, ncols=2)
+
+ for ax in axes:
+ ax.plot(x, y, 'g')
+ ax.set_xlabel('x')
+ ax.set_ylabel('y')
+ ax.set_title('title')
+
+ plt.tight_layout()
+ plt.show()Matplotlib allows the aspect ratio, DPI, and figure size to be specified when the Figure object is created. You can use the figsize and dpi keyword arguments.
figsize is a tuple of the width and height of the figure in inchesdpi is the dots-per-inch (pixel per inch).For example:
> fig, axes = plt.subplots(figsize=(6,2))
+ axes.plot(x,y,'r')
+ axes.set_xlabel('x')
+ axes.set_ylabel('y')
+ axes.set_title('title')
+
+ plt.tight_layout()
+ plt.show()> fig, axes = plt.subplots(figsize=(6,4),
+ nrows=2, ncols=1)
+ axes[0].plot(x,y)
+ axes[1].plot(y,x)
+
+ plt.tight_layout()
+ plt.show()Matplotlib can generate high-quality output in a number formats, including PNG, JPG, EPS, SVG, PGF and PDF.
To save a figure to a file we can use the savefig method in the Figure class:
Here we can also optionally specify the DPI and choose between different output formats:
A title can be added to each axis instance in a figure. To set the title, use the set_title method in the axes instance:
Similarly, with the methods set_xlabel and set_ylabel, we can set the labels of the X and Y axes:
You can use the label=“label text” keyword argument when plots or other objects are added to the figure, and then using the legend method without arguments to add the legend to the figure:
> fig = plt.figure()
+
+ ax = fig.add_axes([0.1,0.1,.8,.8])
+
+ ax.plot(x, x**2, label="x Squared")
+ ax.plot(x, x**3, label="x Cubed")
+ ax.legend(loc=0)The legend function takes an optional keyword argument loc that can be used to specify where in the figure the legend is to be drawn. The allowed values of loc are numerical codes for the various places the legend can be drawn. See the documentation page for details:
http://matplotlib.org/users/legend_guide.html
Some of the most common loc values are:
With matplotlib you can define the colors of lines and other graphical elements in a number of ways.
First, there’s the MATLAB-like syntax where 'b' means blue, 'g' means green, etc. The MATLAB API for selecting line styles are also supported. For example, 'b.-' means a blue line with dots:
> # MATLAB style line color and style
+ fig, ax = plt.subplots()
+ ax.plot(x, x**2, 'b.-') # blue line with dots
+ ax.plot(x, x**3, 'g--') # green dashed lineYou can also define colors by their names or RGB hex codes and optionally provide an alpha value using the color and alpha keyword arguments. Alpha indicates opacity.
> fig, ax = plt.subplots()
+
+ ax.plot(x, x+1, color="blue", alpha=0.5)
+ ax.plot(x, x+2, color="#8B008B")
+ ax.plot(x, x+3, color="#FF8C00") To change the line width you can use the linewidth or lw keyword argument. The line style can be selected using the linestyleorls` keyword arguments:
> fig, ax = plt.subplots(figsize=(12,6))
+
+ ax.plot(x, x+1, color="red", linewidth=0.25)
+ ax.plot(x, x+2, color="red", linewidth=0.50)
+ ax.plot(x, x+3, color="red", linewidth=1.00)
+ ax.plot(x, x+4, color="red", linewidth=2.00)
+
+ # possible linestype options ‘-‘, ‘–’, ‘-.’, ‘:’, ‘steps’
+ ax.plot(x, x+5, color="green", lw=3, linestyle='-')
+ ax.plot(x, x+6, color="green", lw=3, ls='-.')
+ ax.plot(x, x+7, color="green", lw=3, ls=':')
+
+ # custom dash
+ line, = ax.plot(x, x+8, color="black", lw=1.50)
+ line.set_dashes([5, 10, 15, 10])
+ # format: line length, space length, ...
+
+ # possible marker symbols: marker = '+', 'o', '*',
+ # 's', ',', '.', '1', '2', '3', '4', ...
+ ax.plot(x, x+ 9, color="blue", lw=3, ls='-', marker='+')
+ ax.plot(x, x+10, color="blue", lw=3, ls='--', marker='o')
+ ax.plot(x, x+11, color="blue", lw=3, ls='-', marker='s')
+ ax.plot(x, x+12, color="blue", lw=3, ls='--', marker='1')
+
+ # marker size and color
+ ax.plot(x, x+13, color="purple", lw=1,
+ ls='-', marker='o', markersize=2)
+ ax.plot(x, x+14, color="purple", lw=1,
+ ls='-', marker='o', markersize=4)
+ ax.plot(x, x+15, color="purple", lw=1,
+ ls='-', marker='o', markersize=8, markerfacecolor="red")
+ ax.plot(x, x+16, color="purple", lw=1,
+ ls='-', marker='s', markersize=8,
+ markerfacecolor="yellow",
+ markeredgewidth=3, markeredgecolor="green")
+
+ plt.tight_layout()
+ plt.show()We can configure the ranges of the axes using the set_ylim and set_xlim methods in the axis object, or axis('tight') for automatically getting “tightly fitted” axes ranges:
> fig, axes = plt.subplots(1, 3, figsize=(12, 4))
>
> axes[0].plot(x, x**2, x, x**3)
> axes[0].set_title("default axes ranges")
>
> axes[1].plot(x, x**2, x, x**3)
> axes[1].axis('tight')
> axes[1].set_title("tight axes")
>
> axes[2].plot(x, x**2, x, x**3)
> axes[2].set_ylim([0, 60])
> axes[2].set_xlim([2, 5])
> axes[2].set_title("custom axes range")> data = [np.random.normal(0, std,
+ 100) for std in range(1, 4)];
+
+ # rectangular box plot
+ plt.boxplot(data,vert=True,patch_artist=True);
+ plt.show()It is also possible to set a logarithmic scale for one or both axes. This functionality is in fact only one application of a more general transformation system in Matplotlib. Each of the axes’ scales are set separately using set_xscale and set_yscale methods which accept one parameter (with the value “log” in this case):
> fig, axes = plt.subplots(1, 2, figsize=(10,4))
+
+ axes[0].plot(x, x**2, x, np.exp(x));
+ axes[0].set_title("Normal scale")
+
+ axes[1].plot(x, x**2, x, np.exp(x));
+ axes[1].set_yscale("log")
+ axes[1].set_title("Logarithmic scale (y)")We can explicitly determine where we want the axis ticks with set_xticks and set_yticks, which both take a list of values for where on the axis the ticks are to be placed. We can also use the set_xticklabels and set_yticklabels methods to provide a list of custom text labels for each tick location:
> fig, ax = plt.subplots(figsize=(10, 4))
+
+ ax.plot(x, x**2, x, x**3, lw=2);
+
+ ax.set_xticks([1, 2, 3, 4, 5]);
+ ax.set_xticklabels([r'$\alpha$', r'$\beta$', r'$\gamma$',
+ r'$\delta$', r'$\epsilon$'], fontsize=18);
+
+ yticks = [0, 50, 100, 150];
+ ax.set_yticks(yticks);
+ ax.set_yticklabels(["$%.1f$" % y for y in yticks],
+ fontsize=18); # use LaTeX formatted labelsThere are a number of more advanced methods for controlling major and minor tick placement in matplotlib figures, such as automatic placement according to different policies. See http://matplotlib.org/api/ticker_api.html for details.
With large numbers on axes, it is often better use scientific notation:
> fig, ax = plt.subplots(1, 1)
+
+ ax.plot(x, x**2, x, np.exp(x));
+ ax.set_title("scientific notation")
+
+ ax.set_yticks([0, 50, 100, 150]);
+
+ from matplotlib import ticker
+ formatter = ticker.ScalarFormatter(useMathText=True)
+ formatter.set_scientific(True)
+ formatter.set_powerlimits((-1,1))
+ ax.yaxis.set_major_formatter(formatter)
+ plt.show()> plt.rcParams.update({'figure.max_open_warning': 0})
+
+ # distance between x and y
+ plt.rcParams['xtick.major.pad'] = 5
+ plt.rcParams['ytick.major.pad'] = 5
+
+ fig, ax = plt.subplots(1, 1);
+
+ ax.plot(x, x**2, x, np.exp(x));
+ ax.set_yticks([0, 50, 100, 150]);
+
+ ax.set_title("label and axis spacing")
+
+ # padding between axis label and axis numbers
+ ax.xaxis.labelpad = 5
+ ax.yaxis.labelpad = 5
+
+ ax.set_xlabel("x")
+ ax.set_ylabel("y")
+ plt.show()Unfortunately, when saving figures the labels are sometimes clipped, and it can be necessary to adjust the positions of axes a little bit. This can be done using subplots_adjust:
> fig, ax = plt.subplots(1, 1)
+
+ ax.plot(x, x**2, x, np.exp(x));
+ ax.set_yticks([0, 50, 100, 150]);
+
+ ax.set_title("title")
+ ax.set_xlabel("x")
+ ax.set_ylabel("y")
+
+ fig.subplots_adjust(left=0.15, right=.9, bottom=0.1, top=0.9)
+ plt.show()With the grid method in the axis object, we can turn on and off grid lines. We can also customize the appearance of the grid lines using the same keyword arguments as the plot function:
> fig, axes = plt.subplots(1, 2, figsize=(10,3))
+
+ # default grid appearance
+ axes[0].plot(x, x**2, x, x**3, lw=2);
+ axes[0].grid(True)
+
+ # custom grid appearance
+ axes[1].plot(x, x**2, x, x**3, lw=2);
+ axes[1].grid(color='b', alpha=0.5, linestyle='dashed', linewidth=0.5)
+ plt.show()We can also change the properties of axis spines:
> fig, ax = plt.subplots(figsize=(6,2))
+
+ ax.spines['bottom'].set_color('blue')
+ ax.spines['top'].set_color('blue')
+
+ ax.spines['left'].set_color('red')
+ ax.spines['left'].set_linewidth(2)
+
+ # turn off axis spine to the right
+ ax.spines['right'].set_color("none")
+ ax.yaxis.tick_left() # only ticks on the left side
+ plt.show()Sometimes it is useful to have dual x or y axes in a figure; for example, when plotting curves with different units together. Matplotlib supports this with the twinx and twiny functions:
> fig, ax1 = plt.subplots()
+
+ ax1.plot(x, x**2, lw=2, color="blue");
+ ax1.set_ylabel(r"area $(m^2)$", fontsize=18, color="blue")
+ for label in ax1.get_yticklabels():
+ label.set_color("blue")
+
+ ax2 = ax1.twinx()
+ ax2.plot(x, x**3, lw=2, color="red");
+ ax2.set_ylabel(r"volume $(m^3)$", fontsize=18, color="red")
+ for label in ax2.get_yticklabels():
+ label.set_color("red")
+
+ plt.tight_layout()
+ plt.show()> fig, ax = plt.subplots()
+
+ ax.spines['right'].set_color('none')
+ ax.spines['top'].set_color('none')
+
+ ax.xaxis.set_ticks_position('bottom')
+ ax.spines['bottom'].set_position(('data',0))
+ # set position of x spine to x=0
+
+ ax.yaxis.set_ticks_position('left')
+ ax.spines['left'].set_position(('data',0))
+ # set position of y spine to y=0
+
+ xx = np.linspace(-0.75, 1., 100)
+ ax.plot(xx, xx**3)In addition to the regular plot method, there are a number of other functions for generating different kind of plots. See the matplotlib plot gallery for a complete list of available plot types: http://matplotlib.org/gallery.html. Some of the more useful ones are show below:
> fig, axes = plt.subplots(1, 4, figsize=(12,3))
+
+ axes[0].scatter(xx, xx + 0.25*np.random.randn(len(xx)))
+ axes[0].set_title("scatter")
+
+ axes[1].step(n, n**2, lw=2)
+ axes[1].set_title("step")
+
+ axes[2].bar(n, n**2, align="center", width=0.5, alpha=0.5);
+ axes[2].set_title("bar")
+
+ axes[3].fill_between(x, x**2, x**3, color="green", alpha=0.5);
+ axes[3].set_title("fill_between")Annotating text in matplotlib figures can be done using the text function. It supports LaTeX formatting just like axis label texts and titles:
> fig, ax = plt.subplots()
+
+ ax.plot(xx, xx**2, xx, xx**3);
+
+ ax.text(0.15, 0.2, r"$y=x^2$", fontsize=20, color="blue")
+ ax.text(0.65, 0.1, r"$y=x^3$", fontsize=20, color="green")
+ plt.show()Axes can be added to a matplotlib Figure canvas manually using fig.add_axes or using a sub-figure layout manager such as subplots, subplot2grid, or gridspec:
> fig = plt.figure()
+ ax1 = plt.subplot2grid((3,3), (0,0), colspan=3)
+ ax2 = plt.subplot2grid((3,3), (1,0), colspan=2)
+ ax3 = plt.subplot2grid((3,3), (1,2), rowspan=2)
+ ax4 = plt.subplot2grid((3,3), (2,0))
+ ax5 = plt.subplot2grid((3,3), (2,1))
+ plt.tight_layout()
+ plt.show()> import matplotlib.gridspec as gridspec
+
+ fig = plt.figure()
+
+ gs = gridspec.GridSpec(2, 3, height_ratios=[2,1],
+ width_ratios=[1,2,1])
+ for g in gs:
+ ax = fig.add_subplot(g)
+
+ plt.tight_layout()
+ plt.show()Manually adding axes with add_axes is useful for adding insets to figures:
> fig, ax = plt.subplots()
+
+ ax.plot(xx, xx**2, xx, xx**3);
+ plt.tight_layout()
+
+ # inset
+ inset_ax = fig.add_axes([0.2, 0.55, 0.35, 0.35])
+ # X, Y, width, height
+
+ inset_ax.plot(xx, xx**2, xx, xx**3);
+ inset_ax.set_title('zoom near origin')
+
+ # set axis range
+ inset_ax.set_xlim(-.2, .2);
+ inset_ax.set_ylim(-.005, .01);
+
+ # set axis tick locationsColormaps and contour figures are useful for plotting functions of two variables. In most of these functions you will use a colormap to encode one dimension of the data. There are a number of predefined colormaps. It is relatively straightforward to define custom colormaps. For a list of pre-defined colormaps, see: http://www.scipy.org/Cookbook/Matplotlib/Show_colormaps
> alpha = 0.7
+ phi_ext = 2 * np.pi * 0.5
+
+ def flux_qubit_potential(phi_m, phi_p):
+ return 2 + alpha - 2 * np.cos(phi_p) * np.cos(phi_m) - alpha * np.cos(phi_ext - 2*phi_p)> phi_m = np.linspace(0, 2*np.pi, 100)
+ phi_p = np.linspace(0, 2*np.pi, 100)
+ X,Y = np.meshgrid(phi_p, phi_m)
+ Z = flux_qubit_potential(X, Y).T> fig, ax = plt.subplots()
+
+ p = ax.pcolor(X/(2*np.pi), Y/(2*np.pi), Z,
+ cmap=plt.cm.RdBu, vmin=abs(Z).min(),
+ vmax=abs(Z).max())
+ cb = fig.colorbar(p, ax=ax)
+ plt.show()> fig, ax = plt.subplots()
+
+ im = ax.imshow(Z, cmap=plt.cm.RdBu,
+ vmin=abs(Z).min(), vmax=abs(Z).max(),
+ extent=[0, 1, 0, 1])
+ im.set_interpolation('bilinear')
+
+ cb = fig.colorbar(im, ax=ax)
+ plt.show()> fig, ax = plt.subplots()
+
+ cnt = ax.contour(Z, cmap=plt.cm.RdBu,
+ vmin=abs(Z).min(), vmax=abs(Z).max(),
+ extent=[0, 1, 0, 1])
+ plt.show()To use 3D graphics in matplotlib, we first need to create an instance of the Axes3D class. 3D axes can be added to a matplotlib figure canvas in exactly the same way as 2D axes; or, more conveniently, by passing a projection='3d' keyword argument to the add_axes or add_subplot methods.
> from mpl_toolkits.mplot3d.axes3d import Axes3D
+
+ fig = plt.figure(figsize=(14,6))
+
+ # `ax` is a 3D-aware axis instance because of
+ # the projection='3d' keyword argument to add_subplot
+ ax = fig.add_subplot(1, 2, 1, projection='3d')
+
+ p = ax.plot_surface(X, Y, Z, rstride=4,
+ cstride=4, linewidth=0)
+
+ # surface_plot with color grading and color bar
+ ax = fig.add_subplot(1, 2, 2, projection='3d')
+ p = ax.plot_surface(X, Y, Z, rstride=1, cstride=1,
+ cmap=plt.cm.coolwarm, linewidth=0, antialiased=False)
+ cb = fig.colorbar(p, shrink=0.5)
+
+ plt.show()> fig = plt.figure(figsize=(8,6))
+
+ ax = fig.add_subplot(1, 1, 1,
+ projection='3d')
+
+ p = ax.plot_wireframe(X, Y, Z,
+ rstride=4, cstride=4)
+
+ plt.show()> fig = plt.figure(figsize=(8,6))
+
+ ax = fig.add_subplot(1,1,1, projection='3d')
+
+ ax.plot_surface(X, Y, Z, rstride=4,
+ cstride=4, alpha=0.25)
+ cset = ax.contour(X, Y, Z, zdir='z',
+ offset=-np.pi, cmap=plt.cm.coolwarm)
+ cset = ax.contour(X, Y, Z, zdir='x',
+ offset=-np.pi, cmap=plt.cm.coolwarm)
+ cset = ax.contour(X, Y, Z, zdir='y',
+ offset=3*np.pi, cmap=plt.cm.coolwarm)
+
+ ax.set_xlim3d(-np.pi, 2*np.pi);
+ ax.set_ylim3d(0, 3*np.pi);
+ ax.set_zlim3d(-np.pi, 2*np.pi);
+
+ plt.show()