We need to import matplotlib itself this time.
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import gridspec
import matplotlib as mpl
%matplotlib tk
When preparing a figure for a paper or whatever, you will want more control. We can define the size and make another improvement during figure creation using some options.
The most important thing is to specify the width. If the graph does not have too much detail, it should be sized so that it fits within one column of text (the width should be slightly less than 3 3/8 in).
More detailed figures may take up to 1.5 or 2 columns, as necessary.
fig = plt.figure(figsize=(3.3,3), tight_layout=True)
The figsize
parameter requires a tuple of (width, height)
, both
specified in inches.
The tight_layout
option removes some whitespace from the outer
edges.
ax = fig.add_subplot(1,1,1)
We'll discuss what the 1,1,1
is about later.
Read in some data and plot it.
t, V1, V2, V3 = np.loadtxt('data.csv', delimiter=',', unpack=True, skiprows=1)
ax.plot(t, V1, label='Underdamped')
What the label
parameter is for we'll discuss later. For our current
purposes, it's optional.
The horizontal axis looks bad. Close the window and start again, but this time convert to microseconds.
# CISV
fig = plt.figure(figsize=(3.3,3), tight_layout=True)
ax = fig.add_subplot(1,1,1)
ax.plot(t/(1e-6), V1, label='Underdamped')
Label the axes.
# CISV
ax.set_xlabel(r'$t$ ($\mu$s)')
ax.set_ylabel(r'$V_\mathrm{C}$ (V)')
Add the other plots.
# CISV
ax.plot(t/1e-6, V2, label='Overdamped')
ax.plot(t/1e-6, V3, label='Critically damped')
Now we consider the label
argument we've been passing.
# CISV
ax.legend()
So...it tells matplotlib
how to label legends.
Copy all of the essential commands for reproducing that plot, but do not execute immediately. We'll work with a larger figure for now, so we can see more of what's going on.
Mark up the cell so that we can find it again.
# LOOK AT ME!!! WE'LL COPY AND PASTE THESE LINES MANY TIMES
fig = plt.figure(figsize=(6.4,4.8), tight_layout=True)
ax = fig.add_subplot(1,1,1)
ax.plot(t/1e-6, V1, label='Underdamped')
ax.plot(t/1e-6, V2, label='Overdamped')
ax.plot(t/1e-6, V3, label='Critically damped')
ax.set_xlabel(r'$t$ ($\mu$s)')
ax.set_ylabel(r'$V_\mathrm{C}$ (V)')
ax.legend()
There are several ways of specifying colors.
A (case-insensitive) string specifying an X11 color name. A full list of possible values can be found on Wikipedia, though you'll have to remove spaces. There are a lot of options, but here are some examples.
'blue'
'cyan'
'lightslategray'
'slateblue'
One of the single-character (MATLAB-like) codes below.
'b'
: blue'g'
: green'r'
: red'c'
: cyan'm'
: magenta'y'
: yellow'k'
: black'w'
: whiteA tuple of floats in the range [0,1], representing either the (R, G, B) or (R, G, B, A) values.
A hex-code RBG or RBGA string. (For example, use '#008000'
for
what X11 calls "web green".)
The thickness of the plot lines can be modified using the linewidth
parameter. The value should be specified in points.
# CISV
fig = plt.figure(figsize=(6.4,4.8), tight_layout=True)
ax = fig.add_subplot(1,1,1)
ax.plot(t/1e-6, V1, linewidth=1, label='Underdamped')
ax.plot(t/1e-6, V2, linewidth=1.5, label='Overdamped')
ax.plot(t/1e-6, V3, linewidth=2, label='Critically damped')
ax.set_xlabel(r'$t$ ($\mu$s)')
ax.set_ylabel(r'$V_\mathrm{C}$ (V)')
ax.legend()
The style of the line can be configured using the linestyle
parameter. The options are
'-'
: solid line'--'
: dashed line'-.'
: dash-dot line':'
: dotted line''
: no line# CISV
fig = plt.figure(figsize=(6.4,4.8), tight_layout=True)
ax = fig.add_subplot(1,1,1)
ax.plot(t/1e-6, V1, linestyle='-', label='Underdamped')
ax.plot(t/1e-6, V2, linestyle='--', label='Overdamped')
ax.plot(t/1e-6, V3, linestyle=':', label='Critically damped')
ax.set_xlabel(r'$t$ ($\mu$s)')
ax.set_ylabel(r'$V_\mathrm{C}$ (V)')
ax.legend()
The color
parameter sets the color of the line and the markers.
Values are specified using the syntax from Section A.
# CISV
fig = plt.figure(figsize=(6.4,4.8), tight_layout=True)
ax = fig.add_subplot(1,1,1)
ax.plot(t/1e-6, V1, color='slateblue', label='Underdamped')
ax.plot(t/1e-6, V2, color='m', label='Overdamped')
ax.plot(t/1e-6, V3, color=(0,1,0.5), label='Critically damped')
ax.set_xlabel(r'$t$ ($\mu$s)')
ax.set_ylabel(r'$V_\mathrm{C}$ (V)')
ax.legend()
The data we've been working with are too dense to see markers clearly, so we'll load some sparser data.
t, V1, V2, V3 = np.loadtxt('data_sparse.csv', delimiter=',',
unpack=True, skiprows=1)
We can specify the marker style using the marker
parameter.
There are many styles available. Here are some common ones:
'.'
: point','
: pixel'o'
: circle'v'
: triangle down'^'
: triangle up'<'
: triangle left'>'
: triangle right's'
: square'*'
: star'+'
: plus'x'
: x'D'
: diamond'd'
: thin diamond# CISV
fig = plt.figure(figsize=(6.4,4.8), tight_layout=True)
ax = fig.add_subplot(1,1,1)
ax.plot(t/1e-6, V1, marker='.', label='Underdamped')
ax.plot(t/1e-6, V2, marker='<', label='Overdamped')
ax.plot(t/1e-6, V3, marker='*', label='Critically damped')
ax.set_xlabel(r'$t$ ($\mu$s)')
ax.set_ylabel(r'$V_\mathrm{C}$ (V)')
ax.legend()
Markers have two components---a face and an edge. They are customized separately.
The sizes are configured using markersize
(default 6) and
markeredgewidth
(default 1.0), both of which expect a float
in points.
# CISV
fig = plt.figure(figsize=(6.4,4.8), tight_layout=True)
ax = fig.add_subplot(1,1,1)
ax.plot(t/1e-6, V1, marker='.', markersize=9, label='Underdamped')
ax.plot(t/1e-6, V2, marker='<', label='Overdamped')
ax.plot(t/1e-6, V3, marker='*', markeredgewidth=3, label='Critically damped')
ax.set_xlabel(r'$t$ ($\mu$s)')
ax.set_ylabel(r'$V_\mathrm{C}$ (V)')
ax.legend()
The face and edge colors can also be independently specified, using
markeredgecolor
and markerfacecolor
.
If either of these is not given, the color of the respective part
comes from the argument passed to color
(or the default color, if
color
is not given). Normally, this is best.
# CISV
fig = plt.figure(figsize=(6.4,4.8), tight_layout=True)
ax = fig.add_subplot(1,1,1)
ax.plot(t/1e-6, V1, marker='.', markersize=20, markeredgecolor='k',
markerfacecolor='m', label='Underdamped')
ax.plot(t/1e-6, V2, marker='<', markersize=20, markeredgecolor='k',
label='Overdamped')
ax.plot(t/1e-6, V3, marker='*', label='Critically damped')
ax.set_xlabel(r'$t$ ($\mu$s)')
ax.set_ylabel(r'$V_\mathrm{C}$ (V)')
ax.legend()
It is usually faster to specify formatting using a format string,
which is the third posititional argument to plot
(with keyword fmt
if going out of order).
The structure is
fmt = '[marker][line][color]'
Each is optional. If any value is not given, the default from the cycle is used. If no marker is specified, the default is a line without markers.
If only color is specified, you can use any of the methods given above in the discussion of line colors. Otherwise, only the single-letter, MATLAB-style abbreviations are allowed.
The order only matters in cases where ambiguity would arise. For example,
'.-'
gives a solid line with point markers, while '-.'
gives a
dash-dot line with no markers.
'-o'
and 'o-'
both give solid lines with circle markers.
# CISV
fig = plt.figure(figsize=(6.4,4.8), tight_layout=True)
ax = fig.add_subplot(1,1,1)
ax.plot(t/1e-6, V1, 'slateblue', label='Underdamped')
ax.plot(t/1e-6, V2, 'r-.', label='Overdamped')
ax.plot(t/1e-6, V3, 'k.-', label='Critically damped')
ax.set_xlabel(r'$t$ ($\mu$s)')
ax.set_ylabel(r'$V_\mathrm{C}$ (V)')
ax.legend()
Let's plot sine!
# CISV
fig = plt.figure(figsize=(6.4,4.8), tight_layout=True)
ax = fig.add_subplot(1,1,1)
theta = np.linspace(0, 2.5*np.pi, 500)
sin_theta = np.sin(theta)
ax.plot(theta, sin_theta)
ax.set_xlabel(r'$\theta$ (rad)')
ax.set_ylabel(r'$\sin\,\theta$')
Note the extra space at the edges. Suppose we wanted to get rid of it. The limits of the x and y axes are given by
ax.get_xlim()
ax.get_ylim()
# CISV
xlim = ax.get_xlim()
print('x-limits:', xlim)
ylim = ax.get_ylim()
print('y-limits:', ylim)
We can change them using
ax.set_xlim(left=<new_xmin>, right=<new_max>)
ax.set_ylim(bottom=<new_ymin>, top=<new_ymax>)
Any argument set to None
will remain unchanged.
Thus, to get rid of all surrounding space, we could use
# CISV
ax.set_xlim(left=0, right=2.5*np.pi)
ax.set_ylim(bottom=-1, top=1)
We can reverse this by auto-scaling.
# CISV
ax.autoscale(tight=False)
If we had set tight=True
, it would have removed the space, producing
the same effect as our manual change.
We can configure the positions of ticks and labels using
ax.set_xticks(<list_of_x_tick_positions>)
ax.set_yticks(<list_of_y_tick_positions>)
Suppose we only want ticks on the vertical axis at multiples of one-half. We can do it like this:
# CISV
ax.set_yticks([-1.0, -0.5, 0.0, 0.5, 1.0])
We could also put the horizontal ticks at half-integer multiples of $\pi$. We can simplify it using list comprehensions.
# CISV
ax.set_xticks([i*np.pi/2 for i in range(6)])
The tick labels can be similarly changed, using
ax.set_xticklabels(<list_of_x_tick_labels>)
ax.set_yticklabels(<list_of_y_tick_labels>)
Both lists should contain strings.
For the vertical axis ticks, let's use in-line fractions.
# CISV
ax.set_yticklabels(['$-1$', '$-1/2$', '$0$', '$1/2$', '$1$'])
For the horizontal-axis ticks, we can get some nice, pretty $\pi$s.
# CISV
new_xlabels = ['0', r'$\frac{\pi}{2}$', r'$\pi$']
for i in range(3, 6):
if i % 2 == 0:
new_xlabels.append(f'${int(i/2)}\\pi$')
else:
new_xlabels.append(f'$\\frac{{{i}\\pi}}{{2}}$')
ax.set_xticklabels(new_xlabels)
More advanced control over tick formatting is done through
ax.tick_params(axis='both', **kwargs)
where **kwargs
is a sequence of keyword-arguments that
allow you to mess with a lot of different properties of the ticks
and their labels.
Here are some examples.
axis
can be one of 'x'
, 'y'
, and 'both'
to indicate which
axis to modify.length
and width
take float
arguments to specify the length
width of tick marks, in points.color
, labelcolor
, and colors
take mpl
color spec arguments
to specify the colors of the ticks, the labels, or both.pad
takes a float to indicate the distance between the tick and
the label in points.labelsize
takes a float
to indicate the font size of the label.# CISV
ax.tick_params(axis='x', labelcolor='m')
ax.tick_params(axis='x', color='y')
ax.tick_params(axis='x', labelsize=14)
ax.tick_params(axis='y', colors='limegreen', width=2, length=6)
If you ever turn in a plot that looks that stupid, you will get an F for the course.
Reset all the crap.
# CISV
ax.tick_params(axis='y', reset=True)
On to some more common things. Some like to have ticks along all four sides, pointing in. This can be accomplished using the parameters
direction
, which can be 'in'
, 'out'
, or 'inout'
bottom
, top
, left
, right
, each of which takes a bool
indicating whether to draw the respective marks.# CISV
ax.tick_params(axis='both', direction='in',
bottom=True, left=True, right=True, top=True)
ax.tick_params
also allows you to modify properties of gridlines, if
applicable.
We won't be using markers again for a while, so we can go back to the smoother data file.
t, V1, V2, V3 = np.loadtxt('data.csv', delimiter=',',
unpack=True, skiprows=1)
Create a figure as before.
fig = plt.figure(figsize=(6.4,4.8), tight_layout=True)
Before, to add an Axes
, we used
ax = fig.add_subplot(1,1,1)
The syntax is
ax = fig.add_subplot(num_rows, num_cols, position)
position
is an integer, starting from 1
and incrementing in
(English) reading order.
Thus, if we want to plot our three data sets on three different sets of axes, arranged as the first three parts of a two-by-two grid, we can do that:
# CISV
ax1 = fig.add_subplot(2,2,1)
ax1.plot(t/1e-6, V1)
ax2 = fig.add_subplot(2,2,2)
ax2.plot(t/1e-6, V2)
ax3 = fig.add_subplot(2,2,3)
ax3.plot(t/1e-6, V3)
In this particular case, all three graphs should have the same labels, so the most efficient way to label them would be using a loop.
# CISV
for ax in [ax1, ax2, ax3]:
ax.set_xlabel(r'$t$ ($\mu$s)')
ax.set_ylabel(r'$V_\mathrm{C}$ (V)')
Axes can be linked, or shared. Let's make a narrower figure where we vertically stack all three axes.
# CISV
fig = plt.figure(figsize=(4,6), tight_layout=True)
ax1 = fig.add_subplot(3,1,1)
ax1.plot(t/1e-6, V1)
ax2 = fig.add_subplot(3,1,2, sharex=ax1)
ax2.plot(t/1e-6, V2)
ax3 = fig.add_subplot(3,1,3, sharex=ax1)
ax3.plot(t/1e-6, V3)
Apply our axis labels.
# CISV
ax3.set_xlabel(r'$t$ ($\mu$s)')
for ax in [ax1, ax2, ax3]:
ax.set_ylabel(r'$V_\mathrm{C}$ (V)')
Often, since the x-axes are now linked, we won't want to label all three sets of ticks. Typically, only the bottom-most ticks are labeled. We can turn the tick labels on the other two graphs invisible as follows.
The following two methods are equivalent.
# CISV
for i1, i2 in zip(ax1.get_xticklabels(), ax2.get_xticklabels()):
i1.set_visible(False)
i2.set_visible(False)
# CISV
ax1.tick_params('x', labelbottom=False)
ax2.tick_params('x', labelbottom=False)
It's often convenient, when sharing axes, to use a GridSpec
object.
Instead of supplying the number of rows, the number of columns, and
the position to fig.add_subplot
, we first create GridSpec
s:
gs = gridspec.GridSpec(<num_rows>, <num_cols>)
Now the positions in gs
are accessed using typical index notation:
gs[<row>, <col>]
We can pass the GridSpec
positions as arguments to fig.add_subplot
:
ax<num> = fig.add_subplot(gs[<row>, <col>])
fig = plt.figure(figsize=(4,6), tight_layout=True)
gs = gridspec.GridSpec(3,1)
ax1 = fig.add_subplot(gs[0])
ax1.plot(t/1e-6, V1)
ax2 = fig.add_subplot(gs[1])
ax2.plot(t/1e-6, V2)
ax3 = fig.add_subplot(gs[2])
ax3.plot(t/1e-6, V3)
NOTE: Since our GridSpec
had only one dimension (three rows,
one column), we only need to specify one index, rather than two.
If we had, say, a two-by-two grid, we would need two indices.
Now, we can turn the tick labels off using methods from before, but passing empty lists.
ax1.set_xticklabels([])
ax2.set_xticklabels([])
If we want to get rid of the vertical space space between the rows, we use
gs.update(hspace=0)
Note that the tick marks are now invisible (covered by lower graphs). We could fix this by making ticks point inward instead of outward:
ax1.tick_params(axis='x', direction='in')
ax2.tick_params(axis='x', direction='in')
ax3.tick_params(axis='x', direction='inout')
An alternative fix for the disappearing ticks (if you'd rather they still appear pointing outward) is to create the axes in reverse order:
fig = plt.figure(figsize=(4,6), tight_layout=True)
gs = gridspec.GridSpec(3,1)
# Exactly the same as before except that the order is reversed.
ax3 = fig.add_subplot(gs[2])
ax3.plot(t/1e-6, V3)
ax2 = fig.add_subplot(gs[1])
ax2.plot(t/1e-6, V2)
ax1 = fig.add_subplot(gs[0])
ax1.plot(t/1e-6, V1)
ax1.set_xticklabels([])
ax2.set_xticklabels([])
gs.update(hspace=0)
A third, possibly better, option, is to make the axes backgrounds transparent.
fig = plt.figure(figsize=(4,6), tight_layout=True)
gs = gridspec.GridSpec(3,1)
# Exactly the same as before except that the order is reversed.
ax1 = fig.add_subplot(gs[0])
ax1.plot(t/1e-6, V1)
ax2 = fig.add_subplot(gs[1])
ax2.plot(t/1e-6, V2)
ax3 = fig.add_subplot(gs[2])
ax3.plot(t/1e-6, V3)
ax1.set_xticklabels([])
ax2.set_xticklabels([])
ax1.set_facecolor((0,0,0,0))
ax2.set_facecolor((0,0,0,0))
ax3.set_facecolor((0,0,0,0))
gs.update(hspace=0)
We'll be playing around with our graph several times with all the same arguments but different defaults, so let's create a function which generates it.
def make_plot():
fig = plt.figure(figsize=(6.4,4.8), tight_layout=True)
ax = fig.add_subplot(1,1,1)
ax.plot(t/1e-6, V1, label='Underdamped')
ax.plot(t/1e-6, V2, label='Overdamped')
ax.plot(t/1e-6, V3, label='Critically damped')
ax.set_xlabel(r'$t$ ($\mu$s)')
ax.set_ylabel(r'$V_\mathrm{C}$ (V)')
fig.legend()
return fig, ax
Run it!
make_plot()
There are a couple of ways of specifying default values of various parameters. One is to use
mpl.rcParams[<key>] = <value>
Another is to create an 'matplotlibrc' file in the local directory or somewhere in a broader system path (finding the correct locations can be tricky), where the lines are
<key> : <val>
In the first method, <key>
will be a string, with quotation marks
around it. In the second method, quotation marks are not necessary
around <key>
.
Consistent font usage throughout a document is good (unless you want
to look like a crazy person), so it's good to define defaults for fonts. Also,
most publications print in serif font, rather than matplotlib
's sans-serif
default. So let's customize!
mpl.rcParams['font.family'] = 'serif'
mpl.rcParams['font.size'] = 10.0 # This is already default.
make_plot()
The original default choice for the sans-serif font is whichever is first found from this list:
DejaVu Serif, Bitstream Vera Serif, New Century Schoolbook, Century Schoolbook L,
Utopia, ITC Bookman, Bookman, Nimbus Roman No9 L, Times New Roman, Times, Palatino,
Charter, serif
This is the initial value of mpl.rcParams['font.serif']
. Revise it to look for a variant
of Times first.
mpl.rcParams['font.serif'] = ['TeX Gyre Termes', 'Nimbus Roman No9 L',
'Times New Roman', 'Times']
make_plot()
If the previous didn't work, run this.
mpl.font_manager._rebuild()
Then run the previous again.
At the same time, we should choose an equivalent math font. The following options are available:
'dejavusans' (default), 'dejavuserif', 'cm' (Computer Modern), 'stix',
'stixsans' or 'custom'
These are possible values of mpl.rcParams['mathtext.fontset']
. 'custom'
is more
trouble than it's worth, at least for our purposes. The closest to Times is stix.
mpl.rcParams['mathtext.fontset'] = 'stix'
make_plot()
For better formatting, we can have all text processed through LaTeX. It's much slower to do it this way, but it looks better. I'd recommend enabling this option right before creating figures for the final product.
mpl.rcParams['text.usetex'] = True
# The following is comma-separated list of LaTeX statements, in
# raw-string form, to include in the preamble. WARNING: the matplotlib
# folks recommend against using it---it can cause unexpected failures
# and is not supported.
#mpl.rcParams['text.latex.preamble'] = [r'\usepackage{libertine}',
# r'\usepackage{libertinust1math}',
# r'\usepackage[T1]{fontenc}']
#mpl.rcParams['text.latex.preamble'] = [r'\usepackage{newtxmath}',
# r'\usepackage{amsmath}',
# r'\usepackage[T1]{fontenc}']
#mpl.rcParams['text.latex.preamble'] = []
make_plot()
Before continuing, we'll be using markers again, so let's go back to the less dense data.
t, V1, V2, V3 = np.loadtxt('data_sparse.csv', delimiter=',',
unpack=True, skiprows=1)
NOTE: Much of what follows applies to positioning manually-placed text inside figures.
The ax.legend
method takes several optional arguments. Here are the
three most useful for positioning the legend.
loc
: most commonly a string indicating which point on the
legend's box will be the anchor (i.e. the point that will be placed
at the position specified by the next arguments). It can also be an
int
code corresponding to one of the strings (but this makes code
harder to read, so don't do that). Anyway, the options are as
follows.Code | Location String |
---|---|
0 | 'best' |
1 | 'upper right' |
2 | 'upper left' |
3 | 'lower left' |
4 | 'lower right' |
5 | 'right' |
6 | 'center left' |
7 | 'center right' |
8 | 'lower center' |
9 | 'upper center' |
10 | 'center' |
bbox_to_anchor
: A tuple
of float
specifying the point at
which loc
should be located, in "axis coordinates". The lower left
corner of the axes is at (0,0)
, and the upper right corner is at
(1,1)
.
Then to put the center of the legend in the middle of the plot area, use
ax.legend(loc='center', bbox_to_anchor=(0.5,0.5))
To have the center-top of the legend at the top of the plot area, centered on the right-hand plot-area line, use
ax.legend(loc='upper center', bbox_to_anchor=(1,1))
In the second case, you will have to take some care when saving.
fig = plt.figure(figsize=(6.4,4.8), tight_layout=True)
ax = fig.add_subplot(1,1,1)
ax.plot(t/1e-6, V1, 'slateblue', label='Underdamped')
ax.plot(t/1e-6, V2, 'r-.', label='Overdamped')
ax.plot(t/1e-6, V3, 'k.-', label='Critically damped')
ax.set_xlabel(r'$t$ ($\mu$s)')
ax.set_ylabel(r'$V_\mathrm{C}$ (V)')
ax.legend(loc='center', bbox_to_anchor=(0.5,0.5))
ax.legend(loc='upper center', bbox_to_anchor=(1.0,1.0))
ax.legend(loc='lower right', bbox_to_anchor=(1.0,0.0))
bbox_transform
: an object which changes which coordinates are used
for anchoring. If None
(the default), "axes coordinates" are used.
There are two other (relatively) common options.
Data coordinates : specify points according to the actual values of the data in the plot (this is especially useful for positioning text). Use
bbox_transform = ax.transData
Figure coordinates : specify points relative to the figure, so
now instead of (1,1)
giving the top right corner of the box that
bounds the plot area, it gives the top-right corner of the whole
figure. Use
bbox_transform = fig.transFigure
ax.legend(loc='lower right', bbox_to_anchor=(315,-0.1),
bbox_transform=ax.transData)
ax.legend(loc='upper right', bbox_to_anchor=(1,1),
bbox_transform=fig.transFigure)
Another important, related parameter is ncol
, which should be an
integer representing the number of columns in the legend.
ax.legend(loc='lower center', bbox_to_anchor=(0.5,1), ncol=3)
The whole legend can be given a title using the title
parameter.
ax.legend(loc='center', bbox_to_anchor=(1,0.5), title='Graphs')
NOTE: Most of the following should not be changed from graph to
graph within a given project (for the sake of consistency). They
should be set at the level of matplotlib
defaults, rather than in
each legend. However, especially when you are dealing with small
figures, breaking consistency may be necessary to make the figure
more legible.
After each command is the appropriate rcParams
command to set the
default, as a comment, with the default value given.
In any case, if None
is specified, the default is used.
frameon
: None
or bool
Whether to draw a frame around the legend.
ax.legend(loc='center', bbox_to_anchor=(1,0.5), frameon=False)
#mpl.rcParams['legend.frameon'] = True
fancybox
: None
or bool
Whether to curve the corners or not.
ax.legend(loc='center', bbox_to_anchor=(1,0.5), fancybox=False)
#mpl.rcParams['legend.fancybox'] = True
shadow
: None
or bool
Whether to draw a shadow under the legend.
ax.legend(loc='center', bbox_to_anchor=(1,0.5), shadow=True)
#mpl.rcParams['legend.shadow'] = False
framealpha
: None
or float
The transparency of the background.
ax.legend(loc='center', bbox_to_anchor=(1,0.5), framealpha=1)
#mpl.rcParams['legend.framealpha'] = 0.8
facecolor
: None
or a color spec
The color of the background. "color spec" means a color specified using any of the methods described above.
ax.legend(loc='center', bbox_to_anchor=(1,0.5), facecolor='slateblue')
#mpl.rcParams['legend.facecolor'] = 'inherit' # the facecolor is the same
# # as that of the owning Axis
edgecolor
: None
or a color spec
The color of the legend border. "color spec" means a color specified using any of the methods described above.
ax.legend(loc='center', bbox_to_anchor=(1,0.5), edgecolor='m')
#mpl.rcParams['legend.edgecolor'] = 0.8
fontsize
: int
or float
or str
The size of the font. If an int
or a float
, it will be taken
as an absolute font size it points.
If a str
, it should be one of 'xx-small'
, 'x-small'
, 'small'
,
'medium'
, 'large'
, 'x-large'
, 'xx-large'
.
ax.legend(loc='center', bbox_to_anchor=(1,0.5), fontsize=12)
#mpl.rcParams['legend.fontsize'] = 'medium' # same as default font size
ax.legend(loc='center', bbox_to_anchor=(1,0.5), fontsize='x-small')
handlelength
: None
or float
The length of the line/point sample in font-size units.
ax.legend(loc='center', bbox_to_anchor=(1,0.5), handlelength=1)
#mpl.rcParams['legend.handlelength'] = 2.0
numpoints
: None
or int
The number of markers to show on a scatter-plot line/point sample.
ax.legend(loc='center', bbox_to_anchor=(1,0.5), numpoints=2)
#mpl.rcParams['legend.numpoints'] = 1
There are several others (mostly involving spacing) that we won't go into. Check them out on the Internet if you want.
There's also an option to rotate tick labels. This is sometimes useful if one of your axes contains something fairly long (e.g. dates).
Figures are saved using
fig.savefig('filename.ext')
where the ext
determines the file type. For most use cases, the best
option is .pdf. Other options include .eps, .png, .jpg, among
others.
fig.savefig('output.pdf')
In some cases, if the legend hangs outside of the axes, it will get clipped. In that case, you need to get the legend as a separate object, and tell the figure about it.
leg = ax.legend()
fig.savefig('output.pdf', bbox_extra_artists=(leg,))