Reputation: 7397
I need to generate a whole bunch of vertically-stacked plots in matplotlib. The result will be saved using savefig
and viewed on a webpage, so I don't care how tall the final image is, as long as the subplots are spaced so they don't overlap.
No matter how big I allow the figure to be, the subplots always seem to overlap.
My code currently looks like
import matplotlib.pyplot as plt
import my_other_module
titles, x_lists, y_lists = my_other_module.get_data()
fig = plt.figure(figsize=(10,60))
for i, y_list in enumerate(y_lists):
plt.subplot(len(titles), 1, i)
plt.xlabel("Some X label")
plt.ylabel("Some Y label")
plt.title(titles[i])
plt.plot(x_lists[i],y_list)
fig.savefig('out.png', dpi=100)
Upvotes: 585
Views: 946709
Reputation: 740
As the title mentiones size, you may want to provide a list for the suplots-parameter height_ratios
, new in version 3.6 of the library.
Of the already mentioned parameters, sharex=True, layout='constrained', gridspec_kw={'hspace': 0}
are my favorites.
Upvotes: 0
Reputation: 99
I you wish to have control over the subplots spacing, you can specify it when calling plt.subplots
through gridspace_kw
:
fig, axes = plt.subplots(..., gridspec_kw=dict(hspace=..., wspace=...) )
Or specify the layout through the figure kwargs:
fig, axes = plt.subplots(..., layout="tight")
Upvotes: 0
Reputation: 115
For me next config works the best:
plt.rcParams['figure.constrained_layout.use'] = True
Upvotes: 0
Reputation: 284542
Please review matplotlib: Tight Layout guide and try using matplotlib.pyplot.tight_layout
, or matplotlib.figure.Figure.tight_layout
As a quick example:
import matplotlib.pyplot as plt
fig, axes = plt.subplots(nrows=4, ncols=4, figsize=(8, 8))
fig.tight_layout() # Or equivalently, "plt.tight_layout()"
plt.show()
Without Tight Layout
With Tight Layout
Upvotes: 771
Reputation: 62373
pandas.DataFrame.plot
, which uses matplotlib
as the default backend.
kind=
is specified (e.g. 'bar'
, 'scatter'
, 'hist'
, etc.).python 3.8.12
, pandas 1.3.4
, matplotlib 3.4.3
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# sinusoidal sample data
sample_length = range(1, 15+1)
rads = np.arange(0, 2*np.pi, 0.01)
data = np.array([np.sin(t*rads) for t in sample_length])
df = pd.DataFrame(data.T, index=pd.Series(rads.tolist(), name='radians'), columns=[f'freq: {i}x' for i in sample_length])
# default plot with subplots; each column is a subplot
axes = df.plot(subplots=True)
pandas.DataFrame.plot
figsize
: a width of 5 and a height of 4 for each subplot is a good place to start.layout
: (rows, columns) for the layout of subplots.sharey=True
and sharex=True
so space isn't taken for redundant labels on each subplot..plot
method returns a numpy array of matplotlib.axes.Axes
, which should be flattened to easily work with..get_figure()
to extract the DataFrame.plot
figure object from one of the Axes
.fig.tight_layout()
if desired.axes = df.plot(subplots=True, layout=(3, 5), figsize=(25, 16), sharex=True, sharey=True)
# flatten the axes array to easily access any subplot
axes = axes.flat
# extract the figure object
fig = axes[0].get_figure()
# use tight_layout
fig.tight_layout()
df
# display(df.head(3))
freq: 1x freq: 2x freq: 3x freq: 4x freq: 5x freq: 6x freq: 7x freq: 8x freq: 9x freq: 10x freq: 11x freq: 12x freq: 13x freq: 14x freq: 15x
radians
0.00 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000
0.01 0.010000 0.019999 0.029996 0.039989 0.049979 0.059964 0.069943 0.079915 0.089879 0.099833 0.109778 0.119712 0.129634 0.139543 0.149438
0.02 0.019999 0.039989 0.059964 0.079915 0.099833 0.119712 0.139543 0.159318 0.179030 0.198669 0.218230 0.237703 0.257081 0.276356 0.295520
Upvotes: 9
Reputation: 62373
fig.tight_layout
after creating the figure. However, tight_layout
can be set when creating the figure, because matplotlib.pyplot.subplots
accepts additional parameters with **fig_kw
. All additional keyword arguments are passed to the pyplot.figure
call.import matplotlib.pyplot as plt
# create the figure with tight_layout=True
fig, axes = plt.subplots(nrows=4, ncols=4, figsize=(8, 8), tight_layout=True)
Upvotes: 8
Reputation: 173
If passing
tight_layout=True
to plt.subplots()
or
fig.tight_layout()
is not adding sufficient spacing between subplots,
consider tuning with pad like tight_layout(pad=2.0)
to get desired spacing.
Upvotes: 4
Reputation: 9462
You can use plt.subplots_adjust
to change the spacing between the subplots.
call signature:
subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=None, hspace=None)
The parameter meanings (and suggested defaults) are:
left = 0.125 # the left side of the subplots of the figure
right = 0.9 # the right side of the subplots of the figure
bottom = 0.1 # the bottom of the subplots of the figure
top = 0.9 # the top of the subplots of the figure
wspace = 0.2 # the amount of width reserved for blank space between subplots
hspace = 0.2 # the amount of height reserved for white space between subplots
The actual defaults are controlled by the rc file
Upvotes: 556
Reputation: 1273
Using subplots_adjust(hspace=0)
or a very small number (hspace=0.001
) will completely remove the whitespace between the subplots, whereas hspace=None
does not.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker as tic
fig = plt.figure(figsize=(8, 8))
x = np.arange(100)
y = 3.*np.sin(x*2.*np.pi/100.)
for i in range(1, 6):
temp = 510 + i
ax = plt.subplot(temp)
plt.plot(x, y)
plt.subplots_adjust(hspace=0)
temp = tic.MaxNLocator(3)
ax.yaxis.set_major_locator(temp)
ax.set_xticklabels(())
ax.title.set_visible(False)
plt.show()
hspace=0
or hspace=0.001
hspace=None
Upvotes: 100
Reputation: 339052
Similar to tight_layout
matplotlib now (as of version 2.2) provides constrained_layout
. In contrast to tight_layout
, which may be called any time in the code for a single optimized layout, constrained_layout
is a property, which may be active and will optimze the layout before every drawing step.
Hence it needs to be activated before or during subplot creation, such as figure(constrained_layout=True)
or subplots(constrained_layout=True)
.
Example:
import matplotlib.pyplot as plt
fig, axes = plt.subplots(4,4, constrained_layout=True)
plt.show()
constrained_layout may as well be set via rcParams
plt.rcParams['figure.constrained_layout.use'] = True
See the what's new entry and the Constrained Layout Guide
Upvotes: 116
Reputation: 7362
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(10,60))
plt.subplots_adjust( ... )
The plt.subplots_adjust method:
def subplots_adjust(*args, **kwargs):
"""
call signature::
subplots_adjust(left=None, bottom=None, right=None, top=None,
wspace=None, hspace=None)
Tune the subplot layout via the
:class:`matplotlib.figure.SubplotParams` mechanism. The parameter
meanings (and suggested defaults) are::
left = 0.125 # the left side of the subplots of the figure
right = 0.9 # the right side of the subplots of the figure
bottom = 0.1 # the bottom of the subplots of the figure
top = 0.9 # the top of the subplots of the figure
wspace = 0.2 # the amount of width reserved for blank space between subplots
hspace = 0.2 # the amount of height reserved for white space between subplots
The actual defaults are controlled by the rc file
"""
fig = gcf()
fig.subplots_adjust(*args, **kwargs)
draw_if_interactive()
or
fig = plt.figure(figsize=(10,60))
fig.subplots_adjust( ... )
The size of the picture matters.
"I've tried messing with hspace, but increasing it only seems to make all of the graphs smaller without resolving the overlap problem."
Thus to make more white space and keep the sub plot size the total image needs to be bigger.
Upvotes: 37