Reputation: 360
The plot above has been produced using mpl_toolkits and matplotlib.colorbar.ColorbarBase, because I needed to customise the colormap and colorbar for my discrete dataset, as shown below:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import colorbar
from matplotlib.collections import LineCollection
from matplotlib.colors import BoundaryNorm, ListedColormap
from mpl_toolkits.axes_grid1 import make_axes_locatable
import random
x = np.arange(1, 1142)
y = np.zeros(len(x))
z = []
for _ in range(len(x)):
z.append(random.randint(-1, 5))
z = np.array(z)
cmap = ListedColormap(['#FF0000', '#D52B00', '#AA5500', '#808000', '#55AA00', '#2BD500', '#00FF00'])
norm = BoundaryNorm([-1.5, -0.5, 0.5, 1.5, 2.5, 3.5, 4.5, 5.5], cmap.N)
points = np.array([x, y]).T.reshape(-1, 1, 2)
segments = np.concatenate([points[:-1], points[1:]], axis=1)
lc = LineCollection(segments, cmap=cmap, norm=norm)
lc.set_array(z)
lc.set_linewidth(10)
plt.gca().add_collection(lc)
plt.xlim(x.min() - (x.max() * 0.05), x.max() + (x.max() * 0.05))
plt.ylim(-1.1, 1.1)
plt.tick_params(axis='both', which='both', bottom=False, labelbottom=False, left=False, labelleft=False)
divider = make_axes_locatable(plt.gca())
ax_cb = divider.append_axes('bottom', size="2%", pad=-0.5)
cb = colorbar.ColorbarBase(ax_cb, cmap=cmap, norm=norm, orientation='horizontal', ticks=[-1, 0, 1, 2, 3, 4, 5])
cb.ax.set_yticklabels(['-1', '0', '1', '2', '3', '4', '5'])
plt.gcf().add_axes(ax_cb)
plt.show()
This solution was based on the example here.
My question, is how can I make the colorbar shorter, so that it doesn't stretch across the entire width of the plot axis?
Upvotes: 1
Views: 2488
Reputation: 339062
The problem is that the divider created via make_axes_locatable
makes sure the new axes are exactly as large as the one from which it is cut. That is the main aim of this function; but here it's somehow orthorgonal to the desire to have a different size.
The solution would be to not use this kind of divider and create the colorbar in the usual fashion via plt.colorbar
or fig.colorbar
. This allows to use the arguments shrink
and aspect
. Since there is 5% margin on each side of the data, you may want to shrink the colorbar to 90% percent.
plt.colorbar(sm, orientation='horizontal', pad=-0.2, shrink=0.9, aspect=30,
ticks=[-1, 0, 1, 2, 3, 4, 5])
Complete code:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.collections import LineCollection
from matplotlib.colors import BoundaryNorm, ListedColormap
from matplotlib.cm import ScalarMappable
x = np.arange(1, 1142)
y = np.zeros(len(x))
z = np.random.randint(-1, 5, size=x.shape)
cmap = ListedColormap(['#FF0000', '#D52B00', '#AA5500', '#808000', '#55AA00', '#2BD500', '#00FF00'])
norm = BoundaryNorm([-1.5, -0.5, 0.5, 1.5, 2.5, 3.5, 4.5, 5.5], cmap.N)
points = np.array([x, y]).T.reshape(-1, 1, 2)
segments = np.concatenate([points[:-1], points[1:]], axis=1)
lc = LineCollection(segments, cmap=cmap, norm=norm)
lc.set_array(z)
lc.set_linewidth(10)
plt.gca().add_collection(lc)
plt.xlim(x.min() - (x.max() * 0.05), x.max() + (x.max() * 0.05))
plt.ylim(-1.1, 1.1)
plt.tick_params(axis='both', which='both', bottom=False, labelbottom=False,
left=False, labelleft=False)
sm = ScalarMappable(norm=norm, cmap=cmap)
sm.set_array([])
plt.colorbar(sm, orientation='horizontal', pad=-0.2, shrink=0.9, aspect=30,
ticks=[-1, 0, 1, 2, 3, 4, 5])
plt.show()
Upvotes: 2
Reputation: 13196
It may be as simple as changing the padding on the colorbar axis,
ax_cb = divider.append_axes('bottom', size="2%", pad=0.5)
which already looks better,
A more flexible approach would be to add subplots_adjust
and add_axes
. Note, this requires a figure fig
with axis ax
to be set up. So your example is,
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import colorbar
from matplotlib.collections import LineCollection
from matplotlib.colors import BoundaryNorm, ListedColormap
from mpl_toolkits.axes_grid1 import make_axes_locatable
import random
x = np.arange(1, 1142)
y = np.zeros(len(x))
z = []
for _ in range(len(x)):
z.append(random.randint(-1, 5))
z = np.array(z)
cmap = ListedColormap(['#FF0000', '#D52B00', '#AA5500', '#808000', '#55AA00', '#2BD500', '#00FF00'])
norm = BoundaryNorm([-1.5, -0.5, 0.5, 1.5, 2.5, 3.5, 4.5, 5.5], cmap.N)
points = np.array([x, y]).T.reshape(-1, 1, 2)
segments = np.concatenate([points[:-1], points[1:]], axis=1)
lc = LineCollection(segments, cmap=cmap, norm=norm)
lc.set_array(z)
lc.set_linewidth(10)
fig, ax = plt.subplots(1,1)
ax.add_collection(lc)
plt.xlim(x.min() - (x.max() * 0.05), x.max() + (x.max() * 0.05))
plt.ylim(-1.1, 1.1)
plt.tick_params(axis='both', which='both', bottom=False, labelbottom=False, left=False, labelleft=False)
fig.subplots_adjust(bottom=0.2)
ax_cb = fig.add_axes([0.15, 0.11, 0.7, 0.05])
cb = colorbar.ColorbarBase(ax_cb, cmap=cmap, norm=norm, orientation='horizontal', ticks=[-1, 0, 1, 2, 3, 4, 5])
cb.ax.set_yticklabels(['-1', '0', '1', '2', '3', '4', '5'])
plt.gcf().add_axes(ax_cb)
plt.show()
Upvotes: 1