I am trying to make a plot in Python using matplotlib
. Specifically, I am using contourf(Xm,Ym,Zm)
with colorbar
and saving the plot using figX.savefig('name')
, with Xm,Ym,Zm
being some meshgrids.
With the colorbar next to the actual plot, the plot is off-center using default parameters in savefig
.
How can I produce a figure so that the resulting image file is centered on the center of the actual plot. Best case scenario; the size adjusts so that colorbars and such wont be cut off.
I cant seem to find anything I can use in the parameters of savefig()
, and simply have no idea how to go about this.
Some code:
import matplotlib.pyplot as plt
import numpy as np
# make data
Xm, Ym = np.meshgrid(np.linspace(-3, 3, 256), np.linspace(-3, 3, 256))
Zm = (1 - Xm/2 + Xm**5 + Ym**3) * np.exp(-Xm**2 - Ym**2)
levels = np.linspace(Zm.min(), Zm.max(), 7)
# plot
fig, ax = plt.subplots()
cp = ax.contourf(Xm, Ym, Zm, levels=levels)
cbar = fig.colorbar(cp)
#plt.show()
fig.savefig('plots/contour-plot.png')
The red cross should be equal to the purple cross:
3
As said in the comments, you can use GridSpecs:
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec
#generate data
import numpy as np
Xm, Ym = np.meshgrid(np.linspace(-3, 3, 256), np.linspace(-3, 3, 256))
Zm = (1 - Xm/2 + Xm**5 + Ym**3) * np.exp(-Xm**2 - Ym**2)
levels = np.linspace(Zm.min(), Zm.max(), 7)
fig = plt.figure(figsize=(10,8))
#define subplot width ratios
gs = GridSpec(1, 3, width_ratios=[1, 20, 1])
#leave first axis gs[0] empty for symmetry
#add middle plot for contour
plt_ax = fig.add_subplot(gs[1])
cp = plt_ax.contourf(Xm, Ym, Zm, levels=levels)
#add colorbar
cbar_ax = fig.add_subplot(gs[2])
cbar = fig.colorbar(cp, cax=cbar_ax)
#fig.savefig('test.png')
plt.show()
Sample output:
Update
As you now introduced the problem of different figure sizes: The same logic can be applied to the height of the colorbar by creating a subGridSpec. If we want to ensure consistency in appearance for different figure size ratios, we have to take this into account while creating the GridSpecs.
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec, GridSpecFromSubplotSpec
#generate data
import numpy as np
Xm, Ym = np.meshgrid(np.linspace(-3, 3, 256), np.linspace(-3, 3, 256))
Zm = (1 - Xm/2 + Xm**5 + Ym**3) * np.exp(-Xm**2 - Ym**2)
levels = np.linspace(Zm.min(), Zm.max(), 7)
width = 20
height = 8
fig = plt.figure(figsize=(width, height))
#define subplot width ratios
gs_main = GridSpec(1, 3, width_ratios=[1, 2*width, 1], wspace=1/width)
#add middle plot for contour
plt_ax = fig.add_subplot(gs_main[1])
cp = plt_ax.contourf(Xm, Ym, Zm, levels=levels)
#add colorbar to middle subGridSpec on the right
gs_cbar = GridSpecFromSubplotSpec(3, 1, subplot_spec=gs_main[2], height_ratios=[1, 8, 1])
cbar_ax = fig.add_subplot(gs_cbar[1])
cbar = fig.colorbar(cp, cax=cbar_ax)
#fig.savefig('test.png')
plt.show()
This keeps the width of the colorbar, its distance from the main plot, and its relative height constant over a range of figure sizes.
3